From fc7b7c86f3e45872d8386bb73e48ec11d3dfe824 Mon Sep 17 00:00:00 2001 From: DjordyKoert Date: Thu, 2 May 2024 13:38:44 +0200 Subject: [PATCH] [HttpKernel] Support variadic with #[MapRequestPayload] --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../RequestPayloadValueResolver.php | 10 ++++-- .../RequestPayloadValueResolverTest.php | 36 ++++++++++++++++++- .../UploadedFileValueResolverTest.php | 2 +- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 81daf2166f708..2fb0d3c9e9292 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * Add `$type` argument to `#[MapRequestPayload]` that allows mapping a list of items * Deprecate `Extension::addAnnotatedClassesToCompile()` and related code infrastructure * Add `#[MapUploadedFile]` attribute to fetch, validate, and inject uploaded files into controller arguments + * Support variadic argument with `#[MapRequestPayload]` 7.0 --- diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php index c35d5e7e29381..9938d4a4a7144 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php @@ -79,7 +79,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable return []; } - if (!$attribute instanceof MapUploadedFile && $argument->isVariadic()) { + if ($attribute instanceof MapQueryString && $argument->isVariadic()) { throw new \LogicException(sprintf('Mapping variadic argument "$%s" is not supported.', $argument->getName())); } @@ -170,7 +170,11 @@ public function onKernelControllerArguments(ControllerArgumentsEvent $event): vo }; } - $arguments[$i] = $payload; + if ($argument->metadata->isVariadic() && \is_array($payload)) { + array_splice($arguments, $i, 1, $payload); + } else { + $arguments[$i] = $payload; + } } $event->setArguments($arguments); @@ -204,6 +208,8 @@ private function mapRequestPayload(Request $request, ArgumentMetadata $argument, if ('array' === $argument->getType() && null !== $attribute->type) { $type = $attribute->type.'[]'; + } elseif ($argument->isVariadic()) { + $type = $argument->getType().'[]'; } else { $type = $argument->getType(); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php index b277650b44b45..d2196615bb32e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php @@ -498,7 +498,7 @@ public function testItThrowsOnVariadicArgument() $resolver = new RequestPayloadValueResolver($serializer, $validator); $argument = new ArgumentMetadata('variadic', RequestPayload::class, true, false, null, false, [ - MapRequestPayload::class => new MapRequestPayload(), + MapQueryString::class => new MapQueryString(), ]); $request = Request::create('/', 'POST'); @@ -874,6 +874,40 @@ public function testBoolArgumentInJsonBody() $this->assertTrue($event->getArguments()[0]->value); } + + public function testMapRequestPayloadVariadic() + { + $input = [ + ['price' => '50'], + ['price' => '23'], + ]; + $payload = [ + new RequestPayload(50), + new RequestPayload(23), + ]; + + $serializer = new Serializer([new ArrayDenormalizer(), new ObjectNormalizer()], ['json' => new JsonEncoder()]); + + $validator = $this->createMock(ValidatorInterface::class); + $validator->expects($this->once()) + ->method('validate') + ->willReturn(new ConstraintViolationList()); + + $resolver = new RequestPayloadValueResolver($serializer, $validator); + + $argument = new ArgumentMetadata('prices', RequestPayload::class, true, false, null, false, [ + MapRequestPayload::class => new MapRequestPayload(), + ]); + $request = Request::create('/', 'POST', $input); + + $kernel = $this->createMock(HttpKernelInterface::class); + $arguments = $resolver->resolve($request, $argument); + $event = new ControllerArgumentsEvent($kernel, function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST); + + $resolver->onKernelControllerArguments($event); + + $this->assertEquals($payload, $event->getArguments()); + } } class RequestPayload diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php index 5eb0d32483ed5..0340cb6c6b970 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php @@ -269,7 +269,7 @@ static function () {}, $resolver->onKernelControllerArguments($event); /** @var UploadedFile[] $data */ - $data = $event->getArguments()[0]; + $data = $event->getArguments(); $this->assertCount(2, $data); $this->assertSame('file-small.txt', $data[0]->getFilename());