From dd725bef4b558b386c454a2e1dd2087d4a8a690c Mon Sep 17 00:00:00 2001 From: HypeMC Date: Mon, 4 Dec 2023 20:14:47 +0100 Subject: [PATCH] [HttpKernel] Fix request attribute value ignored with pinned resolvers --- .../Controller/ArgumentResolver.php | 1 + .../Tests/Controller/ArgumentResolverTest.php | 49 +++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php index 3b0f89509f65c..6643cc58eede1 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php @@ -73,6 +73,7 @@ public function getArguments(Request $request, callable $controller, \Reflection $argumentValueResolvers = [ $this->namedResolvers->get($resolverName), + new RequestAttributeValueResolver(), new DefaultValueResolver(), ]; } diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php index ef44f45bae078..d34b0b4b450a1 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolverTest.php @@ -22,6 +22,8 @@ use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; +use Symfony\Component\HttpKernel\Controller\ValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory; use Symfony\Component\HttpKernel\Exception\ResolverNotFoundException; use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ExtendingRequest; @@ -298,17 +300,21 @@ public function testTargetedResolver() public function testTargetedResolverWithDefaultValue() { - $resolver = self::getResolver([], [RequestAttributeValueResolver::class => new RequestAttributeValueResolver()]); + $resolver = self::getResolver([], [TestEntityValueResolver::class => new TestEntityValueResolver()]); $request = Request::create('/'); $controller = $this->controllerTargetingResolverWithDefaultValue(...); - $this->assertSame([2], $resolver->getArguments($request, $controller)); + /** @var Post[] $arguments */ + $arguments = $resolver->getArguments($request, $controller); + + $this->assertCount(1, $arguments); + $this->assertSame('Default', $arguments[0]->title); } public function testTargetedResolverWithNullableValue() { - $resolver = self::getResolver([], [RequestAttributeValueResolver::class => new RequestAttributeValueResolver()]); + $resolver = self::getResolver([], [TestEntityValueResolver::class => new TestEntityValueResolver()]); $request = Request::create('/'); $controller = $this->controllerTargetingResolverWithNullableValue(...); @@ -316,6 +322,17 @@ public function testTargetedResolverWithNullableValue() $this->assertSame([null], $resolver->getArguments($request, $controller)); } + public function testTargetedResolverWithRequestAttributeValue() + { + $resolver = self::getResolver([], [TestEntityValueResolver::class => new TestEntityValueResolver()]); + + $request = Request::create('/'); + $request->attributes->set('foo', $object = new Post('Random '.time())); + $controller = $this->controllerTargetingResolverWithTestEntity(...); + + $this->assertSame([$object], $resolver->getArguments($request, $controller)); + } + public function testDisabledResolver() { $resolver = self::getResolver(namedResolvers: []); @@ -393,11 +410,15 @@ public function controllerTargetingResolver(#[ValueResolver(DefaultValueResolver { } - public function controllerTargetingResolverWithDefaultValue(#[ValueResolver(RequestAttributeValueResolver::class)] int $foo = 2) + public function controllerTargetingResolverWithDefaultValue(#[ValueResolver(TestEntityValueResolver::class)] Post $foo = new Post('Default')) + { + } + + public function controllerTargetingResolverWithNullableValue(#[ValueResolver(TestEntityValueResolver::class)] ?Post $foo) { } - public function controllerTargetingResolverWithNullableValue(#[ValueResolver(RequestAttributeValueResolver::class)] ?int $foo) + public function controllerTargetingResolverWithTestEntity(#[ValueResolver(TestEntityValueResolver::class)] Post $foo) { } @@ -422,3 +443,21 @@ public function controllerTargetingUnknownResolver( function controller_function($foo, $foobar) { } + +class TestEntityValueResolver implements ValueResolverInterface +{ + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + return Post::class === $argument->getType() && $request->request->has('title') + ? [new Post($request->request->get('title'))] + : []; + } +} + +class Post +{ + public function __construct( + public readonly string $title, + ) { + } +}