/** * 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(); $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; } // All the following index items (regardless if .children is // explicitly used) are children and grand-children for (; $i < $l && $path->isIndex($i); ++$i) { $this->elements[] = $elements[$i]; $this->isIndex[] = true; $this->mapsForm[] = true; } // Rewind the pointer as the last element above didn't match // (even if the pointer was moved forward) --$i; } elseif ('data' === $elements[$i] && $path->isProperty($i)) { // Skip element "data" ++$i; // End of path if ($i >= $l) { break; } $this->elements[] = $elements[$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->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; } } $this->length = count($this->elements); $this->buildString(); }
/** * 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(); $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->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->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->isIndex[] = $path->isIndex($i); $this->mapsForm[] = false; } } $this->length = count($this->elements); $this->buildString(); }
/** * @expectedException \OutOfBoundsException */ public function testIsIndexDoesNotAcceptNegativeIndices() { $propertyPath = new PropertyPath('grandpa.parent[child]'); $propertyPath->isIndex(-1); }
/** * @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->assertCount(0, $distraction->getErrors(), 'distraction should not have an error, but has one'); } if (self::LEVEL_0 === $target) { $this->assertEquals(array($this->getFormError($violation)), $parent->getErrors(), $parent->getName() . ' should have an error, but has none'); $this->assertCount(0, $child->getErrors(), $childName . ' should not have an error, but has one'); $this->assertCount(0, $grandChild->getErrors(), $grandChildName . ' should not have an error, but has one'); } elseif (self::LEVEL_1 === $target) { $this->assertCount(0, $parent->getErrors(), $parent->getName() . ' should not have an error, but has one'); $this->assertEquals(array($this->getFormError($violation)), $child->getErrors(), $childName . ' should have an error, but has none'); $this->assertCount(0, $grandChild->getErrors(), $grandChildName . ' should not have an error, but has one'); } else { $this->assertCount(0, $parent->getErrors(), $parent->getName() . ' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $childName . ' should not have an error, but has one'); $this->assertEquals(array($this->getFormError($violation)), $grandChild->getErrors(), $grandChildName . ' should have an error, but has none'); } }
/** * Replaces a sub-path by a different (sub-) path. * * @param integer $offset The offset at which to replace. * @param integer $length The length of the piece to replace. * @param PropertyPathInterface|string $path The path to insert. * @param integer $pathOffset The offset where the inserted piece * starts in $path. * @param integer $pathLength The length of the inserted piece. * If 0, the full path is inserted. * * @throws OutOfBoundsException If the offset is invalid */ public function replace($offset, $length, $path, $pathOffset = 0, $pathLength = 0) { if (is_string($path)) { $path = new PropertyPath($path); } if ($offset < 0 && abs($offset) <= $this->getLength()) { $offset = $this->getLength() + $offset; } elseif (!isset($this->elements[$offset])) { throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); } if (0 === $pathLength) { $pathLength = $path->getLength() - $pathOffset; } $this->resize($offset, $length, $pathLength); for ($i = 0; $i < $pathLength; ++$i) { $this->elements[$offset + $i] = $path->getElement($pathOffset + $i); $this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i); } }
/** * @param $path * @param $haystack * @return bool */ private function valueExist($path, array $haystack) { $propertyPath = new PropertyPath($path); $length = $propertyPath->getLength(); $valueExist = true; for ($i = 0; $i < $length; ++$i) { $property = $propertyPath->getElement($i); $isIndex = $propertyPath->isIndex($i); $propertyExist = $this->arrayPropertyExists($property, $haystack); if ($isIndex && !$propertyExist) { $valueExist = false; break; } } unset($propertyPath); return $valueExist; }