[Validator] Decoupled the new classes a bit
This commit is contained in:
parent
a6ed4cae5d
commit
a40189ccb7
@ -15,7 +15,6 @@ use Symfony\Component\Validator\ClassBasedInterface;
|
|||||||
use Symfony\Component\Validator\ConstraintViolationList;
|
use Symfony\Component\Validator\ConstraintViolationList;
|
||||||
use Symfony\Component\Validator\Group\GroupManagerInterface;
|
use Symfony\Component\Validator\Group\GroupManagerInterface;
|
||||||
use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
|
use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
|
||||||
use Symfony\Component\Validator\MetadataFactoryInterface;
|
|
||||||
use Symfony\Component\Validator\Node\Node;
|
use Symfony\Component\Validator\Node\Node;
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
|
||||||
@ -39,11 +38,6 @@ class ExecutionContext implements ExecutionContextInterface
|
|||||||
*/
|
*/
|
||||||
private $nodeStack;
|
private $nodeStack;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var MetadataFactoryInterface
|
|
||||||
*/
|
|
||||||
private $metadataFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ValidatorInterface
|
* @var ValidatorInterface
|
||||||
*/
|
*/
|
||||||
@ -54,9 +48,8 @@ class ExecutionContext implements ExecutionContextInterface
|
|||||||
*/
|
*/
|
||||||
private $groupManager;
|
private $groupManager;
|
||||||
|
|
||||||
public function __construct(MetadataFactoryInterface $metadataFactory, ValidatorInterface $validator, GroupManagerInterface $groupManager)
|
public function __construct(ValidatorInterface $validator, GroupManagerInterface $groupManager)
|
||||||
{
|
{
|
||||||
$this->metadataFactory = $metadataFactory;
|
|
||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
$this->groupManager = $groupManager;
|
$this->groupManager = $groupManager;
|
||||||
$this->violations = new ConstraintViolationList();
|
$this->violations = new ConstraintViolationList();
|
||||||
@ -105,11 +98,6 @@ class ExecutionContext implements ExecutionContextInterface
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMetadataFor($object)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getViolations()
|
public function getViolations()
|
||||||
{
|
{
|
||||||
return $this->violations;
|
return $this->violations;
|
||||||
|
@ -88,8 +88,6 @@ interface ExecutionContextInterface
|
|||||||
*/
|
*/
|
||||||
public function getMetadata();
|
public function getMetadata();
|
||||||
|
|
||||||
public function getMetadataFor($object);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the validation group that is currently being validated.
|
* Returns the validation group that is currently being validated.
|
||||||
*
|
*
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
namespace Symfony\Component\Validator\Context;
|
namespace Symfony\Component\Validator\Context;
|
||||||
|
|
||||||
use Symfony\Component\Validator\Group\GroupManagerInterface;
|
use Symfony\Component\Validator\Group\GroupManagerInterface;
|
||||||
use Symfony\Component\Validator\MetadataFactoryInterface;
|
|
||||||
use Symfony\Component\Validator\Node\Node;
|
use Symfony\Component\Validator\Node\Node;
|
||||||
use Symfony\Component\Validator\NodeTraverser\AbstractVisitor;
|
use Symfony\Component\Validator\NodeTraverser\AbstractVisitor;
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
@ -23,11 +22,6 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|||||||
*/
|
*/
|
||||||
class ExecutionContextManager extends AbstractVisitor implements ExecutionContextManagerInterface
|
class ExecutionContextManager extends AbstractVisitor implements ExecutionContextManagerInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var MetadataFactoryInterface
|
|
||||||
*/
|
|
||||||
private $metadataFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var GroupManagerInterface
|
* @var GroupManagerInterface
|
||||||
*/
|
*/
|
||||||
@ -48,9 +42,8 @@ class ExecutionContextManager extends AbstractVisitor implements ExecutionContex
|
|||||||
*/
|
*/
|
||||||
private $contextStack;
|
private $contextStack;
|
||||||
|
|
||||||
public function __construct(MetadataFactoryInterface $metadataFactory, GroupManagerInterface $groupManager)
|
public function __construct(GroupManagerInterface $groupManager)
|
||||||
{
|
{
|
||||||
$this->metadataFactory = $metadataFactory;
|
|
||||||
$this->groupManager = $groupManager;
|
$this->groupManager = $groupManager;
|
||||||
|
|
||||||
$this->reset();
|
$this->reset();
|
||||||
@ -67,7 +60,7 @@ class ExecutionContextManager extends AbstractVisitor implements ExecutionContex
|
|||||||
$this->contextStack->push($this->currentContext);
|
$this->contextStack->push($this->currentContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->currentContext = new ExecutionContext($this->metadataFactory, $this->validator, $this->groupManager);
|
$this->currentContext = new ExecutionContext($this->validator, $this->groupManager);
|
||||||
|
|
||||||
return $this->currentContext;
|
return $this->currentContext;
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,10 @@
|
|||||||
namespace Symfony\Component\Validator\NodeTraverser;
|
namespace Symfony\Component\Validator\NodeTraverser;
|
||||||
|
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextManagerInterface;
|
|
||||||
use Symfony\Component\Validator\MetadataFactoryInterface;
|
use Symfony\Component\Validator\MetadataFactoryInterface;
|
||||||
|
use Symfony\Component\Validator\Node\ClassNode;
|
||||||
|
use Symfony\Component\Validator\Node\Node;
|
||||||
|
use Symfony\Component\Validator\Node\PropertyNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since %%NextVersion%%
|
* @since %%NextVersion%%
|
||||||
|
@ -25,8 +25,6 @@ interface NodeTraverserInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Node[] $nodes
|
* @param Node[] $nodes
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
*/
|
||||||
public function traverse(array $nodes);
|
public function traverse(array $nodes);
|
||||||
}
|
}
|
||||||
|
@ -15,23 +15,27 @@ use Symfony\Component\Validator\Context\ExecutionContextManager;
|
|||||||
use Symfony\Component\Validator\MetadataFactoryInterface;
|
use Symfony\Component\Validator\MetadataFactoryInterface;
|
||||||
use Symfony\Component\Validator\Tests\AbstractValidatorTest;
|
use Symfony\Component\Validator\Tests\AbstractValidatorTest;
|
||||||
use Symfony\Component\Validator\NodeTraverser\NodeTraverser;
|
use Symfony\Component\Validator\NodeTraverser\NodeTraverser;
|
||||||
use Symfony\Component\Validator\NodeTraverser\NodeVisitor\NodeValidator;
|
|
||||||
use Symfony\Component\Validator\DefaultTranslator;
|
use Symfony\Component\Validator\DefaultTranslator;
|
||||||
use Symfony\Component\Validator\ConstraintValidatorFactory;
|
use Symfony\Component\Validator\ConstraintValidatorFactory;
|
||||||
|
use Symfony\Component\Validator\Validator\NodeValidator;
|
||||||
use Symfony\Component\Validator\Validator\Validator;
|
use Symfony\Component\Validator\Validator\Validator;
|
||||||
|
|
||||||
class TraversingValidatorTest extends AbstractValidatorTest
|
class TraversingValidatorTest extends AbstractValidatorTest
|
||||||
{
|
{
|
||||||
protected function createValidator(MetadataFactoryInterface $metadataFactory)
|
protected function createValidator(MetadataFactoryInterface $metadataFactory)
|
||||||
{
|
{
|
||||||
$validatorFactory = new ConstraintValidatorFactory();
|
|
||||||
$nodeTraverser = new NodeTraverser($metadataFactory);
|
$nodeTraverser = new NodeTraverser($metadataFactory);
|
||||||
$nodeValidator = new NodeValidator($validatorFactory, $nodeTraverser);
|
$nodeValidator = new NodeValidator($nodeTraverser, new ConstraintValidatorFactory());
|
||||||
$contextManager = new ExecutionContextManager($metadataFactory, $nodeValidator, new DefaultTranslator());
|
$contextManager = new ExecutionContextManager($nodeValidator, new DefaultTranslator());
|
||||||
$validator = new Validator($nodeTraverser, $metadataFactory, $contextManager);
|
$validator = new Validator($nodeTraverser, $metadataFactory, $contextManager);
|
||||||
|
|
||||||
|
// The context manager needs the validator for passing it to created
|
||||||
|
// contexts
|
||||||
$contextManager->initialize($validator);
|
$contextManager->initialize($validator);
|
||||||
$nodeValidator->setContextManager($contextManager);
|
|
||||||
|
// The node validator needs the context manager for passing the current
|
||||||
|
// context to the constraint validators
|
||||||
|
$nodeValidator->initialize($contextManager);
|
||||||
|
|
||||||
$nodeTraverser->addVisitor($contextManager);
|
$nodeTraverser->addVisitor($contextManager);
|
||||||
$nodeTraverser->addVisitor($nodeValidator);
|
$nodeTraverser->addVisitor($nodeValidator);
|
||||||
|
@ -16,10 +16,10 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
|||||||
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
|
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
|
||||||
use Symfony\Component\Validator\Mapping\ValueMetadata;
|
use Symfony\Component\Validator\Mapping\ValueMetadata;
|
||||||
use Symfony\Component\Validator\MetadataFactoryInterface;
|
use Symfony\Component\Validator\MetadataFactoryInterface;
|
||||||
use Symfony\Component\Validator\NodeTraverser\ClassNode;
|
use Symfony\Component\Validator\Node\ClassNode;
|
||||||
|
use Symfony\Component\Validator\Node\PropertyNode;
|
||||||
|
use Symfony\Component\Validator\Node\ValueNode;
|
||||||
use Symfony\Component\Validator\NodeTraverser\NodeTraverserInterface;
|
use Symfony\Component\Validator\NodeTraverser\NodeTraverserInterface;
|
||||||
use Symfony\Component\Validator\NodeTraverser\PropertyNode;
|
|
||||||
use Symfony\Component\Validator\NodeTraverser\ValueNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since %%NextVersion%%
|
* @since %%NextVersion%%
|
||||||
@ -60,9 +60,14 @@ abstract class AbstractValidator implements ValidatorInterface
|
|||||||
return new ContextualValidator($this->nodeTraverser, $this->metadataFactory, $context);
|
return new ContextualValidator($this->nodeTraverser, $this->metadataFactory, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMetadataFactory()
|
public function getMetadataFor($object)
|
||||||
{
|
{
|
||||||
return $this->metadataFactory;
|
return $this->metadataFactory->getMetadataFor($object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasMetadataFor($object)
|
||||||
|
{
|
||||||
|
return $this->metadataFactory->hasMetadataFor($object);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function traverseObject($object, $groups = null)
|
protected function traverseObject($object, $groups = null)
|
||||||
|
@ -26,7 +26,7 @@ use Symfony\Component\Validator\NodeTraverser\NodeTraverserInterface;
|
|||||||
*/
|
*/
|
||||||
class NodeValidator extends AbstractVisitor implements GroupManagerInterface
|
class NodeValidator extends AbstractVisitor implements GroupManagerInterface
|
||||||
{
|
{
|
||||||
private $validatedNodes = array();
|
private $validatedObjects = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ConstraintValidatorFactoryInterface
|
* @var ConstraintValidatorFactoryInterface
|
||||||
@ -45,25 +45,25 @@ class NodeValidator extends AbstractVisitor implements GroupManagerInterface
|
|||||||
|
|
||||||
private $currentGroup;
|
private $currentGroup;
|
||||||
|
|
||||||
public function __construct(ConstraintValidatorFactoryInterface $validatorFactory, NodeTraverserInterface $nodeTraverser)
|
public function __construct(NodeTraverserInterface $nodeTraverser, ConstraintValidatorFactoryInterface $validatorFactory)
|
||||||
{
|
{
|
||||||
$this->validatorFactory = $validatorFactory;
|
$this->validatorFactory = $validatorFactory;
|
||||||
$this->nodeTraverser = $nodeTraverser;
|
$this->nodeTraverser = $nodeTraverser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setContextManager(ExecutionContextManagerInterface $contextManager)
|
public function initialize(ExecutionContextManagerInterface $contextManager)
|
||||||
{
|
{
|
||||||
$this->contextManager = $contextManager;
|
$this->contextManager = $contextManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function afterTraversal(array $nodes)
|
public function afterTraversal(array $nodes)
|
||||||
{
|
{
|
||||||
$this->validatedNodes = array();
|
$this->validatedObjects = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function enterNode(Node $node)
|
public function enterNode(Node $node)
|
||||||
{
|
{
|
||||||
$cacheKey = $node instanceof ClassNode
|
$objectHash = $node instanceof ClassNode
|
||||||
? spl_object_hash($node->value)
|
? spl_object_hash($node->value)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@ -75,30 +75,51 @@ class NodeValidator extends AbstractVisitor implements GroupManagerInterface
|
|||||||
|
|
||||||
foreach ($node->groups as $group) {
|
foreach ($node->groups as $group) {
|
||||||
// Validate object nodes only once per group
|
// Validate object nodes only once per group
|
||||||
if (null !== $cacheKey) {
|
if (null !== $objectHash) {
|
||||||
// Use the object hash for group sequences
|
// Use the object hash for group sequences
|
||||||
$groupKey = is_object($group) ? spl_object_hash($group) : $group;
|
$groupHash = is_object($group) ? spl_object_hash($group) : $group;
|
||||||
|
|
||||||
// Exit, if the object is already validated for the current group
|
// Exit, if the object is already validated for the current group
|
||||||
if (isset($this->validatedNodes[$cacheKey][$groupKey])) {
|
if (isset($this->validatedObjects[$objectHash][$groupHash])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember validating this object before starting and possibly
|
// Remember validating this object before starting and possibly
|
||||||
// traversing the object graph
|
// traversing the object graph
|
||||||
$this->validatedNodes[$cacheKey][$groupKey] = true;
|
$this->validatedObjects[$objectHash][$groupHash] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate group sequence until a violation is generated
|
// Validate group sequence until a violation is generated
|
||||||
if ($group instanceof GroupSequence) {
|
if (!$group instanceof GroupSequence) {
|
||||||
// Rename for clarity
|
$this->validateNodeForGroup($node, $group);
|
||||||
$groupSequence = $group;
|
|
||||||
|
|
||||||
// Only evaluate group sequences at class, not at property level
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only traverse group sequences at class, not at property level
|
||||||
if (!$node instanceof ClassNode) {
|
if (!$node instanceof ClassNode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->traverseGroupSequence($node, $group);
|
||||||
|
|
||||||
|
// Optimization: If the groups only contain the group sequence,
|
||||||
|
// we can skip the traversal for the properties of the object
|
||||||
|
if (1 === count($node->groups)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurrentGroup()
|
||||||
|
{
|
||||||
|
return $this->currentGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function traverseGroupSequence(ClassNode $node, GroupSequence $groupSequence)
|
||||||
|
{
|
||||||
$context = $this->contextManager->getCurrentContext();
|
$context = $this->contextManager->getCurrentContext();
|
||||||
$violationCount = count($context->getViolations());
|
$violationCount = count($context->getViolations());
|
||||||
|
|
||||||
@ -116,18 +137,16 @@ class NodeValidator extends AbstractVisitor implements GroupManagerInterface
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization: If the groups only contain the group sequence,
|
|
||||||
// we can skip the traversal for the properties of the object
|
|
||||||
if (1 === count($node->groups)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're done for the current loop execution.
|
/**
|
||||||
continue;
|
* @param Node $node
|
||||||
}
|
* @param $group
|
||||||
|
*
|
||||||
// Validate normal group (non group sequences)
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
private function validateNodeForGroup(Node $node, $group)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
$this->currentGroup = $group;
|
$this->currentGroup = $group;
|
||||||
|
|
||||||
@ -144,12 +163,4 @@ class NodeValidator extends AbstractVisitor implements GroupManagerInterface
|
|||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCurrentGroup()
|
|
||||||
{
|
|
||||||
return $this->currentGroup;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -85,4 +85,8 @@ interface ValidatorInterface
|
|||||||
* @return ContextualValidatorInterface
|
* @return ContextualValidatorInterface
|
||||||
*/
|
*/
|
||||||
public function inContext(ExecutionContextInterface $context);
|
public function inContext(ExecutionContextInterface $context);
|
||||||
|
|
||||||
|
public function getMetadataFor($object);
|
||||||
|
|
||||||
|
public function hasMetadataFor($object);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user