8000 [Validator] Decoupled the new classes a bit · symfony/symfony@a40189c · GitHub
[go: up one dir, main page]

Skip to content

Commit a40189c

Browse files
committed
[Validator] Decoupled the new classes a bit
1 parent a6ed4ca commit a40189c

9 files changed

+95
-92
lines changed

src/Symfony/Component/Validator/Context/ExecutionContext.php

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use Symfony\Component\Validator\ConstraintViolationList;
1616
use Symfony\Component\Validator\Group\GroupManagerInterface;
1717
use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
18-
use Symfony\Component\Validator\MetadataFactoryInterface;
1918
use Symfony\Component\Validator\Node\Node;
2019
use Symfony\Component\Validator\Validator\ValidatorInterface;
2120

@@ -39,11 +38,6 @@ class ExecutionContext implements ExecutionContextInterface
3938
*/
4039
private $nodeStack;
4140

42-
/**
43-
* @var MetadataFactoryInterface
44-
*/
45-
private $metadataFactory;
46-
4741
/**
4842
* @var ValidatorInterface
4943
*/
@@ -54,9 +48,8 @@ class ExecutionContext implements ExecutionContextInterface
5448
*/
5549
private $groupManager;
5650

57-
public function __construct(MetadataFactoryInterface $metadataFactory, ValidatorInterface $validator, GroupManagerInterface $groupManager)
51+
public function __construct(ValidatorInterface $validator, GroupManagerInterface $groupManager)
5852
{
59-
$this->metadataFactory = $metadataFactory;
6053
$this->validator = $validator;
6154
$this->groupManager = $groupManager;
6255
$this->violations = new ConstraintViolationList();
@@ -105,11 +98,6 @@ public function buildViolation($message)
10598

10699
}
107100

108-
public function getMetadataFor($object)
109-
{
110-
111-
}
112-
113101
public function getViolations()
114102
{
115103
return $this->violations;

src/Symfony/Component/Validator/Context/ExecutionContextInterface.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ public function getValue();
8888
*/
8989
public function getMetadata();
9090

91-
public function getMetadataFor($object);
92-
9391
/**
9492
* Returns the validation group that is currently being validated.
9593
*

src/Symfony/Component/Validator/Context/ExecutionContextManager.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\Validator\Context;
1313

1414
use Symfony\Component\Validator\Group\GroupManagerInterface;
15-
use Symfony\Component\Validator\MetadataFactoryInterface;
1615
use Symfony\Component\Validator\Node\Node;
1716
use Symfony\Component\Validator\NodeTraverser\AbstractVisitor;
1817
use Symfony\Component\Validator\Validator\ValidatorInterface;
@@ -23,11 +22,6 @@
2322
*/
2423
class ExecutionContextManager extends AbstractVisitor implements ExecutionContextManagerInterface
2524
{
26-
/**
27-
* @var MetadataFactoryInterface
28-
*/
29-
private $metadataFactory;
30-
3125
/**
3226
* @var GroupManagerInterface
3327
*/
@@ -48,9 +42,8 @@ class ExecutionContextManager extends AbstractVisitor implements ExecutionContex
4842
*/
4943
private $contextStack;
5044

51-
public function __construct(MetadataFactoryInterface $metadataFactory, GroupManagerInterface $groupManager)
45+
public function __construct(GroupManagerInterface $groupManager)
5246
{
53-
$this->metadataFactory = $metadataFactory;
5447
$this->groupManager = $groupManager;
5548

5649
$this->reset();
@@ -67,7 +60,7 @@ public function startContext()
6760
$this->contextStack->push($this->currentContext);
6861
}
6962

70-
$this->currentContext = new ExecutionContext($this->metadataFactory, $this->validator, $this->groupManager);
63+
$this->currentContext = new ExecutionContext($this->validator, $this->groupManager);
7164

7265
return $this->currentContext;
7366
}

src/Symfony/Component/Validator/NodeTraverser/NodeTraverser.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespace Symfony\Component\Validator\NodeTraverser;
1313

1414
use Symfony\Component\Validator\Constraint;
15-
use Symfony\Component\Validator\Context\ExecutionContextManagerInterface;
1615
use Symfony\Component\Validator\MetadataFactoryInterface;
16+
use Symfony\Component\Validator\Node\ClassNode;
17+
use Symfony\Component\Validator\Node\Node;
18+
use Symfony\Component\Validator\Node\PropertyNode;
1719

1820
/**
1921
* @since %%NextVersion%%

src/Symfony/Component/Validator/NodeTraverser/NodeTraverserInterface.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ public function removeVisitor(NodeVisitorInterface $visitor);
2525

2626
/**
2727
* @param Node[] $nodes
28-
*
29-
* @return mixed
3028
*/
3129
public function traverse(array $nodes);
3230
}

