[Form] Renamed FormMapping to MappingRule and moved some logic there to make rules more extendable
This commit is contained in:
parent
d0d1fe6182
commit
c8b61d576b
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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 <bschussek@gmail.com>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* 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 <bschussek@gmail.com>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user