[Form] Fix ChoiceType to ensure submitted data is not nested unnecessarily

This commit is contained in:
Issei.M 2017-01-13 14:08:30 +09:00 committed by Fabien Potencier
parent 6babdb3296
commit 64d7a82d28
2 changed files with 46 additions and 3 deletions

View File

@ -160,6 +160,22 @@ class ChoiceType extends AbstractType
// transformation is merged back into the original collection
$builder->addEventSubscriber(new MergeCollectionListener(true, true));
}
// To avoid issues when the submitted choices are arrays (i.e. array to string conversions),
// we have to ensure that all elements of the submitted choice data are strings or null.
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getData();
if (!is_array($data)) {
return;
}
foreach ($data as $v) {
if (null !== $v && !is_string($v)) {
throw new TransformationFailedException('All choices submitted must be NULL or strings.');
}
}
}, 256);
}
/**
@ -505,8 +521,8 @@ class ChoiceType extends AbstractType
* "choice_label" closure by default.
*
* @param array|\Traversable $choices The choice labels indexed by choices
* @param object $choiceLabels The object that receives the choice labels
* indexed by generated keys.
* @param object $choiceLabels the object that receives the choice labels
* indexed by generated keys
* @param int $nextKey The next generated key
*
* @return array The choices in a normalized array with labels replaced by generated keys

View File

@ -14,9 +14,10 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type;
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Form\Tests\Fixtures\ChoiceSubType;
class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
class ChoiceTypeTest extends TypeTestCase
{
private $choices = array(
'Bernhard' => 'a',
@ -2283,4 +2284,30 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
// In this case the 'choice_label' closure returns null and not the closure from the first choice type.
$this->assertNull($form->get('subChoice')->getConfig()->getOption('choice_label'));
}
/**
* @dataProvider invalidNestedValueTestMatrix
*/
public function testSubmitInvalidNestedValue($multiple, $expanded, $submissionData)
{
$form = $this->factory->create('choice', null, array(
'choices' => $this->choices,
'multiple' => $multiple,
'expanded' => $expanded,
));
$form->submit($submissionData);
$this->assertFalse($form->isSynchronized());
$this->assertEquals('All choices submitted must be NULL or strings.', $form->getTransformationFailure()->getMessage());
}
public function invalidNestedValueTestMatrix()
{
return array(
'non-multiple, non-expanded' => array(false, false, array(array())),
'non-multiple, expanded' => array(false, true, array(array())),
'multiple, non-expanded' => array(true, false, array(array())),
'multiple, expanded' => array(true, true, array(array())),
);
}
}