8000 [Form] Fix ChoiceType to ensure submitted data is not nested unnecessarily by issei-m · Pull Request #21267 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,22 @@ public function buildForm(FormBuilderInterface $builder, array $options)
// 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)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a new event listener we could do this in the already existing one before flipping the data, can't we?

Copy link
Contributor Author
@issei-m issei-m Feb 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The listener you mentioned is only added when choice is multiple. Even though we would do so we still need to add a new listener for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I missed that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The is_string() check may be a little bit to restrictive in a loosely typed language like PHP.
In our code we have an event listener that adds IDs to the submitted form data. But the IDs are integers. So in Symfony 2.8.17 our processing works fine, but in 2.8.18 our processing fails. So for me the fixed code introduces a BC break. What is your opinion about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see #21957 which is part of the 2.8.19 release

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks :)
But 2.8.19 has some changes in DoctrineBridge that breaks our code (so we switched back to 2.18.18) :(

throw new TransformationFailedException('All choices submitted must be NULL or strings.');
}
}
}, 256);
}

/**
Expand Down Expand Up @@ -505,8 +521,8 @@ private function createChoiceListView(ChoiceListInterface $choiceList, array $op
* "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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component 9FFF \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',
Expand Down Expand Up @@ -2283,4 +2284,30 @@ public function testCustomChoiceTypeDoesNotInheritChoiceLabels()
// 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())),
);
}
}
0