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

Skip to content

Commit 01ceeda

Browse files
committed
[Validator] Improved test coverage of the Traverse constraint
1 parent 9ca61df commit 01ceeda

File tree

7 files changed

+214
-45
lines changed

7 files changed

+214
-45
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ class Traverse extends Constraint
2424
{
2525
public $traverse = true;
2626

27-
public $deep = false;
28-
2927
public function __construct($options = null)
3028
{
3129
if (is_array($options) && array_key_exists('groups', $options)) {

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class Valid extends Constraint
2525
{
2626
public $traverse = true;
2727

28+
/**
29+
* @deprecated Deprecated as of version 2.5, to be removed in Symfony 3.0.
30+
*/
2831
public $deep = true;
2932

3033
public function __construct($options = null)
@@ -38,11 +41,4 @@ public function __construct($options = null)
3841

3942
parent::__construct($options);
4043
}
41-
42-
public function getDefaultOption()
43-
{
44-
// Traverse is extended for backwards compatibility reasons
45-
// The parent class should be removed in 3.0
46-
return null;
47-
}
4844
}

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

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,8 @@ public function addViolationAt($subPath, $message, array $parameters = array(),
111111
public function validate($value, $subPath = '', $groups = null, $traverse = false, $deep = false)
112112
{
113113
if (is_array($value)) {
114-
$constraint = new Traverse(array(
115-
'traverse' => true,
116-
'deep' => $deep,
117-
));
114+
// The $traverse flag is ignored for arrays
115+
$constraint = new Valid(array('traverse' => true, 'deep' => $deep));
118116

119117
return $this
120118
->getValidator()
@@ -125,16 +123,13 @@ public function validate($value, $subPath = '', $groups = null, $traverse = fals
125123
}
126124

127125
if ($traverse && $value instanceof \Traversable) {
128-
$constraints = array(
129-
new Valid(),
130-
new Traverse(array('traverse' => true, 'deep' => $deep)),
131-
);
126+
$constraint = new Valid(array('traverse' => true, 'deep' => $deep));
132127

133128
return $this
134129
->getValidator()
135130
->inContext($this)
136131
->atPath($subPath)
137-
->validate($value, $constraints, $groups)
132+
->validate($value, $constraint, $groups)
138133
;
139134
}
140135

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,20 +201,12 @@ public function addConstraint(Constraint $constraint)
201201
}
202202

203203
if ($constraint instanceof Traverse) {
204-
if (true === $constraint->traverse) {
204+
if ($constraint->traverse) {
205205
// If traverse is true, traversal should be explicitly enabled
206206
$this->traversalStrategy = TraversalStrategy::TRAVERSE;
207-
208-
if (!$constraint->deep) {
209-
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
210-
}
211-
} elseif (false === $constraint->traverse) {
207+
} else {
212208
// If traverse is false, traversal should be explicitly disabled
213209
$this->traversalStrategy = TraversalStrategy::NONE;
214-
} else {
215-
// Else, traverse depending on the contextual information that
216-
// is available during validation
217-
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
218210
}
219211

220212
// The constraint is not added

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

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

1414
use Symfony\Component\Validator\Constraint;
15+
use Symfony\Component\Validator\Constraints\Traverse;
1516
use Symfony\Component\Validator\Constraints\Valid;
1617
use Symfony\Component\Validator\Exception\BadMethodCallException;
18+
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
1719
use Symfony\Component\Validator\ValidationVisitorInterface;
1820

1921
/**
@@ -103,9 +105,20 @@ public function __clone()
103105
* @param Constraint $constraint The constraint to add
104106
*
105107
* @return GenericMetadata This object
108+
*
109+
* @throws ConstraintDefinitionException When trying to add the
110+
* {@link Traverse} constraint
106111
*/
107112
public function addConstraint(Constraint $constraint)
108113
{
114+
if ($constraint instanceof Traverse) {
115+
throw new ConstraintDefinitionException(sprintf(
116+
'The constraint "%s" can only be put on classes. Please use '.
117+
'"Symfony\Component\Validator\Constraints\Valid" instead.',
118+
get_class($constraint)
119+
));
120+
}
121+
109122
if ($constraint instanceof Valid) {
110123
$this->cascadingStrategy = CascadingStrategy::CASCADE;
111124

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,6 @@ public function addConstraint(Constraint $constraint)
5858
));
5959
}
6060

61-
// BC with Symfony < 2.5
62-
if ($constraint instanceof Valid) {
63-
if (true === $constraint->traverse) {
64-
// Try to traverse cascaded objects, but ignore if they do not
65-
// implement Traversable
66-
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
67-
68-
if (!$constraint->deep) {
69-
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
70-
}
71-
} elseif (false === $constraint->traverse) {
72-
$this->traversalStrategy = TraversalStrategy::NONE;
73-
}
74-
}
75-
7661
parent::addConstraint($constraint);
7762

7863
return $this;

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

Lines changed: 192 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,18 +328,208 @@ public function testTraverseTraversableByDefault()
328328
$this->assertNull($violations[0]->getCode());
329329
}
330330

331+
public function testTraversalEnabledOnClass()
332+
{
333+
$entity = new Entity();
334+
$traversable = new \ArrayIterator(array('key' => $entity));
335+
336+
$callback = function ($value, ExecutionContextInterface $context) {
337+
$context->addViolation('Message');
338+
};
339+
340+
$traversableMetadata = new ClassMetadata('ArrayIterator');
341+
$traversableMetadata->addConstraint(new Traverse(true));
342+
343+
$this->metadataFactory->addMetadata($traversableMetadata);
344+
$this->metadata->addConstraint(new Callback(array(
345+
'callback' => $callback,
346+
'groups' => 'Group',
347+
)));
348+
349+
$violations = $this->validate($traversable, new Valid(), 'Group');
350+
351+
/** @var ConstraintViolationInterface[] $violations */
352+
$this->assertCount(1, $violations);
353+
}
354+
355+
public function testTraversalDisabledOnClass()
356+
{
357+
$test = $this;
358+
$entity = new Entity();
359+
$traversable = new \ArrayIterator(array('key' => $entity));
360+
361+
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
362+
$test->fail('Should not be called');
363+
};
364+
365+
$traversableMetadata = new ClassMetadata('ArrayIterator');
366+
$traversableMetadata->addConstraint(new Traverse(false));
367+
368+
$this->metadataFactory->addMetadata($traversableMetadata);
369+
$this->metadata->addConstraint(new Callback(array(
370+
'callback' => $callback,
371+
'groups' => 'Group',
372+
)));
373+
374+
$violations = $this->validate($traversable, new Valid(), 'Group');
375+
376+
/** @var ConstraintViolationInterface[] $violations */
377+
$this->assertCount(0, $violations);
378+
}
379+
331380
/**
332381
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
333382
*/
334-
public function testExpectTraversableIfTraverseOnClass()
383+
public function testExpectTraversableIfTraversalEnabledOnClass()
335384
{
336385
$entity = new Entity();
337386

338-
$this->metadata->addConstraint(new Traverse());
387+
$this->metadata->addConstraint(new Traverse(true));
339388

340389
$this->validator->validate($entity);
341390
}
342391

392+
public function testReferenceTraversalDisabledOnClass()
393+
{
394+
$test = $this;
395+
$entity = new Entity();
396+
$entity->reference = new \ArrayIterator(array('key' => new Reference()));
397+
398+
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
399+
$test->fail('Should not be called');
400+
};
401+
402+
$traversableMetadata = new ClassMetadata('ArrayIterator');
403+
$traversableMetadata->addConstraint(new Traverse(false));
404+
405+
$this->metadataFactory->addMetadata($traversableMetadata);
406+
$this->referenceMetadata->addConstraint(new Callback(array(
407+
'callback' => $callback,
408+
'groups' => 'Group',
409+
)));
410+
$this->metadata->addPropertyConstraint('reference', new Valid());
411+
412+
$violations = $this->validate($entity, new Valid(), 'Group');
413+
414+
/** @var ConstraintViolationInterface[] $violations */
415+
$this->assertCount(0, $violations);
416+
}
417+
418+
public function testReferenceTraversalEnabledOnReferenceDisabledOnClass()
419+
{
420+
$test = $this;
421+
$entity = new Entity();
422+
$entity->reference = new \ArrayIterator(array('key' => new Reference()));
423+
424+
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
425+
$test->fail('Should not be called');
426+
};
427+
428+
$traversableMetadata = new ClassMetadata('ArrayIterator');
429+
$traversableMetadata->addConstraint(new Traverse(false));
430+
431+
$this->metadataFactory->addMetadata($traversableMetadata);
432+
$this->referenceMetadata->addConstraint(new Callback(array(
433+
'callback' => $callback,
434+
'groups' => 'Group',
435+
)));
436+
$this->metadata->addPropertyConstraint('reference', new Valid(array(
437+
'traverse' => true,
438+
)));
439+
440+
$violations = $this->validate($entity, new Valid(), 'Group');
441+
442+
/** @var ConstraintViolationInterface[] $violations */
443+
$this->assertCount(0, $violations);
444+
}
445+
446+
public function testReferenceTraversalDisabledOnReferenceEnabledOnClass()
447+
{
448+
$test = $this;
449+
$entity = new Entity();
450+
$entity->reference = new \ArrayIterator(array('key' => new Reference()));
451+
452+
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
453+
$test->fail('Should not be called');
454+
};
455+
456+
$traversableMetadata = new ClassMetadata('ArrayIterator');
457+
$traversableMetadata->addConstraint(new Traverse(true));
458+
459+
$this->metadataFactory->addMetadata($traversableMetadata);
460+
$this->referenceMetadata->addConstraint(new Callback(array(
461+
'callback' => $callback,
462+
'groups' => 'Group',
463+
)));
464+
$this->metadata->addPropertyConstraint('reference', new Valid(array(
465+
'traverse' => false,
466+
)));
467+
468+
$violations = $this->validate($entity, new Valid(), 'Group');
469+
470+
/** @var ConstraintViolationInterface[] $violations */
471+
$this->assertCount(0, $violations);
472+
}
473+
474+
public function testReferenceTraversalRecursionEnabledOnReferenceTraversalEnabledOnClass()
475+
{
476+
$entity = new Entity();
477+
$entity->reference = new \ArrayIterator(array(
478+
2 => new \ArrayIterator(array('key' => new Reference())),
479+
));
480+
481+
$callback = function ($value, ExecutionContextInterface $context) {
482+
$context->addViolation('Message');
483+
};
484+
485+
$traversableMetadata = new ClassMetadata('ArrayIterator');
486+
$traversableMetadata->addConstraint(new Traverse(true));
487+
488+
$this->metadataFactory->addMetadata($traversableMetadata);
489+
$this->referenceMetadata->addConstraint(new Callback(array(
490+
'callback' => $callback,
491+
'groups' => 'Group',
492+
)));
493+
$this->metadata->addPropertyConstraint('reference', new Valid(array(
494+
'deep' => true,
495+
)));
496+
497+
$violations = $this->validate($entity, new Valid(), 'Group');
498+
499+
/** @var ConstraintViolationInterface[] $violations */
500+
$this->assertCount(1, $violations);
501+
}
502+
503+
public function testReferenceTraversalRecursionDisabledOnReferenceTraversalEnabledOnClass()
504+
{
505+
$test = $this;
506+
$entity = new Entity();
507+
$entity->reference = new \ArrayIterator(array(
508+
2 => new \ArrayIterator(array('key' => new Reference())),
509+
));
510+
511+
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
512+
$test->fail('Should not be called');
513+
};
514+
515+
$traversableMetadata = new ClassMetadata('ArrayIterator');
516+
$traversableMetadata->addConstraint(new Traverse(true));
517+
518+
$this->metadataFactory->addMetadata($traversableMetadata);
519+
$this->referenceMetadata->addConstraint(new Callback(array(
520+
'callback' => $callback,
521+
'groups' => 'Group',
522+
)));
523+
$this->metadata->addPropertyConstraint('reference', new Valid(array(
524+
'deep' => false,
525+
)));
526+
527+
$violations = $this->validate($entity, new Valid(), 'Group');
528+
529+
/** @var ConstraintViolationInterface[] $violations */
530+
$this->assertCount(0, $violations);
531+
}
532+
343533
public function testAddCustomizedViolation()
344534
{
345535
$entity = new Entity();

0 commit comments

Comments
 (0)