From 479d0f6450d7cc66befbc008f2a58ad029f95e07 Mon Sep 17 00:00:00 2001 From: Artem Lopata Date: Fri, 10 Apr 2020 13:43:00 +0200 Subject: [PATCH] RepeatedType should always have inner types mapped --- .../Form/Extension/Core/Type/RepeatedType.php | 20 +++++++++- .../Extension/Core/Type/RepeatedTypeTest.php | 38 +++++++++++++++++++ .../Form/Tests/Fixtures/NotMappedType.php | 23 +++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Form/Tests/Fixtures/NotMappedType.php diff --git a/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php b/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php index ffb7520a582b6..915d1ceed5555 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Extension\Core\DataTransformer\ValueToDuplicatesTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -36,8 +37,8 @@ public function buildForm(FormBuilderInterface $builder, array $options) $options['first_name'], $options['second_name'], ])) - ->add($options['first_name'], $options['type'], array_merge($options['options'], $options['first_options'])) - ->add($options['second_name'], $options['type'], array_merge($options['options'], $options['second_options'])) + ->add($options['first_name'], $options['type'], $this->mergeOptions($options['options'], $options['first_options'])) + ->add($options['second_name'], $options['type'], $this->mergeOptions($options['options'], $options['second_options'])) ; } @@ -68,4 +69,19 @@ public function getBlockPrefix() { return 'repeated'; } + + private function mergeOptions(array $fieldOptions, array $innerOptions) + { + $mergedOptions = array_merge($fieldOptions, $innerOptions); + + if (\array_key_exists('mapped', $mergedOptions)) { + if (false === $mergedOptions['mapped']) { + throw new InvalidConfigurationException('Inner types must be mapped'); + } + } else { + $mergedOptions['mapped'] = true; + } + + return $mergedOptions; + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php index 8b4666d6fa5f0..a08e9081260a3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/RepeatedTypeTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Form; +use Symfony\Component\Form\Tests\Fixtures\NotMappedType; class RepeatedTypeTest extends BaseTypeTest { @@ -78,6 +80,19 @@ public function testSetRequired() $this->assertFalse($form['second']->isRequired()); } + public function testMappedOverridesDefault() + { + $form = $this->factory->create(NotMappedType::class); + $this->assertFalse($form->getConfig()->getMapped()); + + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'type' => NotMappedType::class, + ]); + + $this->assertTrue($form['first']->getConfig()->getMapped()); + $this->assertTrue($form['second']->getConfig()->getMapped()); + } + public function testSetInvalidOptions() { $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); @@ -105,6 +120,29 @@ public function testSetInvalidSecondOptions() ]); } + /** + * @param string $configurationKey + * @dataProvider notMappedConfigurationKeys + */ + public function testNotMappedInner($configurationKey) + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage('Inner types must be mapped'); + + $this->factory->create(static::TESTED_TYPE, null, [ + 'type' => TextTypeTest::TESTED_TYPE, + $configurationKey => ['mapped' => false], + ]); + } + + public function notMappedConfigurationKeys() + { + return [ + ['first_options'], + ['second_options'], + ]; + } + public function testSetErrorBubblingToTrue() { $form = $this->factory->create(static::TESTED_TYPE, null, [ diff --git a/src/Symfony/Component/Form/Tests/Fixtures/NotMappedType.php b/src/Symfony/Component/Form/Tests/Fixtures/NotMappedType.php new file mode 100644 index 0000000000000..14c340b8917af --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Fixtures/NotMappedType.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Fixtures; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class NotMappedType extends AbstractType +{ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('mapped', false); + } +}