[Validator] Improved test coverage of the Traverse constraint
This commit is contained in:
parent
9ca61df923
commit
01ceeda376
|
@ -24,8 +24,6 @@ class Traverse extends Constraint
|
|||
{
|
||||
public $traverse = true;
|
||||
|
||||
public $deep = false;
|
||||
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if (is_array($options) && array_key_exists('groups', $options)) {
|
||||
|
|
|
@ -25,6 +25,9 @@ class Valid extends Constraint
|
|||
{
|
||||
public $traverse = true;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated as of version 2.5, to be removed in Symfony 3.0.
|
||||
*/
|
||||
public $deep = true;
|
||||
|
||||
public function __construct($options = null)
|
||||
|
@ -38,11 +41,4 @@ class Valid extends Constraint
|
|||
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
public function getDefaultOption()
|
||||
{
|
||||
// Traverse is extended for backwards compatibility reasons
|
||||
// The parent class should be removed in 3.0
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,10 +111,8 @@ class LegacyExecutionContext extends ExecutionContext
|
|||
public function validate($value, $subPath = '', $groups = null, $traverse = false, $deep = false)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$constraint = new Traverse(array(
|
||||
'traverse' => true,
|
||||
'deep' => $deep,
|
||||
));
|
||||
// The $traverse flag is ignored for arrays
|
||||
$constraint = new Valid(array('traverse' => true, 'deep' => $deep));
|
||||
|
||||
return $this
|
||||
->getValidator()
|
||||
|
@ -125,16 +123,13 @@ class LegacyExecutionContext extends ExecutionContext
|
|||
}
|
||||
|
||||
if ($traverse && $value instanceof \Traversable) {
|
||||
$constraints = array(
|
||||
new Valid(),
|
||||
new Traverse(array('traverse' => true, 'deep' => $deep)),
|
||||
);
|
||||
$constraint = new Valid(array('traverse' => true, 'deep' => $deep));
|
||||
|
||||
return $this
|
||||
->getValidator()
|
||||
->inContext($this)
|
||||
->atPath($subPath)
|
||||
->validate($value, $constraints, $groups)
|
||||
->validate($value, $constraint, $groups)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,20 +201,12 @@ class ClassMetadata extends ElementMetadata implements LegacyMetadataInterface,
|
|||
}
|
||||
|
||||
if ($constraint instanceof Traverse) {
|
||||
if (true === $constraint->traverse) {
|
||||
if ($constraint->traverse) {
|
||||
// If traverse is true, traversal should be explicitly enabled
|
||||
$this->traversalStrategy = TraversalStrategy::TRAVERSE;
|
||||
|
||||
if (!$constraint->deep) {
|
||||
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
|
||||
}
|
||||
} elseif (false === $constraint->traverse) {
|
||||
} else {
|
||||
// If traverse is false, traversal should be explicitly disabled
|
||||
$this->traversalStrategy = TraversalStrategy::NONE;
|
||||
} else {
|
||||
// Else, traverse depending on the contextual information that
|
||||
// is available during validation
|
||||
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
|
||||
}
|
||||
|
||||
// The constraint is not added
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
namespace Symfony\Component\Validator\Mapping;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Traverse;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\Exception\BadMethodCallException;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\ValidationVisitorInterface;
|
||||
|
||||
/**
|
||||
|
@ -103,9 +105,20 @@ class GenericMetadata implements MetadataInterface
|
|||
* @param Constraint $constraint The constraint to add
|
||||
*
|
||||
* @return GenericMetadata This object
|
||||
*
|
||||
* @throws ConstraintDefinitionException When trying to add the
|
||||
* {@link Traverse} constraint
|
||||
*/
|
||||
public function addConstraint(Constraint $constraint)
|
||||
{
|
||||
if ($constraint instanceof Traverse) {
|
||||
throw new ConstraintDefinitionException(sprintf(
|
||||
'The constraint "%s" can only be put on classes. Please use '.
|
||||
'"Symfony\Component\Validator\Constraints\Valid" instead.',
|
||||
get_class($constraint)
|
||||
));
|
||||
}
|
||||
|
||||
if ($constraint instanceof Valid) {
|
||||
$this->cascadingStrategy = CascadingStrategy::CASCADE;
|
||||
|
||||
|
|
|
@ -58,21 +58,6 @@ abstract class MemberMetadata extends ElementMetadata implements PropertyMetadat
|
|||
));
|
||||
}
|
||||
|
||||
// BC with Symfony < 2.5
|
||||
if ($constraint instanceof Valid) {
|
||||
if (true === $constraint->traverse) {
|
||||
// Try to traverse cascaded objects, but ignore if they do not
|
||||
// implement Traversable
|
||||
$this->traversalStrategy = TraversalStrategy::IMPLICIT;
|
||||
|
||||
if (!$constraint->deep) {
|
||||
$this->traversalStrategy |= TraversalStrategy::STOP_RECURSION;
|
||||
}
|
||||
} elseif (false === $constraint->traverse) {
|
||||
$this->traversalStrategy = TraversalStrategy::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
parent::addConstraint($constraint);
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -328,18 +328,208 @@ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest
|
|||
$this->assertNull($violations[0]->getCode());
|
||||
}
|
||||
|
||||
public function testTraversalEnabledOnClass()
|
||||
{
|
||||
$entity = new Entity();
|
||||
$traversable = new \ArrayIterator(array('key' => $entity));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) {
|
||||
$context->addViolation('Message');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(true));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->metadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
|
||||
$violations = $this->validate($traversable, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(1, $violations);
|
||||
}
|
||||
|
||||
public function testTraversalDisabledOnClass()
|
||||
{
|
||||
$test = $this;
|
||||
$entity = new Entity();
|
||||
$traversable = new \ArrayIterator(array('key' => $entity));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
|
||||
$test->fail('Should not be called');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(false));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->metadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
|
||||
$violations = $this->validate($traversable, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(0, $violations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
|
||||
*/
|
||||
public function testExpectTraversableIfTraverseOnClass()
|
||||
public function testExpectTraversableIfTraversalEnabledOnClass()
|
||||
{
|
||||
$entity = new Entity();
|
||||
|
||||
$this->metadata->addConstraint(new Traverse());
|
||||
$this->metadata->addConstraint(new Traverse(true));
|
||||
|
||||
$this->validator->validate($entity);
|
||||
}
|
||||
|
||||
public function testReferenceTraversalDisabledOnClass()
|
||||
{
|
||||
$test = $this;
|
||||
$entity = new Entity();
|
||||
$entity->reference = new \ArrayIterator(array('key' => new Reference()));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
|
||||
$test->fail('Should not be called');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(false));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->referenceMetadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
||||
|
||||
$violations = $this->validate($entity, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(0, $violations);
|
||||
}
|
||||
|
||||
public function testReferenceTraversalEnabledOnReferenceDisabledOnClass()
|
||||
{
|
||||
$test = $this;
|
||||
$entity = new Entity();
|
||||
$entity->reference = new \ArrayIterator(array('key' => new Reference()));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
|
||||
$test->fail('Should not be called');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(false));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->referenceMetadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid(array(
|
||||
'traverse' => true,
|
||||
)));
|
||||
|
||||
$violations = $this->validate($entity, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(0, $violations);
|
||||
}
|
||||
|
||||
public function testReferenceTraversalDisabledOnReferenceEnabledOnClass()
|
||||
{
|
||||
$test = $this;
|
||||
$entity = new Entity();
|
||||
$entity->reference = new \ArrayIterator(array('key' => new Reference()));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
|
||||
$test->fail('Should not be called');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(true));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->referenceMetadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid(array(
|
||||
'traverse' => false,
|
||||
)));
|
||||
|
||||
$violations = $this->validate($entity, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(0, $violations);
|
||||
}
|
||||
|
||||
public function testReferenceTraversalRecursionEnabledOnReferenceTraversalEnabledOnClass()
|
||||
{
|
||||
$entity = new Entity();
|
||||
$entity->reference = new \ArrayIterator(array(
|
||||
2 => new \ArrayIterator(array('key' => new Reference())),
|
||||
));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) {
|
||||
$context->addViolation('Message');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(true));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->referenceMetadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid(array(
|
||||
'deep' => true,
|
||||
)));
|
||||
|
||||
$violations = $this->validate($entity, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(1, $violations);
|
||||
}
|
||||
|
||||
public function testReferenceTraversalRecursionDisabledOnReferenceTraversalEnabledOnClass()
|
||||
{
|
||||
$test = $this;
|
||||
$entity = new Entity();
|
||||
$entity->reference = new \ArrayIterator(array(
|
||||
2 => new \ArrayIterator(array('key' => new Reference())),
|
||||
));
|
||||
|
||||
$callback = function ($value, ExecutionContextInterface $context) use ($test) {
|
||||
$test->fail('Should not be called');
|
||||
};
|
||||
|
||||
$traversableMetadata = new ClassMetadata('ArrayIterator');
|
||||
$traversableMetadata->addConstraint(new Traverse(true));
|
||||
|
||||
$this->metadataFactory->addMetadata($traversableMetadata);
|
||||
$this->referenceMetadata->addConstraint(new Callback(array(
|
||||
'callback' => $callback,
|
||||
'groups' => 'Group',
|
||||
)));
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid(array(
|
||||
'deep' => false,
|
||||
)));
|
||||
|
||||
$violations = $this->validate($entity, new Valid(), 'Group');
|
||||
|
||||
/** @var ConstraintViolationInterface[] $violations */
|
||||
$this->assertCount(0, $violations);
|
||||
}
|
||||
|
||||
public function testAddCustomizedViolation()
|
||||
{
|
||||
$entity = new Entity();
|
||||
|
|
Reference in New Issue