src/Symfony/Component/Validator/Tests/Validator/TraversingValidatorTest.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,27 @@
1515
use Symfony\Component\Validator\MetadataFactoryInterface;
1616
use Symfony\Component\Validator\Tests\AbstractValidatorTest;
1717
use Symfony\Component\Validator\NodeTraverser\NodeTraverser;
18-
use Symfony\Component\Validator\NodeTraverser\NodeVisitor\NodeValidator;
1918
use Symfony\Component\Validator\DefaultTranslator;
2019
use Symfony\Component\Validator\ConstraintValidatorFactory;
20+
use Symfony\Component\Validator\Validator\NodeValidator;
2121
use Symfony\Component\Validator\Validator\Validator;
2222

2323
class TraversingValidatorTest extends AbstractValidatorTest
2424
{
2525
protected function createValidator(MetadataFactoryInterface $metadataFactory)
2626
{
27-
$validatorFactory = new ConstraintValidatorFactory();
2827
$nodeTraverser = new NodeTraverser($metadataFactory);
29-
$nodeValidator = new NodeValidator($validatorFactory, $nodeTraverser);
30-
$contextManager = new ExecutionContextManager($metadataFactory, $nodeValidator, new DefaultTranslator());
28+
$nodeValidator = new NodeValidator($nodeTraverser, new ConstraintValidatorFactory());
29+
$contextManager = new ExecutionContextManager($nodeValidator, new DefaultTranslator());
3130
$validator = new Validator($nodeTraverser, $metadataFactory, $contextManager);
3231

32+
// The context manager needs the validator for passing it to created
33+
// contexts
3334
$contextManager->initialize($validator);
34-
$nodeValidator->setContextManager($contextManager);
35+
36+
// The node validator needs the context manager for passing the current
37+
// context to the constraint validators
38+
$nodeValidator->initialize($contextManager);
3539

3640
$nodeTraverser->addVisitor($contextManager);
3741
$nodeTraverser->addVisitor($nodeValidator);

src/Symfony/Component/Validator/Validator/AbstractValidator.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
1717
use Symfony\Component\Validator\Mapping\ValueMetadata;
1818
use Symfony\Component\Validator\MetadataFactoryInterface;
19-
use Symfony\Component\Validator\NodeTraverser\ClassNode;
19+
use Symfony\Component\Validator\Node\ClassNode;
20+
use Symfony\Component\Validator\Node\PropertyNode;
21+
use Symfony\Component\Validator\Node\ValueNode;
2022
use Symfony\Component\Validator\NodeTraverser\NodeTraverserInterface;
21-
use Symfony\Component\Validator\NodeTraverser\PropertyNode;
22-
use Symfony\Component\Validator\NodeTraverser\ValueNode;
2323

2424
/**
2525
* @since %%NextVersion%%
@@ -60,9 +60,14 @@ public function inContext(ExecutionContextInterface $context)
6060
return new ContextualValidator($this->nodeTraverser, $this->metadataFactory, $context);
6161
}
6262

63-
public function getMetadataFactory()
63+
public function getMetadataFor($object)
6464
{
65-
return $this->metadataFactory;
65+
return $this->metadataFactory->getMetadataFor($object);
66+
}
67+
68+
public function hasMetadataFor($object)
69+
{
70+
return $this->metadataFactory->hasMetadataFor($object);
6671
}
6772

6873
protected function traverseObject($object, $groups = null)

src/Symfony/Component/Validator/Validator/NodeValidator.php

Lines changed: 66 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*/
2727
class NodeValidator extends AbstractVisitor implements GroupManagerInterface
2828
{
29-
private $validatedNodes = array();
29+
private $validatedObjects = array();
3030

3131
/**
3232
* @var ConstraintValidatorFactoryInterface
@@ -45,25 +45,25 @@ class NodeValidator extends AbstractVisitor implements GroupManagerInterface
4545

4646
private $currentGroup;
4747

48-
public function __construct(ConstraintValidatorFactoryInterface $validatorFactory, NodeTraverserInterface $nodeTraverser)
48+
public function __construct(NodeTraverserInterface $nodeTraverser, ConstraintValidatorFactoryInterface $validatorFactory)
4949
{
5050
$this->validatorFactory = $validatorFactory;
5151
$this->nodeTraverser = $nodeTraverser;
5252
}
5353

54-
public function setContextManager(ExecutionContextManagerInterface $contextManager)
54+
public function initialize(ExecutionContextManagerInterface $contextManager)
5555
{
5656
$this->contextManager = $contextManager;
5757
}
5858

5959
public function afterTraversal(array $nodes)
6060
{
61-
$this->validatedNodes = array();
61+
$this->validatedObjects = array();
6262
}
6363

6464
public function enterNode(Node $node)
6565
{
66-
$cacheKey = $node instanceof ClassNode
66+
$objectHash = $node instanceof ClassNode
6767
? spl_object_hash($node->value)
6868
: null;
6969

@@ -75,73 +75,38 @@ public function enterNode(Node $node)
7575

7676
foreach ($node->groups as $group) {
7777
// Validate object nodes only once per group
78-
if (null !== $cacheKey) {
78+
if (null !== $objectHash) {
7979
// Use the object hash for group sequences
80-
$groupKey = is_object($group) ? spl_object_hash($group) : $group;
80+
$groupHash = is_object($group) ? spl_object_hash($group) : $group;
8181

8282
// Exit, if the object is already validated for the current group
83-
if (isset($this->validatedNodes[$cacheKey][$groupKey])) {
83+
if (isset($this->validatedObjects[$objectHash][$groupHash])) {
8484
return false;
8585
}
8686

8787
// Remember validating this object before starting and possibly
8888
// traversing the object graph
89-
$this->validatedNodes[$cacheKey][$groupKey] = true;
89+
$this->validatedObjects[$objectHash][$groupHash] = true;
9090
}
9191

9292
// Validate group sequence until a violation is generated
93-
if ($group instanceof GroupSequence) {
94-
// Rename for clarity
95-
$groupSequence = $group;
93+
if (!$group instanceof GroupSequence) {
94+
$this->validateNodeForGroup($node, $group);
9695

97-
// Only evaluate group sequences at class, not at property level
98-
if (!$node instanceof ClassNode) {
99-
continue;
100-
}
101-
102-
$context = $this->contextManager->getCurrentContext();
103-
$violationCount = count($context->getViolations());
104-
105-
foreach ($groupSequence->groups as $groupInSequence) {
106-
$this->nodeTraverser->traverse(array(new ClassNode(
107-
$node->value,
108-
$node->metadata,
109-
$node->propertyPath,
110-
array($groupInSequence),
111-
array($groupSequence->cascadedGroup ?: $groupInSequence)
112-
)));
113-
114-
// Abort sequence validation if a violation was generated
115-
if (count($context->getViolations()) > $violationCount) {
116-
break;
117-
}
118-
}
119-
120-
// Optimization: If the groups only contain the group sequence,
121-
// we can skip the traversal for the properties of the object
122-
if (1 === count($node->groups)) {
123-
return false;
124-
}
125-
126-
// We're done for the current loop execution.
12796
continue;
12897
}
12998

130-
// Validate normal group (non group sequences)
131-
try {
132-
$this->currentGroup = $group;
133-
134-
foreach ($node->metadata->findConstraints($group) as $constraint) {
135-
$validator = $this->validatorFactory->getInstance($constraint);
136-
$validator->initialize($this->contextManager->getCurrentContext());
137-
$validator->validate($node->value, $constraint);
138-
}
99+
// Only traverse group sequences at class, not at property level
100+
if (!$node instanceof ClassNode) {
101+
continue;
102+
}
139103

140-
$this->currentGroup = null;
141-
} catch (\Exception $e) {
142-
$this->currentGroup = null;
104+
$this->traverseGroupSequence($node, $group);
143105

144-
throw $e;
106+
// Optimization: If the groups only contain the group sequence,
107+
// we can skip the traversal for the properties of the object
108+
if (1 === count($node->groups)) {
109+
return false;
145110
}
146111
}
147112

@@ -152,4 +117,50 @@ public function getCurrentGroup()
152117
{
153118
return $this->currentGroup;
154119
}
120+
121+
private function traverseGroupSequence(ClassNode $node, GroupSequence $groupSequence)
122+
{
123+
$context = $this->contextManager->getCurrentContext();
124+
$violationCount = count($context->getViolations());
125+
126+
foreach ($groupSequence->groups as $groupInSequence) {
127+
$this->nodeTraverser->traverse(array(new ClassNode(
128+
$node->value,
129+
$node->metadata,
130+
$node->propertyPath,
131+
array($groupInSequence),
132+
array($groupSequence->cascadedGroup ?: $groupInSequence)
133+
)));
134+
135+
// Abort sequence validation if a violation was generated
< 10000 code>136+
if (count($context->getViolations()) > $violationCount) {
137+
break;
138+
}
139+
}
140+
}
141+
142+
/**
143+
* @param Node $node
144+
* @param $group
145+
*
146+
* @throws \Exception
147+
*/
148+
private function validateNodeForGroup(Node $node, $group)
149+
{
150+
try {
151+
$this->currentGroup = $group;
152+
153+
foreach ($node->metadata->findConstraints($group) as $constraint) {
154+
$validator = $this->validatorFactory->getInstance($constraint);
155+
$validator->initialize($this->contextManager->getCurrentContext());
156+
$validator->validate($node->value, $constraint);
157+
}
158+
159+
$this->currentGroup = null;
160+
} catch (\Exception $e) {
161+
$this->currentGroup = null;
162+
163+
throw $e;
164+
}
165+
}
155166
}

src/Symfony/Component/Validator/Validator/ValidatorInterface.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,8 @@ public function validateValue($value, $constraints, $groups = null);
8585
* @return ContextualValidatorInterface
8686
*/
8787
public function inContext(ExecutionContextInterface $context);
88+
89+
public function getMetadataFor($object);
90+
91+
public function hasMetadataFor($object);
8892
}

0 commit comments

Comments
 (0)
0