/** * Creates a new violation path from a string. * * @param string $violationPath The property path of a {@link ConstraintViolation} * object. */ public function __construct($violationPath) { $path = new PropertyPath($violationPath); $elements = $path->getElements(); $positions = $path->getPositions(); $data = false; for ($i = 0, $l = count($elements); $i < $l; ++$i) { if (!$data) { // The element "data" has not yet been passed if ('children' === $elements[$i] && $path->isProperty($i)) { // Skip element "children" ++$i; // Next element must exist and must be an index // Otherwise consider this the end of the path if ($i >= $l || !$path->isIndex($i)) { break; } $this->elements[] = $elements[$i]; $this->positions[] = $positions[$i]; $this->isIndex[] = true; $this->mapsForm[] = true; } elseif ('data' === $elements[$i] && $path->isProperty($i)) { // Skip element "data" ++$i; // End of path if ($i >= $l) { break; } $this->elements[] = $elements[$i]; $this->positions[] = $positions[$i]; $this->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; $data = true; } else { // Neither "children" nor "data" property found // Consider this the end of the path break; } } else { // Already after the "data" element // Pick everything as is $this->elements[] = $elements[$i]; $this->positions[] = $positions[$i]; $this->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; } } $this->length = count($this->elements); $this->pathAsString = $violationPath; $this->resizeString(); }
/** * @dataProvider provideCustomDataErrorTests */ public function testCustomDataErrorMapping($target, $mapFrom, $mapTo, $childName, $childPath, $grandChildName, $grandChildPath, $violationPath) { $violation = $this->getConstraintViolation($violationPath); $parent = $this->getForm('parent', null, null, array($mapFrom => $mapTo)); $child = $this->getForm($childName, $childPath); $grandChild = $this->getForm($grandChildName, $grandChildPath); $parent->add($child); $child->add($grandChild); // Add a field mapped to the first element of $mapFrom // to try to distract the algorithm // Only add it if we expect the error to come up on a different // level than LEVEL_0, because in this case the error would // (correctly) be mapped to the distraction field if ($target !== self::LEVEL_0) { $mapFromPath = new PropertyPath($mapFrom); $mapFromPrefix = $mapFromPath->isIndex(0) ? '['.$mapFromPath->getElement(0).']' : $mapFromPath->getElement(0); $distraction = $this->getForm('distraction', $mapFromPrefix); $parent->add($distraction); } $this->mapper->mapViolation($violation, $parent); if ($target !== self::LEVEL_0) { $this->assertFalse($distraction->hasErrors(), 'distraction should not have an error, but has one'); } if (self::LEVEL_0 === $target) { $this->assertEquals(array($this->getFormError()), $parent->getErrors(), $parent->getName() . ' should have an error, but has none'); $this->assertFalse($child->hasErrors(), $childName . ' should not have an error, but has one'); $this->assertFalse($grandChild->hasErrors(), $grandChildName . ' should not have an error, but has one'); } elseif (self::LEVEL_1 === $target) { $this->assertFalse($parent->hasErrors(), $parent->getName() . ' should not have an error, but has one'); $this->assertEquals(array($this->getFormError()), $child->getErrors(), $childName . ' should have an error, but has none'); $this->assertFalse($grandChild->hasErrors(), $grandChildName . ' should not have an error, but has one'); } else { $this->assertFalse($parent->hasErrors(), $parent->getName() . ' should not have an error, but has one'); $this->assertFalse($child->hasErrors(), $childName . ' should not have an error, but has one'); $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName. ' should have an error, but has none'); } }
/** * @expectedException \OutOfBoundsException */ public function testIsIndexDoesNotAcceptNegativeIndices() { $propertyPath = new PropertyPath('grandpa.parent[child]'); $propertyPath->isIndex(-1); }