Skip to content

Commit 5459ba3

Browse files
authored
fix(metadata): parameter cast to array flag (#7160)
1 parent efd00d1 commit 5459ba3

File tree

4 files changed

+70
-4
lines changed

4 files changed

+70
-4
lines changed

src/Metadata/Parameter.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function __construct(
5050
protected ?array $extraProperties = [],
5151
protected array|string|null $filterContext = null,
5252
protected ?Type $nativeType = null,
53+
protected ?bool $castToArray = null,
5354
) {
5455
}
5556

@@ -312,4 +313,17 @@ public function withNativeType(Type $nativeType): self
312313

313314
return $self;
314315
}
316+
317+
public function getCastToArray(): ?bool
318+
{
319+
return $this->castToArray;
320+
}
321+
322+
public function withCastToArray(bool $castToArray): self
323+
{
324+
$self = clone $this;
325+
$self->castToArray = $castToArray;
326+
327+
return $self;
328+
}
315329
}

src/State/Util/ParameterParserTrait.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,11 @@ private function extractParameterValues(Parameter $parameter, array $values): st
9292
}
9393
}
9494

95-
if ($isCollection) {
96-
$value = \is_array($value) ? $value : [$value];
97-
} elseif ($parameter instanceof HeaderParameter && \is_array($value) && array_is_list($value) && 1 === \count($value)) {
95+
if ($isCollection && true === $parameter->getCastToArray() && !\is_array($value)) {
96+
$value = [$value];
97+
}
98+
99+
if (!$isCollection && $parameter instanceof HeaderParameter && \is_array($value) && array_is_list($value) && 1 === \count($value)) {
98100
$value = $value[0];
99101
}
100102

tests/Fixtures/TestBundle/ApiResource/WithParameter.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
use Symfony\Component\Serializer\Attribute\Groups;
3030
use Symfony\Component\TypeInfo\Type\BuiltinType;
3131
use Symfony\Component\TypeInfo\TypeIdentifier;
32+
use Symfony\Component\Validator\Constraints\All;
3233
use Symfony\Component\Validator\Constraints as Assert;
34+
use Symfony\Component\Validator\Constraints\Country;
3335

3436
#[Get(
3537
uriTemplate: 'with_parameters/{id}{._format}',
@@ -56,6 +58,20 @@
5658
],
5759
provider: [self::class, 'collectionProvider']
5860
)]
61+
#[GetCollection(
62+
uriTemplate: 'with_parameters_country{._format}',
63+
parameters: [
64+
'country' => new QueryParameter(schema: ['type' => 'string'], constraints: [new Country()]),
65+
],
66+
provider: [self::class, 'collectionProvider']
67+
)]
68+
#[GetCollection(
69+
uriTemplate: 'with_parameters_countries{._format}',
70+
parameters: [
71+
'country' => new QueryParameter(constraints: [new All([new Country()])], castToArray: true),
72+
],
73+
provider: [self::class, 'collectionProvider'],
74+
)]
5975
#[GetCollection(
6076
uriTemplate: 'validate_parameters{._format}',
6177
parameters: [
@@ -105,7 +121,6 @@
105121
parameters: new Parameters([
106122
new QueryParameter(
107123
key: 'q',
108-
nativeType: new BuiltinType(TypeIdentifier::STRING),
109124
),
110125
new HeaderParameter(
111126
key: 'q',

tests/Functional/Parameters/ParameterTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ public function testHeaderAndQuery(): void
102102
]);
103103
}
104104

105+
public function testHeaderAndQueryWithArray(): void
106+
{
107+
$response = self::createClient()->request('GET', 'with_parameters_header_and_query?q[]=blabla', ['headers' => ['q' => '(complex stuff)']]);
108+
$this->assertEquals($response->toArray(), [
109+
'(complex stuff)',
110+
['blabla'],
111+
]);
112+
}
113+
105114
public function testHeaderParameterRequired(): void
106115
{
107116
self::createClient()->request('GET', 'header_required', ['headers' => ['req' => 'blabla']]);
@@ -125,4 +134,30 @@ public static function provideHeaderValues(): iterable
125134
yield 'too low' => ['0', 422];
126135
yield 'invalid integer' => ['string', 422];
127136
}
137+
138+
#[DataProvider('provideCountryValues')]
139+
public function testIssue7157(string $queryParameter, int $expectedStatusCode): void
140+
{
141+
self::createClient()->request('GET', 'with_parameters_country?'.$queryParameter);
142+
$this->assertResponseStatusCodeSame($expectedStatusCode);
143+
}
144+
145+
public static function provideCountryValues(): iterable
146+
{
147+
yield 'valid country' => ['country=FR', 200];
148+
yield 'array of countries' => ['country[]=FR', 422];
149+
}
150+
151+
#[DataProvider('provideCountriesValues')]
152+
public function testIssue7157WithCountries(string $queryParameter, int $expectedStatusCode): void
153+
{
154+
self::createClient()->request('GET', 'with_parameters_countries?'.$queryParameter);
155+
$this->assertResponseStatusCodeSame($expectedStatusCode);
156+
}
157+
158+
public static function provideCountriesValues(): iterable
159+
{
160+
yield 'valid country' => ['country=FR', 200];
161+
yield 'array of countries' => ['country[]=FR', 200];
162+
}
128163
}

0 commit comments

Comments
 (0)