Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 51197f6

Browse files
committed
[Validator] Made traversal of Traversables consistent
If the traversal strategy is IMPLICIT (the default), the validator will now traverse any object that implements \Traversable and any array
1 parent 117b1b9 commit 51197f6

21 files changed

+244
-228
lines changed

src/Symfony/Component/Validator/Constraints/Traverse.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ public function getDefaultOption()
5151
*/
5252
public function getTargets()
5353
{
54-
return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT);
54+
return self::CLASS_CONSTRAINT;
5555
}
5656
}

src/Symfony/Component/Validator/Constraints/Valid.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,8 @@
2323
*/
2424
class Valid extends Constraint
2525
{
26-
/**
27-
* @deprecated Deprecated since version 2.5, to be removed in Symfony 3.0.
28-
* Use the {@link Traverse} constraint instead.
29-
*/
3026
public $traverse = true;
3127

32-
/**
33-
* @deprecated Deprecated since version 2.5, to be removed in Symfony 3.0.
34-
* Use the {@link Traverse} constraint instead.
35-
*/
3628
public $deep = false;
3729

3830
public function __construct($options = null)

src/Symfony/Component/Validator/Mapping/ClassMetadata.php

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

1414
use Symfony\Component\Validator\Constraints\GroupSequence;
15+
use Symfony\Component\Validator\Constraints\Traverse;
1516
use Symfony\Component\Validator\Constraints\Valid;
1617
use Symfony\Component\Validator\ValidationVisitorInterface;
1718
use Symfony\Component\Validator\PropertyMetadataContainerInterface;
@@ -190,6 +191,27 @@ public function addConstraint(Constraint $constraint)
190191
));
191192
}
192193

194+
if ($constraint instanceof Traverse) {
195+
if (true === $constraint->traverse) {
196+
// If traverse is true, traversal should be explicitly enabled
197+
$this->traversalStrategy = TraversalStrategy::TRAVERSE;
198+
199+
if (!$constraint->deep) {
200+
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
201+
}
202+
} elseif (false === $constraint->traverse) {
203+
// If traverse is false, traversal should be explicitly disabled
204+
$this->traversalStrategy = TraversalStrategy::NONE;
205+
} else {
206+
// Else, traverse depending on the contextual information that
207+
// is available during validation
208+
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
209+
}
210+
211+
// The constraint is not added
212+
return $this;
213+
}
214+
193215
$constraint->addImplicitGroupName($this->getDefaultGroup());
194216

195217
parent::addConstraint($constraint);

