8000 bug #21267 [Form] Fix ChoiceType to ensure submitted data is not nest… · symfony/symfony@8175248 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8175248

Browse files
committed
bug #21267 [Form] Fix ChoiceType to ensure submitted data is not nested unnecessarily (issei-m)
This PR was squashed before being merged into the 2.7 bra 10000 nch (closes #21267). Discussion ---------- [Form] Fix ChoiceType to ensure submitted data is not nested unnecessarily | Q | A | ------------- | --- | Branch? | 2.7 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Fixed ChoiceType to protect against some problem caused by treating of array. Let's say we have the choice-form like: ```php $form = $factory->create(ChoiceType, null, [ 'choices' => [ 'A', 'B', 'C', ], 'expanded' => true, 'multiple' => true, ]); ``` Then, submit data like this: ```php $form->submit([ [], // unnecessality nested ]); ``` (Yes, I agree in most cases these situation doesn't happen, but can be) Then, we get `array_flip(): Can only flip STRING and INTEGER values!` error at [here](https://github.com/symfony/symfony/blob/6babdb3296a5fbbd9c69d1e3410adbdf749959ef/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php#L114). Even if form is not `multiple`, annoying `Array to string conversion` error occurs in [here](https://github.com/symfony/symfony/blob/6babdb3296a5fbbd9c69d1e3410adbdf749959ef/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php#L144) (via [ChoicesToValuesTransformer](https://github.com/symfony/symfony/blob/5129c4cf7e294b1a5ea30d6fec6e89b75396dcd2/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php#L74)). (As far as I know, non-multiple and non-expanded form has no problem, thanks to [ChoiceToValueTransformer](https://github.com/symfony/symfony/blob/6babdb3296a5fbbd9c69d1e3410adbdf749959ef/src/Symfony/Component/Form/Extension/Core/DataTransformer/ChoiceToValueTransformer.php#L43)) To resolve these problems, I just added a simple-validation listener to choice type. Commits ------- 64d7a82 [Form] Fix ChoiceType to ensure submitted data is not nested unnecessarily
2 parents 0a15eea + 64d7a82 commit 8175248

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,22 @@ public function buildForm(FormBuilderInterface $builder, array $options)
160160
// transformation is merged back into the original collection
161161
$builder->addEventSubscriber(new MergeCollectionListener(true, true));
162162
}
163+
164+
// To avoid issues when the submitted choices are arrays (i.e. array to string conversions),
165+
// we have to ensure that all elements of the submitted choice data are strings or null.
166+
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
167+
$data = $event->getData();
168+
169+
if (!is_array($data)) {
170+
return;
171+
}
172+
173+
foreach ($data as $v) {
174+
if (null !== $v && !is_string($v)) {
175+
throw new TransformationFailedException('All choices submitted must be NULL or strings.');
176+
}
177+
}
178+
}, 256);
163179
}
164180

165181
/**
@@ -505,8 +521,8 @@ private function createChoiceListView(ChoiceListInterface $choiceList, array $op
505521
* "choice_label" closure by default.
506522
*
507523
* @param array|\Traversable $choices The choice labels indexed by choices
508-
* @param object $choiceLabels The object that receives the choice labels
509-
* indexed by generated keys.
524+
* @param object $choiceLabels the object that receives the choice labels
525+
* indexed by generated keys
510526
* @param int $nextKey The next generated key
511527
*
512528
* @return array The choices in a normalized array with labels replaced by generated keys

src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
1515
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1616
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
17+
use Symfony\Component\Form\Test\TypeTestCase;
1718
use Symfony\Component\Form\Tests\Fixtures\ChoiceSubType;
1819

19-
class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
20+
class ChoiceTypeTest extends TypeTestCase
2021
{
2122
private $choices = array(
2223
'Bernhard' => 'a',
@@ -2283,4 +2284,30 @@ public function testCustomChoiceTypeDoesNotInheritChoiceLabels()
22832284
// In this case the 'choice_label' closure returns null and not the closure from the first choice type.
22842285
$this->assertNull($form->get('subChoice')->getConfig()->getOption('choice_label'));
22852286
}
2287+
2288+
/**
2289+
* @dataProvider invalidNestedValueTestMatrix
2290+
*/
2291+
public function testSubmitInvalidNestedValue($multiple, $expanded, $submissionData)
2292+
{
2293+
$form = $this->factory->create('choice', null, array(
2294+
'choices' => $this->choices,
2295+
'multiple' => $multiple,
2296+
'expanded' => $expanded,
2297+
));
2298+
2299+
$form->submit($submissionData);
2300+
$this->assertFalse($form->isSynchronized());
2301+
$this->assertEquals('All choices submitted must be NULL or strings.', $form->getTransformationFailure()->getMessage());
2302+
}
2303+
2304+
public function invalidNestedValueTestMatrix()
2305+
{
2306+
return array(
2307+
'non-multiple, non-expanded' => array(false, false, array(array())),
2308+
'non-multiple, expanded' => array(false, true, array(array())),
2309+
'multiple, non-expanded' => array(true, false, array(array())),
2310+
'multiple, expanded' => array(true, true, array(array())),
2311+
);
2312+
}
22862313
}

0 commit comments

Comments
 (0)
0