Skip to content

Commit a8d9ce2

Browse files
committed
test: mitigates #7194 with link constraints
1 parent 6e482c0 commit a8d9ce2

File tree

5 files changed

+70
-9
lines changed

5 files changed

+70
-9
lines changed

src/Metadata/Link.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Metadata;
1515

1616
use ApiPlatform\OpenApi;
17+
use Symfony\Component\TypeInfo\Type;
1718

1819
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_PARAMETER)]
1920
final class Link extends Parameter
@@ -27,7 +28,8 @@ public function __construct(
2728
private ?array $identifiers = null,
2829
private ?bool $compositeIdentifier = null,
2930
private ?string $expandedValue = null,
30-
?string $security = null,
31+
32+
string|\Stringable|null $security = null,
3133
?string $securityMessage = null,
3234
private ?string $securityObjectName = null,
3335

@@ -37,9 +39,15 @@ public function __construct(
3739
mixed $provider = null,
3840
mixed $filter = null,
3941
?string $property = null,
42+
?array $properties = null,
4043
?string $description = null,
4144
?bool $required = null,
4245
array $extraProperties = [],
46+
47+
mixed $constraints = null,
48+
array|string|null $filterContext = null,
49+
?Type $nativeType = null,
50+
?bool $castToArray = null,
4351
) {
4452
// For the inverse property shortcut
4553
if ($this->parameterName && class_exists($this->parameterName)) {
@@ -53,11 +61,16 @@ public function __construct(
5361
provider: $provider,
5462
filter: $filter,
5563
property: $property,
64+
properties: $properties,
5665
description: $description,
5766
required: $required,
67+
constraints: $constraints,
5868
security: $security,
5969
securityMessage: $securityMessage,
60-
extraProperties: $extraProperties
70+
extraProperties: $extraProperties,
71+
filterContext: $filterContext,
72+
nativeType: $nativeType,
73+
castToArray: $castToArray,
6174
);
6275
}
6376

src/State/Provider/SecurityParameterProvider.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
5656

5757
if ($operation instanceof HttpOperation) {
5858
foreach ($operation->getUriVariables() ?? [] as $key => $uriVariable) {
59+
if ($uriVariable->getValue() instanceof ParameterNotFound) {
60+
$uriVariable->setValue($uriVariables[$key] ?? new ParameterNotFound());
61+
}
62+
5963
$parameters->add($key, $uriVariable->withKey($key));
6064
}
6165
}
@@ -69,7 +73,6 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
6973
$value = $parameter->getValue();
7074
if ($parameter instanceof Link) {
7175
$targetResource = $parameter->getFromClass() ?? $parameter->getToClass() ?? null;
72-
$value = $uriVariables[$parameter->getKey()] ?? new ParameterNotFound();
7376
}
7477

7578
if ($value instanceof ParameterNotFound) {

src/Symfony/Validator/State/ParameterValidatorProvider.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
namespace ApiPlatform\Symfony\Validator\State;
1515

16+
use ApiPlatform\Metadata\HttpOperation;
1617
use ApiPlatform\Metadata\Operation;
1718
use ApiPlatform\Metadata\Parameter;
19+
use ApiPlatform\Metadata\Parameters;
1820
use ApiPlatform\State\ParameterNotFound;
1921
use ApiPlatform\State\ProviderInterface;
2022
use ApiPlatform\State\Util\ParameterParserTrait;
@@ -52,12 +54,25 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
5254
}
5355

5456
$constraintViolationList = new ConstraintViolationList();
55-
foreach ($operation->getParameters() ?? [] as $parameter) {
57+
$parameters = $operation->getParameters() ?? new Parameters();
58+
59+
if ($operation instanceof HttpOperation) {
60+
foreach ($operation->getUriVariables() ?? [] as $key => $uriVariable) {
61+
if ($uriVariable->getValue() instanceof ParameterNotFound) {
62+
$uriVariable->setValue($uriVariables[$key] ?? new ParameterNotFound());
63+
}
64+
65+
$parameters->add($key, $uriVariable->withKey($key));
66+
}
67+
}
68+
69+
foreach ($parameters as $parameter) {
5670
if (!$constraints = $parameter->getConstraints()) {
5771
continue;
5872
}
5973

6074
$value = $parameter->getValue();
75+
6176
if ($value instanceof ParameterNotFound) {
6277
$value = null;
6378
}

tests/Fixtures/TestBundle/Entity/Employee.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use ApiPlatform\Metadata\Post;
2121
use Doctrine\ORM\Mapping as ORM;
2222
use Symfony\Component\Serializer\Annotation\Groups;
23+
use Symfony\Component\Validator\Constraints\IdenticalTo;
2324

2425
#[ApiResource]
2526
#[Post]
@@ -46,8 +47,9 @@
4647
identifiers: ['name'],
4748
fromClass: Company::class,
4849
toProperty: 'company',
49-
security: 'company.name == "Test"',
50-
extraProperties: ['uri_template' => '/company-by-name/{name}']
50+
security: 'company.name == "Test" or company.name == "NotTest"',
51+
extraProperties: ['uri_template' => '/company-by-name/{name}'],
52+
constraints: [new IdenticalTo('Test')]
5153
),
5254
],
5355
)]

tests/Functional/Parameters/LinkProviderParameterTest.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,36 @@ public function testLinkSecurityWithSlug(): void
130130
$this->markTestSkipped();
131131
}
132132

133-
$response = self::createClient()->request('GET', '/companies-by-name/Test/employees');
134-
dd($response->toArray(false));
135-
self::assertEquals(200, $response->getStatusCode());
133+
self::createClient()->request('GET', '/companies-by-name/Test/employees');
134+
self::assertJsonContains([
135+
'hydra:member' => [
136+
['company' => ['@id' => '/company-by-name/Test', 'name' => 'Test']],
137+
],
138+
]);
139+
self::assertResponseStatusCodeSame(200);
140+
}
141+
142+
/**
143+
* See https://github.com/api-platform/core/issues/7061.
144+
*/
145+
public function testLinkSecurityWithConstraint(): void
146+
{
147+
$manager = $this->getManager();
148+
$employee = new Employee();
149+
$employee->setName('me');
150+
$dummy = new Company();
151+
$dummy->setName('Test');
152+
$employee->setCompany($dummy);
153+
$manager->persist($employee);
154+
$manager->persist($dummy);
155+
$manager->flush();
156+
157+
$container = static::getContainer();
158+
if ('mongodb' === $container->getParameter('kernel.environment')) {
159+
$this->markTestSkipped();
160+
}
161+
162+
$response = self::createClient()->request('GET', '/companies-by-name/NotTest/employees');
163+
self::assertEquals(422, $response->getStatusCode());
136164
}
137165
}

0 commit comments

Comments
 (0)