From c8b61d576b2c206e04ed7006139bb4bf312bae2c Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Mon, 21 May 2012 09:51:42 +0200 Subject: [PATCH] [Form] Renamed FormMapping to MappingRule and moved some logic there to make rules more extendable --- .../Validator/ViolationMapper/FormMapping.php | 76 ------------- .../Validator/ViolationMapper/MappingRule.php | 107 ++++++++++++++++++ .../ViolationMapper/ViolationMapper.php | 40 +++---- 3 files changed, 120 insertions(+), 103 deletions(-) delete mode 100644 src/Symfony/Component/Form/Extension/Validator/ViolationMapper/FormMapping.php create mode 100644 src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/FormMapping.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/FormMapping.php deleted file mode 100644 index bf23ddaa70..0000000000 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/FormMapping.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; - -use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\Exception\ErrorMappingException; - -/** - * @author Bernhard Schussek - */ -class FormMapping -{ - /** - * @var FormInterface - */ - private $origin; - - /** - * @var FormInterface - */ - private $target; - - /** - * @var string - */ - private $targetPath; - - public function __construct(FormInterface $origin, $targetPath) - { - $this->origin = $origin; - $this->targetPath = $targetPath; - } - - /** - * @return FormInterface - */ - public function getOrigin() - { - return $this->origin; - } - - /** - * @return FormInterface - * - * @throws ErrorMappingException - */ - public function getTarget() - { - // Lazy initialization to make sure that the constructor is cheap - if (null === $this->target) { - $childNames = explode('.', $this->targetPath); - $target = $this->origin; - - foreach ($childNames as $childName) { - if (!$target->has($childName)) { - throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName())); - } - $target = $target->get($childName); - } - - // Only set once successfully resolved - $this->target = $target; - } - - return $this->target; - } -} diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php new file mode 100644 index 0000000000..56371ed198 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; + +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\Util\PropertyPathInterface; +use Symfony\Component\Form\Exception\ErrorMappingException; + +/** + * @author Bernhard Schussek + */ +class MappingRule +{ + /** + * @var FormInterface + */ + private $origin; + + /** + * @var string + */ + private $propertyPath; + + /** + * @var string + */ + private $targetPath; + + public function __construct(FormInterface $origin, $propertyPath, $targetPath) + { + $this->origin = $origin; + $this->propertyPath = $propertyPath; + $this->targetPath = $targetPath; + } + + /** + * @return FormInterface + */ + public function getOrigin() + { + return $this->origin; + } + + /** + * Matches a property path against the rule path. + * + * If the rule matches, the form mapped by the rule is returned. + * Otherwise this method returns false. + * + * @param string $propertyPath The property path to match against the rule. + * + * @return Boolean|FormInterface The mapped form or false. + */ + public function match($propertyPath) + { + if ($propertyPath === (string) $this->propertyPath) { + return $this->getTarget(); + } + + return false; + } + + /** + * Matches a property path against a prefix of the rule path. + * + * @param string $propertyPath The property path to match against the rule. + * + * @return Boolean Whether the property path is a prefix of the rule or not. + */ + public function isPrefix($propertyPath) + { + $length = strlen($propertyPath); + $prefix = substr($this->propertyPath, 0, $length); + $next = isset($this->propertyPath[$length]) ? $this->propertyPath[$length] : null; + + return $prefix === $propertyPath && ('[' === $next || '.' === $next); + } + + /** + * @return FormInterface + * + * @throws ErrorMappingException + */ + private function getTarget() + { + $childNames = explode('.', $this->targetPath); + $target = $this->origin; + + foreach ($childNames as $childName) { + if (!$target->has($childName)) { + throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName())); + } + $target = $target->get($childName); + } + + return $target; + } +} diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php index 4e7b27c36d..db014eca12 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -75,8 +75,10 @@ class ViolationMapper // mapped form of the violation path // e.g. "children[foo].children[bar].data.baz" // Here the innermost directly mapped child is "bar" - $this->setScope($form); + $it = new ViolationPathIterator($violationPath); + // The overhead of setScope() is not needed anymore here + $this->scope = $form; while ($it->valid() && $it->mapsForm()) { if (!$this->scope->has($it->current())) { @@ -84,7 +86,7 @@ class ViolationMapper break; } - $this->setScope($this->scope->get($it->current())); + $this->scope = $this->scope->get($it->current()); $it->next(); } } @@ -129,16 +131,17 @@ class ViolationMapper } // Test mapping rules as long as we have any - foreach ($this->rules as $path => $mapping) { + foreach ($this->rules as $key => $rule) { + /* @var MappingRule $rule */ + // Mapping rule matches completely, terminate. - if ($chunk === $path) { - /* @var FormMapping $mapping */ - return $mapping->getTarget(); + if (false !== ($form = $rule->match($chunk))) { + return $form; } // Keep only rules that have $chunk as prefix - if (!$this->isPrefixPath($chunk, $path)) { - unset($this->rules[$path]); + if (!$rule->isPrefix($chunk)) { + unset($this->rules[$key]); } } @@ -249,25 +252,8 @@ class ViolationMapper $this->children = new \RecursiveIteratorIterator( new VirtualFormAwareIterator($form->getChildren()) ); - foreach ($form->getAttribute('error_mapping') as $propertyPath => $childPath) { - $this->rules[$propertyPath] = new FormMapping($form, $childPath); + foreach ($form->getAttribute('error_mapping') as $propertyPath => $targetPath) { + $this->rules[] = new MappingRule($form, $propertyPath, $targetPath); } } - - /** - * Tests whether $needle is a prefix path of $haystack. - * - * @param string $needle - * @param string $haystack - * - * @return Boolean - */ - private function isPrefixPath($needle, $haystack) - { - $length = strlen($needle); - $prefix = substr($haystack, 0, $length); - $next = isset($haystack[$length]) ? $haystack[$length] : null; - - return $prefix === $needle && ('[' === $next || '.' === $next); - } }