Skip to content

Commit 2af8f39

Browse files
bug #50458 [HttpKernel] Fix default value ignored with pinned resolvers (HypeMC)
This PR was merged into the 6.3 branch. Discussion ---------- [HttpKernel] Fix default value ignored with pinned resolvers | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - Since #48992 the default value is ignored when, for example, `#[MapEntity]` is used: ```php #[Route('/')] #[Route('/{someId}')] public function index(#[MapEntity(id: 'someId')] ?Post $post): Response { // ... } ``` Before, `$post` would be `null` when making a request to `/`, now an exception is thrown: ``` Controller "App\Controller\TestController::index" requires that you provide a value for the "$post" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or there is a non-optional argument after this one. ``` Since I can't think of a valid case when one would want to ignore the default value, I'd suggest always adding the `DefaultValueResolver` to the list when a pinned resolver is used. Commits ------- fabe7bc [HttpKernel] Fix default value ignored with pinned resolvers
2 parents acac306 + fabe7bc commit 2af8f39

File tree

4 files changed

+36
-9
lines changed

4 files changed

+36
-9
lines changed

src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ public function getArguments(Request $request, callable $controller, \Reflection
7171
throw new ResolverNotFoundException($resolverName, $this->namedResolvers instanceof ServiceProviderInterface ? array_keys($this->namedResolvers->getProvidedServices()) : []);
7272
}
7373

74-
$argumentValueResolvers = [$this->namedResolvers->get($resolverName)];
74+
$argumentValueResolvers = [
75+
$this->namedResolvers->get($resolverName),
76+
new DefaultValueResolver(),
77+
];
7578
}
7679
}
7780

src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/QueryParameterValueResolver.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,8 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
3131

3232
$name = $attribute->name ?? $argument->getName();
3333
if (!$request->query->has($name)) {
34-
if ($argument->hasDefaultValue()) {
35-
return [$argument->getDefaultValue()];
36-
}
37-
38-
if ($argument->isNullable()) {
39-
return [null];
34+
if ($argument->isNullable() || $argument->hasDefaultValue()) {
35+
return [];
4036
}
4137

4238
throw new NotFoundHttpException(sprintf('Missing query parameter "%s".', $name));

src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/QueryParameterValueResolverTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ public static function provideTestResolve(): iterable
179179
yield 'parameter not found but nullable' => [
180180
Request::create('/', 'GET'),
181181
new ArgumentMetadata('firstName', 'string', false, false, false, true, [new MapQueryParameter()]),
182-
[null],
182+
[],
183183
null,
184184
];
185185

186186
yield 'parameter not found but optional' => [
187187
Request::create('/', 'GET'),
188188
new ArgumentMetadata('firstName', 'string', false, true, false, attributes: [new MapQueryParameter()]),
189-
[false],
189+
[],
190190
null,
191191
];
192192

src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,26 @@ public function testTargetedResolver()
296296
$this->assertSame([1], $resolver->getArguments($request, $controller));
297297
}
298298

299+
public function testTargetedResolverWithDefaultValue()
300+
{
301+
$resolver = self::getResolver([], [RequestAttributeValueResolver::class => new RequestAttributeValueResolver()]);
302+
303+
$request = Request::create('/');
304+
$controller = $this->controllerTargetingResolverWithDefaultValue(...);
305+
306+
$this->assertSame([2], $resolver->getArguments($request, $controller));
307+
}
308+
309+
public function testTargetedResolverWithNullableValue()
310+
{
311+
$resolver = self::getResolver([], [RequestAttributeValueResolver::class => new RequestAttributeValueResolver()]);
312+
313+
$request = Request::create('/');
314+
$controller = $this->controllerTargetingResolverWithNullableValue(...);
315+
316+
$this->assertSame([null], $resolver->getArguments($request, $controller));
317+
}
318+
299319
public function testDisabledResolver()
300320
{
301321
$resolver = self::getResolver(namedResolvers: []);
@@ -373,6 +393,14 @@ public function controllerTargetingResolver(#[ValueResolver(DefaultValueResolver
373393
{
374394
}
375395

396+
public function controllerTargetingResolverWithDefaultValue(#[ValueResolver(RequestAttributeValueResolver::class)] int $foo = 2)
397+
{
398+
}
399+
400+
public function controllerTargetingResolverWithNullableValue(#[ValueResolver(RequestAttributeValueResolver::class)] ?int $foo)
401+
{
402+
}
403+
376404
public function controllerDisablingResolver(#[ValueResolver(RequestAttributeValueResolver::class, disabled: true)] int $foo = 1)
377405
{
378406
}

0 commit comments

Comments
 (0)