Skip to content

Commit ef1d257

Browse files
committed
fix(openapi): generate both singular and array parameter variants for filters
| Q | A | ------------- | --- | Branch? | main | Tickets | Fixes #7905 | License | MIT | Doc PR | ∅ When castToArray is null (default), OpenApiFilterTrait now returns both `param` and `param[]` variants, matching the old ApiFilter behavior.
1 parent 7cc01a6 commit ef1d257

2 files changed

Lines changed: 48 additions & 8 deletions

File tree

src/Doctrine/Common/Filter/OpenApiFilterTrait.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|arr
3434
$arraySchema = ['type' => 'array', 'items' => $schema ?? ['type' => 'string']];
3535
}
3636

37-
return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true, schema: $arraySchema);
37+
$arrayParameter = new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true, schema: $arraySchema);
38+
39+
// When castToArray is null (default), both singular and array forms are accepted
40+
if (null === $parameter->getCastToArray()) {
41+
return [
42+
new OpenApiParameter(name: $parameter->getKey(), in: 'query'),
43+
$arrayParameter,
44+
];
45+
}
46+
47+
return $arrayParameter;
3848
}
3949
}

tests/Functional/Parameters/DoctrineTest.php

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ private function loadProductFixtures(string $resourceClass): void
342342
}
343343

344344
#[DataProvider('openApiParameterDocumentationProvider')]
345-
public function testOpenApiParameterDocumentation(string $parameterName, bool $shouldHaveArrayNotation, string $expectedStyle, bool $expectedExplode, string $expectedDescription = '', ?array $expectedSchema = null): void
345+
public function testOpenApiParameterDocumentation(string $parameterName, bool $shouldHaveArrayNotation, string $expectedStyle, bool $expectedExplode, string $expectedDescription = '', ?array $expectedSchema = null, bool $shouldHaveBothVariants = false): void
346346
{
347347
if ($this->isMongoDB()) {
348348
$this->markTestSkipped('Not tested with mongodb.');
@@ -359,12 +359,38 @@ public function testOpenApiParameterDocumentation(string $parameterName, bool $s
359359
$openApiDoc = $response->toArray();
360360

361361
$parameters = $openApiDoc['paths']['/product_with_query_parameters']['get']['parameters'];
362+
363+
if ($shouldHaveBothVariants) {
364+
$singularParameter = null;
365+
$arrayParameter = null;
366+
367+
foreach ($parameters as $parameter) {
368+
if ($parameter['name'] === $parameterName) {
369+
$singularParameter = $parameter;
370+
}
371+
if ($parameter['name'] === $parameterName.'[]') {
372+
$arrayParameter = $parameter;
373+
}
374+
}
375+
376+
$this->assertNotNull($singularParameter, \sprintf('%s singular parameter should be present in OpenAPI documentation', $parameterName));
377+
$this->assertNotNull($arrayParameter, \sprintf('%s[] array parameter should be present in OpenAPI documentation', $parameterName));
378+
$this->assertSame('query', $arrayParameter['in']);
379+
$this->assertSame($expectedStyle, $arrayParameter['style'] ?? 'form');
380+
$this->assertSame($expectedExplode, $arrayParameter['explode'] ?? false);
381+
382+
if ($expectedSchema) {
383+
$this->assertSame($expectedSchema, $arrayParameter['schema'], 'Array parameter schema should match expected schema');
384+
}
385+
386+
return;
387+
}
388+
362389
$foundParameter = null;
363390
$expectedName = $shouldHaveArrayNotation ? $parameterName.'[]' : $parameterName;
364-
$alternativeName = $shouldHaveArrayNotation ? $parameterName : $parameterName.'[]';
365391

366392
foreach ($parameters as $parameter) {
367-
if ($parameter['name'] === $expectedName || $parameter['name'] === $alternativeName) {
393+
if ($parameter['name'] === $expectedName) {
368394
$foundParameter = $parameter;
369395
break;
370396
}
@@ -390,21 +416,23 @@ public function testOpenApiParameterDocumentation(string $parameterName, bool $s
390416
public static function openApiParameterDocumentationProvider(): array
391417
{
392418
return [
393-
'default behavior (no castToArray, no schema) should use array notation' => [
419+
'default behavior (no castToArray, no schema) should generate both singular and array parameters' => [
394420
'parameterName' => 'brand',
395421
'shouldHaveArrayNotation' => true,
396422
'expectedStyle' => 'deepObject',
397423
'expectedExplode' => true,
398424
'expectedDescription' => '',
399425
'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string']],
426+
'shouldHaveBothVariants' => true,
400427
],
401-
'default behavior with an extra description' => [
428+
'default behavior with an extra description should generate both variants' => [
402429
'parameterName' => 'brandWithDescription',
403430
'shouldHaveArrayNotation' => true,
404431
'expectedStyle' => 'deepObject',
405432
'expectedExplode' => true,
406433
'expectedDescription' => 'Extra description about the filter',
407434
'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string']],
435+
'shouldHaveBothVariants' => true,
408436
],
409437
'explicit schema type string should not use array notation' => [
410438
'parameterName' => 'exactBrand',
@@ -422,21 +450,23 @@ public static function openApiParameterDocumentationProvider(): array
422450
'expectedDescription' => '',
423451
'expectedSchema' => ['type' => 'string'],
424452
],
425-
'with schema and default castToArray should wrap schema in array type' => [
453+
'with schema and default castToArray should generate both variants wrapping schema in array type' => [
426454
'parameterName' => 'tags',
427455
'shouldHaveArrayNotation' => true,
428456
'expectedStyle' => 'deepObject',
429457
'expectedExplode' => true,
430458
'expectedDescription' => '',
431459
'expectedSchema' => ['type' => 'array', 'items' => ['anyOf' => [['type' => 'array', 'items' => ['type' => 'string']], ['type' => 'string']]]],
460+
'shouldHaveBothVariants' => true,
432461
],
433-
'with schema and default castToArray should not wrap schema in array type if already an array' => [
462+
'with schema and default castToArray should generate both variants without wrapping if already array' => [
434463
'parameterName' => 'listOfTags',
435464
'shouldHaveArrayNotation' => true,
436465
'expectedStyle' => 'deepObject',
437466
'expectedExplode' => true,
438467
'expectedDescription' => '',
439468
'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string']],
469+
'shouldHaveBothVariants' => true,
440470
],
441471
];
442472
}

0 commit comments

Comments
 (0)