Skip to content

Commit 732d8e5

Browse files
committed
fix(openapi): properly document list parameters
fixes #7657
1 parent 39c5583 commit 732d8e5

File tree

3 files changed

+30
-19
lines changed

3 files changed

+30
-19
lines changed

src/Doctrine/Common/Filter/OpenApiFilterTrait.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,12 @@ trait OpenApiFilterTrait
2424
public function getOpenApiParameters(Parameter $parameter): OpenApiParameter|array|null
2525
{
2626
$schema = $parameter->getSchema();
27-
$isArraySchema = 'array' === ($schema['type'] ?? null);
28-
$castToArray = $parameter->getCastToArray();
29-
30-
// Use non-array notation if:
31-
// 1. Schema type is explicitly set to a non-array type (string, number, etc.)
32-
// 2. OR castToArray is explicitly false
33-
$hasNonArraySchema = null !== $schema && !$isArraySchema;
34-
35-
if ($hasNonArraySchema || false === $castToArray) {
27+
if (false === $parameter->getCastToArray() || (isset($schema['type']) && 'array' !== $schema['type'])) {
3628
return new OpenApiParameter(name: $parameter->getKey(), in: 'query');
3729
}
3830

39-
return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true);
31+
$arraySchema = ['type' => 'array', 'items' => $schema ?? ['type' => 'string']];
32+
33+
return new OpenApiParameter(name: $parameter->getKey().'[]', in: 'query', style: 'deepObject', explode: true, schema: $arraySchema);
4034
}
4135
}

tests/Fixtures/TestBundle/Entity/ProductWithQueryParameter.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@
5656
property: 'category',
5757
castToArray: false
5858
),
59+
'tags' => new QueryParameter(
60+
filter: new ExactFilter(),
61+
property: 'tags',
62+
schema: ['anyOf' => [['type' => 'array', 'items' => ['type' => 'string']], ['type' => 'string']]]
63+
),
5964
]
6065
),
6166
]

tests/Functional/Parameters/DoctrineTest.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ private function loadProductFixtures(string $resourceClass): void
302302
}
303303

304304
#[DataProvider('openApiParameterDocumentationProvider')]
305-
public function testOpenApiParameterDocumentation(string $parameterName, bool $shouldHaveArrayNotation, string $expectedStyle, bool $expectedExplode, ?string $expectedSchemaType = null, string $expectedDescription = ''): void
305+
public function testOpenApiParameterDocumentation(string $parameterName, bool $shouldHaveArrayNotation, string $expectedStyle, bool $expectedExplode, string $expectedDescription = '', ?array $expectedSchema = null): void
306306
{
307307
if ($this->isMongoDB()) {
308308
$this->markTestSkipped('Not tested with mongodb.');
@@ -335,13 +335,14 @@ public function testOpenApiParameterDocumentation(string $parameterName, bool $s
335335
$this->assertSame('query', $foundParameter['in']);
336336
$this->assertFalse($foundParameter['required']);
337337

338-
if ($expectedSchemaType) {
339-
$this->assertSame($expectedSchemaType, $foundParameter['schema']['type'], \sprintf('Parameter schema type should be %s', $expectedSchemaType));
340-
}
341-
342338
if (isset($foundParameter['expectedDescription'])) {
343339
$this->assertSame($expectedDescription, $foundParameter['description'] ?? '', \sprintf('Description should be %s', $expectedDescription));
344340
}
341+
342+
if ($expectedSchema) {
343+
$this->assertSame($expectedSchema, $foundParameter['schema'], 'Parameter schema should match expected schema');
344+
}
345+
345346
$this->assertSame($expectedStyle, $foundParameter['style'] ?? 'form', \sprintf('Style should be %s', $expectedStyle));
346347
$this->assertSame($expectedExplode, $foundParameter['explode'] ?? false, \sprintf('Explode should be %s', $expectedExplode ? 'true' : 'false'));
347348
}
@@ -354,29 +355,40 @@ public static function openApiParameterDocumentationProvider(): array
354355
'shouldHaveArrayNotation' => true,
355356
'expectedStyle' => 'deepObject',
356357
'expectedExplode' => true,
357-
'expectedSchemaType' => 'string',
358+
'expectedDescription' => '',
359+
'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string']],
358360
],
359361
'default behavior with an extra description' => [
360362
'parameterName' => 'brandWithDescription',
361363
'shouldHaveArrayNotation' => true,
362364
'expectedStyle' => 'deepObject',
363365
'expectedExplode' => true,
364-
'expectedSchemaType' => 'string',
365366
'expectedDescription' => 'Extra description about the filter',
367+
'expectedSchema' => ['type' => 'array', 'items' => ['type' => 'string']],
366368
],
367369
'explicit schema type string should not use array notation' => [
368370
'parameterName' => 'exactBrand',
369371
'shouldHaveArrayNotation' => false,
370372
'expectedStyle' => 'form',
371373
'expectedExplode' => false,
372-
'expectedSchemaType' => 'string',
374+
'expectedDescription' => '',
375+
'expectedSchema' => ['type' => 'string'],
373376
],
374377
'castToArray false should not use array notation' => [
375378
'parameterName' => 'exactCategory',
376379
'shouldHaveArrayNotation' => false,
377380
'expectedStyle' => 'form',
378381
'expectedExplode' => false,
379-
'expectedSchemaType' => 'string',
382+
'expectedDescription' => '',
383+
'expectedSchema' => ['type' => 'string'],
384+
],
385+
'with schema and default castToArray should wrap schema in array type' => [
386+
'parameterName' => 'tags',
387+
'shouldHaveArrayNotation' => true,
388+
'expectedStyle' => 'deepObject',
389+
'expectedExplode' => true,
390+
'expectedDescription' => '',
391+
'expectedSchema' => ['type' => 'array', 'items' => ['anyOf' => [['type' => 'array', 'items' => ['type' => 'string']], ['type' => 'string']]]],
380392
],
381393
];
382394
}

0 commit comments

Comments
 (0)