You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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](https://github.com/symfony/symfony/blob/f29d46f29b91ea5c30699cf6bdb8e65545d1dd26/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
// The error occurred on the child of the second form with the same path
1560
1571
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1561
1572
$this->assertCount(0, $child1->getErrors(), $child1->getName().' should not have an error, but has one');
1562
1573
$this->assertCount(0, $child2->getErrors(), $child2->getName().' should not have an error, but has one');
1563
-
$this->assertEquals(array($this->getFormError($violation, $grandChild)), iterator_to_array($grandChild->getErrors()), $grandChild->getName().' should have an error, but has none');
1574
+
$this->assertCount(0, $child3->getErrors(), $child3->getName().' should not have an error, but has one');
1575
+
$this->assertCount(0, $child4->getErrors(), $child4->getName().' should not have an error, but has one');
1576
+
$this->assertEquals(array($this->getFormError($violation1, $grandChild1)), iterator_to_array($grandChild1->getErrors()), $grandChild1->getName().' should have an error, but has none');
1577
+
$this->assertEquals(array($this->getFormError($violation2, $grandChild2)), iterator_to_array($grandChild2->getErrors()), $grandChild2->getName().' should have an error, but has none');
1578
+
$this->assertEquals(array($this->getFormError($violation3, $grandChild3)), iterator_to_array($grandChild3->getErrors()), $grandChild3->getName().' should have an error, but has none');
0 commit comments