src/Symfony/Component/Validator/Mapping/CollectionMetadata.php

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/Symfony/Component/Validator/Mapping/GenericMetadata.php

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,17 @@ public function addConstraint(Constraint $constraint)
7777
if ($constraint instanceof Valid) {
7878
$this->cascadingStrategy = CascadingStrategy::CASCADE;
7979

80-
return $this;
81-
}
82-
83-
if ($constraint instanceof Traverse) {
84-
if (true === $constraint->traverse) {
85-
// If traverse is true, traversal should be explicitly enabled
86-
$this->traversalStrategy = TraversalStrategy::TRAVERSE;
80+
if ($constraint->traverse) {
81+
// Traverse unless the value is not traversable
82+
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
8783

88-
if ($constraint->deep) {
89-
$this->traversalStrategy |= TraversalStrategy::RECURSIVE;
84+
if (!$constraint->deep) {
85+
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
9086
}
91-
} elseif (false === $constraint->traverse) {
92-
// If traverse is false, traversal should be explicitly disabled
93-
$this->traversalStrategy = TraversalStrategy::NONE;
9487
} else {
95-
// Else, traverse depending on the contextual information that
96-
// is available during validation
97-
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
88+
$this->traversalStrategy = TraversalStrategy::NONE;
9889
}
9990

100-
// The constraint is not added
10191
return $this;
10292
}
10393

src/Symfony/Component/Validator/Mapping/MemberMetadata.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,14 @@ public function addConstraint(Constraint $constraint)
6060
}
6161

6262
// BC with Symfony < 2.5
63-
// Only process if the traversal strategy was not already set by the
64-
// Traverse constraint
65-
if ($constraint instanceof Valid && !$this->traversalStrategy) {
63+
if ($constraint instanceof Valid) {
6664
if (true === $constraint->traverse) {
6765
// Try to traverse cascaded objects, but ignore if they do not
6866
// implement Traversable
69-
$this->traversalStrategy = TraversalStrategy::TRAVERSE
70-
| TraversalStrategy::IGNORE_NON_TRAVERSABLE;
67+
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
7168

72-
if ($constraint->deep) {
73-
$this->traversalStrategy |= TraversalStrategy::RECURSIVE;
69+
if (!$constraint->deep) {
70+
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
7471
}
7572
} elseif (false === $constraint->traverse) {
7673
$this->traversalStrategy = TraversalStrategy::NONE;
@@ -180,7 +177,7 @@ public function isCascaded()
180177
*/
181178
public function isCollectionCascaded()
182179
{
183-
return (boolean) ($this->traversalStrategy & TraversalStrategy::TRAVERSE);
180+
return (boolean) ($this->traversalStrategy & (TraversalStrategy::IMPLICIT | TraversalStrategy::TRAVERSE));
184181
}
185182

186183
/**
@@ -191,7 +188,7 @@ public function isCollectionCascaded()
191188
*/
192189
public function isCollectionCascadedDeeply()
193190
{
194-
return (boolean) ($this->traversalStrategy & TraversalStrategy::RECURSIVE);
191+
return !($this->traversalStrategy & TraversalStrategy::STOP_RECURSION);
195192
}
196193

197194
/**

src/Symfony/Component/Validator/Mapping/TraversalStrategy.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@
1717
*/
1818
class TraversalStrategy
1919
{
20-
const IMPLICIT = 0;
20+
/**
21+
* @var integer
22+
*/
23+
const IMPLICIT = 1;
2124

22-
const NONE = 1;
25+
const NONE = 2;
2326

24-
const TRAVERSE = 2;
27+
const TRAVERSE = 4;
2528

26-
const RECURSIVE = 4;
27-
28-
const IGNORE_NON_TRAVERSABLE = 8;
29+
const STOP_RECURSION = 8;
2930

3031
private function __construct()
3132
{

src/Symfony/Component/Validator/Node/ClassNode.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
1515
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
16+
use Symfony\Component\Validator\Mapping\TraversalStrategy;
1617

1718
/**
1819
* Represents an object and its class metadata in the validation graph.
@@ -40,10 +41,11 @@ class ClassNode extends Node
4041
* @param string[]|null $cascadedGroups The groups in which
4142
* cascaded objects should be
4243
* validated
44+
* @param integer $traversalStrategy
4345
*
44-
* @throws UnexpectedTypeException If the given value is not an object
46+
* @throws \Symfony\Component\Validator\Exception\UnexpectedTypeException
4547
*/
46-
public function __construct($object, ClassMetadataInterface $metadata, $propertyPath, array $groups, $cascadedGroups = null)
48+
public function __construct($object, ClassMetadataInterface $metadata, $propertyPath, array $groups, $cascadedGroups = null, $traversalStrategy = TraversalStrategy::IMPLICIT)
4749
{
4850
if (!is_object($object)) {
4951
throw new UnexpectedTypeException($object, 'object');
@@ -56,5 +58,7 @@ public function __construct($object, ClassMetadataInterface $metadata, $property
5658
$groups,
5759
$cascadedGroups
5860
);
61+
62+
$this->traversalStrategy = $traversalStrategy;
5963
}
6064
}

src/Symfony/Component/Validator/Node/CollectionNode.php

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Component\Validator\Node;
1313

14+
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1415
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
1516
use Symfony\Component\Validator\Mapping\MetadataInterface;
17+
use Symfony\Component\Validator\Mapping\TraversalStrategy;
1618

1719
/**
1820
* Represents an traversable collection in the validation graph.
@@ -25,32 +27,35 @@ class CollectionNode extends Node
2527
/**
2628
* Creates a new collection node.
2729
*
28-
* @param array|\Traversable $collection The validated collection
29-
* @param MetadataInterface $metadata The class metadata of that
30-
* object
31-
* @param string $propertyPath The property path leading
30+
* @param array|\Traversable $collection The validated collection
31+
* @param string $propertyPath The property path leading
3232
* to this node
33-
* @param string[] $groups The groups in which this
33+
* @param string[] $groups The groups in which this
3434
* node should be validated
35-
* @param string[]|null $cascadedGroups The groups in which
35+
* @param string[]|null $cascadedGroups The groups in which
3636
* cascaded objects should be
3737
* validated
38+
* @param integer $traversalStrategy The traversal strategy
3839
*
39-
* @throws UnexpectedTypeException If the given value is not an array or
40-
* an instance of {@link \Traversable}
40+
* @throws \Symfony\Component\Validator\Exception\ConstraintDefinitionException
4141
*/
42-
public function __construct($collection, MetadataInterface $metadata, $propertyPath, array $groups, $cascadedGroups = null)
42+
public function __construct($collection, $propertyPath, array $groups, $cascadedGroups = null, $traversalStrategy = TraversalStrategy::TRAVERSE)
4343
{
4444
if (!is_array($collection) && !$collection instanceof \Traversable) {
45-
throw new UnexpectedTypeException($collection, 'object');
45+
throw new ConstraintDefinitionException(sprintf(
46+
'Traversal was enabled for "%s", but this class '.
47+
'does not implement "\Traversable".',
48+
get_class($collection)
49+
));
4650
}
4751

4852
parent::__construct(
4953
$collection,
50-
$metadata,
54+
null,
5155
$propertyPath,
5256
$groups,
53-
$cascadedGroups
57+
$cascadedGroups,
58+
$traversalStrategy
5459
);
5560
}
5661
}

src/Symfony/Component/Validator/Node/Node.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
1515
use Symfony\Component\Validator\Mapping\MetadataInterface;
16+
use Symfony\Component\Validator\Mapping\TraversalStrategy;
1617

1718
/**
1819
* A node in the validated graph.
@@ -32,7 +33,7 @@ abstract class Node
3233
/**
3334
* The metadata specifying how the value should be validated.
3435
*
35-
* @var MetadataInterface
36+
* @var MetadataInterface|null
3637
*/
3738
public $metadata;
3839

@@ -57,21 +58,27 @@ abstract class Node
5758
*/
5859
public $cascadedGroups;
5960

61+
/**
62+
* @var integer
63+
*/
64+
public $traversalStrategy;
65+
6066
/**
6167
* Creates a new property node.
6268
*
63-
* @param mixed $value The property value
64-
* @param MetadataInterface $metadata The property's metadata
65-
* @param string $propertyPath The property path leading to
66-
* this node
67-
* @param string[] $groups The groups in which this node
68-
* should be validated
69-
* @param string[]|null $cascadedGroups The groups in which cascaded
70-
* objects should be validated
69+
* @param mixed $value The property value
70+
* @param MetadataInterface|null $metadata The property's metadata
71+
* @param string $propertyPath The property path leading to
72+
* this node
73+
* @param string[] $groups The groups in which this node
74+
* should be validated
75+
* @param string[]|null $cascadedGroups The groups in which cascaded
76+
* objects should be validated
77+
* @param integer $traversalStrategy
7178
*
7279
* @throws UnexpectedTypeException If $cascadedGroups is invalid
7380
*/
74-
public function __construct($value, MetadataInterface $metadata, $propertyPath, array $groups, $cascadedGroups = null)
81+
public function __construct($value, MetadataInterface $metadata = null, $propertyPath, array $groups, $cascadedGroups = null, $traversalStrategy = TraversalStrategy::IMPLICIT)
7582
{
7683
if (null !== $cascadedGroups && !is_array($cascadedGroups)) {
7784
throw new UnexpectedTypeException($cascadedGroups, 'null or array');
@@ -82,5 +89,6 @@ public function __construct($value, MetadataInterface $metadata, $propertyPath,
8289
$this->propertyPath = $propertyPath;
8390
$this->groups = $groups;
8491
$this->cascadedGroups = $cascadedGroups;
92+
$this->traversalStrategy = $traversalStrategy;
8593
}
8694
}

src/Symfony/Component/Validator/Node/PropertyNode.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
1515
use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
16+
use Symfony\Component\Validator\Mapping\TraversalStrategy;
1617

1718
/**
1819
* Represents the value of a property and its associated metadata.
@@ -57,10 +58,11 @@ class PropertyNode extends Node
5758
* @param string[]|null $cascadedGroups The groups in which
5859
* cascaded objects should
5960
* be validated
61+
* @param integer $traversalStrategy
6062
*
6163
* @throws UnexpectedTypeException If $object is not an object
6264
*/
63-
public function __construct($object, $value, PropertyMetadataInterface $metadata, $propertyPath, array $groups, $cascadedGroups = null)
65+
public function __construct($object, $value, PropertyMetadataInterface $metadata, $propertyPath, array $groups, $cascadedGroups = null, $traversalStrategy = TraversalStrategy::IMPLICIT)
6466
{
6567
if (!is_object($object)) {
6668
throw new UnexpectedTypeException($object, 'object');
@@ -71,7 +73,8 @@ public function __construct($object, $value, PropertyMetadataInterface $metadata
7173
$metadata,
7274
$propertyPath,
7375
$groups,
74-
$cascadedGroups
76+
$cascadedGroups,
77+
$traversalStrategy
7578
);
7679

7780
$this->object = $object;

0 commit comments

Comments
 (0)