From 4da09bc891d0c11a8724f1c5ffc559525272634a Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Thu, 12 Oct 2023 23:56:38 +0700 Subject: [PATCH] [Form] Fix merging params & files when "multiple" is enabled If a form field is configured with the "multiple" option, the request handler merges param values with uploaded files. However, it does not merge correctly if "multiple" is enabled. Example: With the example, the file field will incorrectly replace the first hidden field, when they should be merged. This commit fixes the problem. --- .../HttpFoundationRequestHandler.php | 3 +- .../Component/Form/NativeRequestHandler.php | 3 +- .../Tests/AbstractRequestHandlerTestCase.php | 36 +++++++++++++++++++ src/Symfony/Component/Form/Util/FormUtil.php | 25 +++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 05503ff52977f..90723fd8b48a9 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\RequestHandlerInterface; +use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -95,7 +96,7 @@ public function handleRequest(FormInterface $form, $request = null) } if (\is_array($params) && \is_array($files)) { - $data = array_replace_recursive($params, $files); + $data = FormUtil::mergeParamsAndFiles($params, $files); } else { $data = $params ?: $files; } diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index 7b39ad3a17c65..1afa6a6ba734f 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\ServerParams; /** @@ -106,7 +107,7 @@ public function handleRequest(FormInterface $form, $request = null) } if (\is_array($params) && \is_array($files)) { - $data = array_replace_recursive($params, $files); + $data = FormUtil::mergeParamsAndFiles($params, $files); } else { $data = $params ?: $files; } diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php index becf3504c3183..c61447a1ddc68 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php @@ -236,6 +236,42 @@ public function testMergeParamsAndFiles($method) $this->assertSame($file, $form->get('field2')->getData()); } + /** + * @dataProvider methodExceptGetProvider + */ + public function testMergeParamsAndFilesMultiple($method) + { + $form = $this->createForm('param1', $method, true); + $form->add($this->createBuilder('field1', false, ['allow_file_upload' => true, 'multiple' => true])->getForm()); + $file1 = $this->getUploadedFile(); + $file2 = $this->getUploadedFile(); + + $this->setRequestData($method, [ + 'param1' => [ + 'field1' => [ + 'foo', + 'bar', + 'baz', + ], + ], + ], [ + 'param1' => [ + 'field1' => [ + $file1, + $file2, + ], + ], + ]); + + $this->requestHandler->handleRequest($form, $this->request); + $data = $form->get('field1')->getData(); + + $this->assertTrue($form->isSubmitted()); + $this->assertIsArray($data); + $this->assertCount(5, $data); + $this->assertSame(['foo', 'bar', 'baz', $file1, $file2], $data); + } + /** * @dataProvider methodExceptGetProvider */ diff --git a/src/Symfony/Component/Form/Util/FormUtil.php b/src/Symfony/Component/Form/Util/FormUtil.php index fed96de4fa9b3..6c7873de70cb6 100644 --- a/src/Symfony/Component/Form/Util/FormUtil.php +++ b/src/Symfony/Component/Form/Util/FormUtil.php @@ -41,4 +41,29 @@ public static function isEmpty($data) // not considered to be empty, ever. return null === $data || '' === $data; } + + /** + * Recursively replaces or appends elements of the first array with elements + * of second array. If the key is an integer, the values will be appended to + * the new array; otherwise, the value from the second array will replace + * the one from the first array. + */ + public static function mergeParamsAndFiles(array $params, array $files): array + { + $result = []; + + foreach ($params as $key => $value) { + if (\is_array($value) && \is_array($files[$key] ?? null)) { + $value = self::mergeParamsAndFiles($value, $files[$key]); + unset($files[$key]); + } + if (\is_int($key)) { + $result[] = $value; + } else { + $result[$key] = $value; + } + } + + return array_merge($result, $files); + } }