Skip to content

Commit de6e3f5

Browse files
authored
fix(laravel): validate enum schema within filter (#6615)
1 parent a49bde1 commit de6e3f5

File tree

4 files changed

+26
-21
lines changed

4 files changed

+26
-21
lines changed

src/Laravel/Metadata/ParameterValidationResourceMetadataCollectionFactory.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ private function addSchemaValidation(Parameter $parameter): Parameter
136136
$assertions[] = 'multiple_of:'.$schema['multipleOf'];
137137
}
138138

139-
// if (isset($schema['enum'])) {
140-
// $assertions[] = [Rule::enum($schema['enum'])];
141-
// }
139+
if (isset($schema['enum'])) {
140+
$assertions[] = Rule::in($schema['enum']);
141+
}
142142

143143
if (isset($schema['type']) && 'array' === $schema['type']) {
144144
$assertions[] = 'array';

src/Laravel/State/ParameterValidatorProvider.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Laravel\State;
1515

16+
use ApiPlatform\Metadata\Exception\RuntimeException;
1617
use ApiPlatform\Metadata\Operation;
1718
use ApiPlatform\State\ParameterNotFound;
1819
use ApiPlatform\State\ProviderInterface;
@@ -59,18 +60,23 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
5960
}
6061

6162
$key = $parameter->getKey();
63+
if (null === $key) {
64+
throw new RuntimeException('A parameter must have a defined key.');
65+
}
66+
6267
$value = $parameter->getValue();
6368
if ($value instanceof ParameterNotFound) {
6469
$value = null;
6570
}
6671

67-
foreach ((array) $constraints as $k => $c) {
68-
if (!\is_string($k)) {
69-
$k = $key;
70-
}
71-
72-
$allConstraints[$k] = $c;
72+
// Basically renames our key from order[:property] to order.* to assign the rule properly (see https://laravel.com/docs/11.x/validation#rule-in)
73+
if (str_contains($key, '[:property]')) {
74+
$k = str_replace('[:property]', '', $key);
75+
$allConstraints[$k.'.*'] = $constraints;
76+
continue;
7377
}
78+
79+
$allConstraints[$key] = $constraints;
7480
}
7581

7682
$validator = Validator::make($request->query->all(), $allConstraints);

src/Laravel/Tests/EloquentTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ public function testSearchFilterWithPropertyPlaceholder(): void
235235

236236
public function testOrderFilterWithPropertyPlaceholder(): void
237237
{
238-
$res = $this->get('/api/authors?order[id]=desc', ['Accept' => ['application/ld+json']]);
238+
$res = $this->get('/api/authors?order[id]=desc', ['Accept' => ['application/ld+json']])->json();
239239
$this->assertSame($res['member'][0]['id'], 10);
240240
}
241241

@@ -362,4 +362,10 @@ public function testRangeGreaterThanEqualFilter(): void
362362
$this->assertSame($response->json()['member'][1]['@id'], $bookAfter['@id']);
363363
$this->assertSame($response->json()['totalItems'], 2);
364364
}
365+
366+
public function testWrongOrderFilter(): void
367+
{
368+
$res = $this->get('/api/authors?order[name]=something', ['Accept' => ['application/ld+json']]);
369+
$this->assertEquals($res->getStatusCode(), 422);
370+
}
365371
}

src/Metadata/Parameter.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use ApiPlatform\OpenApi\Model\Parameter as OpenApiParameter;
1818
use ApiPlatform\State\ParameterNotFound;
1919
use ApiPlatform\State\ParameterProviderInterface;
20-
use Symfony\Component\Validator\Constraint;
2120

2221
/**
2322
* @experimental
@@ -29,7 +28,7 @@ abstract class Parameter
2928
* @param array<string, mixed> $extraProperties
3029
* @param ParameterProviderInterface|callable|string|null $provider
3130
* @param FilterInterface|string|null $filter
32-
* @param Constraint|array<string, string>|string|Constraint[]|null $constraints
31+
* @param mixed $constraints an array of Symfony constraints, or an array of Laravel rules
3332
*/
3433
public function __construct(
3534
protected ?string $key = null,
@@ -42,7 +41,7 @@ public function __construct(
4241
protected ?bool $required = null,
4342
protected ?int $priority = null,
4443
protected ?false $hydra = null,
45-
protected Constraint|array|string|null $constraints = null,
44+
protected mixed $constraints = null,
4645
protected string|\Stringable|null $security = null,
4746
protected ?string $securityMessage = null,
4847
protected ?array $extraProperties = [],
@@ -106,10 +105,7 @@ public function getHydra(): ?bool
106105
return $this->hydra;
107106
}
108107

109-
/**
110-
* @return Constraint|string|array<string, string>|Constraint[]|null
111-
*/
112-
public function getConstraints(): Constraint|string|array|null
108+
public function getConstraints(): mixed
113109
{
114110
return $this->constraints;
115111
}
@@ -239,10 +235,7 @@ public function withHydra(false $hydra): static
239235
return $self;
240236
}
241237

242-
/**
243-
* @param string|array<string, string>|Constraint[]|Constraint $constraints
244-
*/
245-
public function withConstraints(string|array|Constraint $constraints): static
238+
public function withConstraints(mixed $constraints): static
246239
{
247240
$self = clone $this;
248241
$self->constraints = $constraints;

0 commit comments

Comments
 (0)