Skip to content

Commit e9c8b66

Browse files
committed
Merge branch '2.3' into 2.7
* 2.3: [DependencyInjection] fix dumped YAML snytax Remove InputOption::VALUE_REQUIRED mode from $default parameter description as InputOption::setDefault() throws an exception only when called in InputOption::VALUE_NONE mode. In practice the $default value could still be accessed in InputOption::VALUE_REQUIRED mode in case InputOption was never set but accessed from InputDefinition::getOption() method [Form] Fixed violation mapping if multiple forms are using the same (or part of the same) property path [TwigBridge] Symfony 3.1 forward compatibility
2 parents 4ebf00d + 47af57f commit e9c8b66

File tree

2 files changed

+41
-35
lines changed

2 files changed

+41
-35
lines changed

Extension/Validator/ViolationMapper/ViolationMapper.php

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,9 @@ public function mapViolation(ConstraintViolation $violation, FormInterface $form
148148
*/
149149
private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it)
150150
{
151-
// Remember at what property path underneath "data"
152-
// we are looking. Check if there is a child with that
153-
// path, otherwise increase path by one more piece
151+
$target = null;
154152
$chunk = '';
155-
$foundChild = null;
156-
$foundAtIndex = 0;
153+
$foundAtIndex = null;
157154

158155
// Construct mapping rules for the given form
159156
$rules = array();
@@ -165,17 +162,11 @@ private function matchChild(FormInterface $form, PropertyPathIteratorInterface $
165162
}
166163
}
167164

168-
// Skip forms inheriting their parent data when iterating the children
169-
$childIterator = new \RecursiveIteratorIterator(
165+
$children = iterator_to_array(new \RecursiveIteratorIterator(
170166
new InheritDataAwareIterator($form)
171-
);
172-
173-
// Make the path longer until we find a matching child
174-
while (true) {
175-
if (!$it->valid()) {
176-
return;
177-
}
167+
));
178168

169+
while ($it->valid()) {
179170
if ($it->isIndex()) {
180171
$chunk .= '['.$it->current().']';
181172
} else {
@@ -197,33 +188,27 @@ private function matchChild(FormInterface $form, PropertyPathIteratorInterface $
197188
}
198189
}
199190

200-
// Test children unless we already found one
201-
if (null === $foundChild) {
202-
foreach ($childIterator as $child) {
203-
/* @var FormInterface $child */
204-
$childPath = (string) $child->getPropertyPath();
205-
206-
// Child found, mark as return value
207-
if ($chunk === $childPath) {
208-
$foundChild = $child;
209-
$foundAtIndex = $it->key();
210-
}
191+
/** @var FormInterface $child */
192+
foreach ($children as $key => $child) {
193+
$childPath = (string) $child->getPropertyPath();
194+
if ($childPath === $chunk) {
195+
$target = $child;
196+
$foundAtIndex = $it->key();
197+
} elseif (0 === strpos($childPath, $chunk)) {
198+
continue;
211199
}
200+
201+
unset($children[$key]);
212202
}
213203

214-
// Add element to the chunk
215204
$it->next();
205+
}
216206

217-
// If we reached the end of the path or if there are no
218-
// more matching mapping rules, return the found child
219-
if (null !== $foundChild && (!$it->valid() || count($rules) === 0)) {
220-
// Reset index in case we tried to find mapping
221-
// rules further down the path
222-
$it->seek($foundAtIndex);
223-
224-
return $foundChild;
225-
}
207+
if (null !== $foundAtIndex) {
208+
$it->seek($foundAtIndex);
226209
}
210+
211+
return $target;
227212
}
228213

229214
/**

Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,4 +1539,25 @@ public function testErrorMappingForFormInheritingParentData($target, $childName,
15391539
$this->assertEquals(array($this->getFormError($violation, $grandChild)), iterator_to_array($grandChild->getErrors()), $grandChildName.' should have an error, but has none');
15401540
}
15411541
}
1542+
1543+
public function testBacktrackIfSeveralSubFormsWithSamePropertyPath()
1544+
{
1545+
$violation = $this->getConstraintViolation('data.address[street]');
1546+
$parent = $this->getForm('parent');
1547+
$child1 = $this->getForm('subform1', 'address');
1548+
$child2 = $this->getForm('subform2', 'address');
1549+
$grandChild = $this->getForm('street');
1550+
1551+
$parent->add($child1);
1552+
$parent->add($child2);
1553+
$child2->add($grandChild);
1554+
1555+
$this->mapper->mapViolation($violation, $parent);
1556+
1557+
// The error occurred on the child of the second form with the same path
1558+
$this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one');
1559+
$this->assertCount(0, $child1->getErrors(), $child1->getName().' should not have an error, but has one');
1560+
$this->assertCount(0, $child2->getErrors(), $child2->getName().' should not have an error, but has one');
1561+
$this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChild->getName().' should have an error, but has none');
1562+
}
15421563
}

0 commit comments

Comments
 (0)