From 10e5189da493eefe1ebc36671399f3d2603e91f8 Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Mon, 19 May 2025 20:36:58 -0300 Subject: [PATCH] [HttpKernel] Fix `#[MapUploadedFile]` handling for optional file uploads --- .../RequestPayloadValueResolver.php | 6 +- .../UploadedFileValueResolverTest.php | 60 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php index a196250e8b23b..3a10c9d9c7854 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php @@ -232,6 +232,10 @@ private function mapRequestPayload(Request $request, ArgumentMetadata $argument, private function mapUploadedFile(Request $request, ArgumentMetadata $argument, MapUploadedFile $attribute): UploadedFile|array|null { - return $request->files->get($attribute->name ?? $argument->getName(), []); + if (!($files = $request->files->get($attribute->name ?? $argument->getName(), [])) && ($argument->isNullable() || $argument->hasDefaultValue())) { + return null; + } + + return $files; } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php index 5eb0d32483ed5..c15a625155d8f 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/UploadedFileValueResolverTest.php @@ -307,6 +307,66 @@ static function () {}, $resolver->onKernelControllerArguments($event); } + /** + * @dataProvider provideContext + */ + public function testShouldAllowEmptyWhenNullable(RequestPayloadValueResolver $resolver, Request $request) + { + $attribute = new MapUploadedFile(); + $argument = new ArgumentMetadata( + 'qux', + UploadedFile::class, + false, + false, + null, + true, + [$attribute::class => $attribute] + ); + /** @var HttpKernelInterface&MockObject $httpKernel */ + $httpKernel = $this->createMock(HttpKernelInterface::class); + $event = new ControllerArgumentsEvent( + $httpKernel, + static function () {}, + $resolver->resolve($request, $argument), + $request, + HttpKernelInterface::MAIN_REQUEST + ); + $resolver->onKernelControllerArguments($event); + $data = $event->getArguments()[0]; + + $this->assertNull($data); + } + + /** + * @dataProvider provideContext + */ + public function testShouldAllowEmptyWhenHasDefaultValue(RequestPayloadValueResolver $resolver, Request $request) + { + $attribute = new MapUploadedFile(); + $argument = new ArgumentMetadata( + 'qux', + UploadedFile::class, + false, + true, + null, + false, + [$attribute::class => $attribute] + ); + /** @var HttpKernelInterface&MockObject $httpKernel */ + $httpKernel = $this->createMock(HttpKernelInterface::class); + $event = new ControllerArgumentsEvent( + $httpKernel, + static function () {}, + $resolver->resolve($request, $argument), + $request, + HttpKernelInterface::MAIN_REQUEST + ); + $resolver->onKernelControllerArguments($event); + $data = $event->getArguments()[0]; + + $this->assertNull($data); + } + public static function provideContext(): iterable { $resolver = new RequestPayloadValueResolver(