bug #18747 [2.8] [Form] Modified iterator_to_array's 2nd parameter to false in ViolationMapper (issei-m)
This PR was submitted for the 2.8 branch but it was merged into the 2.7 branch instead (closes #18747). Discussion ---------- [2.8] [Form] Modified iterator_to_array's 2nd parameter to false in ViolationMapper | Q | A | ------------- | --- | Branch? | 2.8 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | n/a | License | MIT | Doc PR | n/a This bug was introduced in PR #17099. So does not represent in 2.8.2 or older. If we have the following structure form: ```php $builder = $formFactory->createBuilder(); $form = $builder ->add( $builder->create('person1_name', FormType::class, ['inherit_data' => true]) ->add('first', TextType::class, ['property_path' => '[person1_first_name]']) ->add('last', TextType::class, ['property_path' => '[person1_last_name]']) ) ->add( $builder->create('person2_name', FormType::class, ['inherit_data' => true]) ->add('first', TextType::class, ['property_path' => '[person2_first_name]']) ->add('last', TextType::class, ['property_path' => '[person2_last_name]']) ) ->getForm() ; ``` The following mapping for this form doesn't work correctly: ```php $mapper = new ViolationMapper(); $mapper->mapViolation(new ConstraintViolation('', '', [], null, 'data[person1_first_name]', null), $form); $form['person1_name']['first']->getErrors(); // empty $form->getErrors(); // The violation is mapped to here instead. ``` ## Cause Because ViolationMapper uses `iterator_to_array` in [here](f29d46f29b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php (L165)
) to collect the sub forms. `person1_name` and `person2_name` enable `inherit_data` option. So ViolationMapper will attempt to collect the sub forms of root form like this: ```php [ 'first' => Form object, // root.person1_name.first 'last' => Form object, // root.person1_name.last 'first' => Form object, // root.person2_name.first 'last' => Form object, // root.person2_name.last ] ``` As you can see, The name `first` and `last` are used in two places, thus we cannot get result like that. (first/last of person1_name are overwritten by person2_name's) So the violation will finally lost the form where it should map to. It should pass `false` to `iterator_to_array`'s 2nd parameter. Commits -------ae38660
[2.8] [Form] Modified iterator_to_array's 2nd parameter to false in ViolationMapper
This commit is contained in:
commit
0753bd70ae
@ -1542,24 +1542,39 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testBacktrackIfSeveralSubFormsWithSamePropertyPath()
|
||||
{
|
||||
$violation = $this->getConstraintViolation('data.address[street]');
|
||||
$parent = $this->getForm('parent');
|
||||
$child1 = $this->getForm('subform1', 'address');
|
||||
$child2 = $this->getForm('subform2', 'address');
|
||||
$grandChild = $this->getForm('street');
|
||||
$child3 = $this->getForm('subform3', null, null, array(), true);
|
||||
$child4 = $this->getForm('subform4', null, null, array(), true);
|
||||
$grandChild1 = $this->getForm('street');
|
||||
$grandChild2 = $this->getForm('street', '[sub_address1_street]');
|
||||
$grandChild3 = $this->getForm('street', '[sub_address2_street]');
|
||||
|
||||
$parent->add($child1);
|
||||
$parent->add($child2);
|
||||
$child2->add($grandChild);
|
||||
$parent->add($child3);
|
||||
$parent->add($child4);
|
||||
$child2->add($grandChild1);
|
||||
$child3->add($grandChild2);
|
||||
$child4->add($grandChild3);
|
||||
|
||||
$parent->submit(array());
|
||||
|
||||
$this->mapper->mapViolation($violation, $parent);
|
||||
$violation1 = $this->getConstraintViolation('data.address[street]');
|
||||
$violation2 = $this->getConstraintViolation('data[sub_address1_street]');
|
||||
$violation3 = $this->getConstraintViolation('data[sub_address2_street]');
|
||||
$this->mapper->mapViolation($violation1, $parent);
|
||||
$this->mapper->mapViolation($violation2, $parent);
|
||||
$this->mapper->mapViolation($violation3, $parent);
|
||||
|
||||
// The error occurred on the child of the second form with the same path
|
||||
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
|
||||
$this->assertCount(0, $child1->getErrors(), $child1->getName().' should not have an error, but has one');
|
||||
$this->assertCount(0, $child2->getErrors(), $child2->getName().' should not have an error, but has one');
|
||||
$this->assertEquals(array($this->getFormError($violation, $grandChild)), iterator_to_array($grandChild->getErrors()), $grandChild->getName().' should have an error, but has none');
|
||||
$this->assertCount(0, $child3->getErrors(), $child3->getName().' should not have an error, but has one');
|
||||
$this->assertCount(0, $child4->getErrors(), $child4->getName().' should not have an error, but has one');
|
||||
$this->assertEquals(array($this->getFormError($violation1, $grandChild1)), iterator_to_array($grandChild1->getErrors()), $grandChild1->getName().' should have an error, but has none');
|
||||
$this->assertEquals(array($this->getFormError($violation2, $grandChild2)), iterator_to_array($grandChild2->getErrors()), $grandChild2->getName().' should have an error, but has none');
|
||||
$this->assertEquals(array($this->getFormError($violation3, $grandChild3)), iterator_to_array($grandChild3->getErrors()), $grandChild3->getName().' should have an error, but has none');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user