bug #17099 [Form] Fixed violation mapping if multiple forms are using the same (or part of the same) property path (alekitto)
This PR was squashed before being merged into the 2.3 branch (closes #17099).
Discussion
----------
[Form] Fixed violation mapping if multiple forms are using the same (or part of the same) property path
| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #5656
| License | MIT
| Doc PR |
Commits
-------
f005c80
[Form] Fixed violation mapping if multiple forms are using the same (or part of the same) property path
This commit is contained in:
commit
d4ac467462
@ -147,12 +147,9 @@ class ViolationMapper implements ViolationMapperInterface
|
|||||||
*/
|
*/
|
||||||
private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it)
|
private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it)
|
||||||
{
|
{
|
||||||
// Remember at what property path underneath "data"
|
$target = null;
|
||||||
// we are looking. Check if there is a child with that
|
|
||||||
// path, otherwise increase path by one more piece
|
|
||||||
$chunk = '';
|
$chunk = '';
|
||||||
$foundChild = null;
|
$foundAtIndex = null;
|
||||||
$foundAtIndex = 0;
|
|
||||||
|
|
||||||
// Construct mapping rules for the given form
|
// Construct mapping rules for the given form
|
||||||
$rules = array();
|
$rules = array();
|
||||||
@ -164,17 +161,11 @@ class ViolationMapper implements ViolationMapperInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip forms inheriting their parent data when iterating the children
|
$children = iterator_to_array(new \RecursiveIteratorIterator(
|
||||||
$childIterator = new \RecursiveIteratorIterator(
|
|
||||||
new InheritDataAwareIterator($form)
|
new InheritDataAwareIterator($form)
|
||||||
);
|
));
|
||||||
|
|
||||||
// Make the path longer until we find a matching child
|
|
||||||
while (true) {
|
|
||||||
if (!$it->valid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
while ($it->valid()) {
|
||||||
if ($it->isIndex()) {
|
if ($it->isIndex()) {
|
||||||
$chunk .= '['.$it->current().']';
|
$chunk .= '['.$it->current().']';
|
||||||
} else {
|
} else {
|
||||||
@ -196,33 +187,27 @@ class ViolationMapper implements ViolationMapperInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test children unless we already found one
|
/** @var FormInterface $child */
|
||||||
if (null === $foundChild) {
|
foreach ($children as $key => $child) {
|
||||||
foreach ($childIterator as $child) {
|
$childPath = (string) $child->getPropertyPath();
|
||||||
/* @var FormInterface $child */
|
if ($childPath === $chunk) {
|
||||||
$childPath = (string) $child->getPropertyPath();
|
$target = $child;
|
||||||
|
$foundAtIndex = $it->key();
|
||||||
// Child found, mark as return value
|
} elseif (0 === strpos($childPath, $chunk)) {
|
||||||
if ($chunk === $childPath) {
|
continue;
|
||||||
$foundChild = $child;
|
|
||||||
$foundAtIndex = $it->key();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unset($children[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add element to the chunk
|
|
||||||
$it->next();
|
$it->next();
|
||||||
|
|
||||||
// If we reached the end of the path or if there are no
|
|
||||||
// more matching mapping rules, return the found child
|
|
||||||
if (null !== $foundChild && (!$it->valid() || count($rules) === 0)) {
|
|
||||||
// Reset index in case we tried to find mapping
|
|
||||||
// rules further down the path
|
|
||||||
$it->seek($foundAtIndex);
|
|
||||||
|
|
||||||
return $foundChild;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $foundAtIndex) {
|
||||||
|
$it->seek($foundAtIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1474,4 +1474,25 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
|
$this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
$parent->add($child1);
|
||||||
|
$parent->add($child2);
|
||||||
|
$child2->add($grandChild);
|
||||||
|
|
||||||
|
$this->mapper->mapViolation($violation, $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()), $grandChild->getErrors(), $grandChild->getName().' should have an error, but has none');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user