[Validator] Implemented traversing of \Traversable objects using the @Valid constraint. Can be disabled by setting the @Valid option 'traverse' to false

This commit is contained in:
Bernhard Schussek 2011-01-27 16:25:25 +01:00 committed by Fabien Potencier
parent 803dd58002
commit 0c3ca26e6e
4 changed files with 88 additions and 22 deletions

View File

@ -15,19 +15,7 @@ use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
class Valid extends \Symfony\Component\Validator\Constraint
{
/**
* This constraint does not accept any options
*
* @param mixed $options Unsupported argument!
*
* @throws InvalidOptionsException When the parameter $options is not NULL
*/
public function __construct($options = null)
{
if (null !== $options && count($options) > 0) {
throw new ConstraintDefinitionException('The constraint Valid does not accept any options');
}
}
public $traverse = true;
/**
* {@inheritDoc}

View File

@ -129,20 +129,24 @@ class GraphWalker
}
if ($metadata->isCascaded()) {
$this->walkReference($value, $propagatedGroup ?: $group, $propertyPath);
$this->walkReference($value, $propagatedGroup ?: $group, $propertyPath, $metadata->isCollectionCascaded());
}
}
protected function walkReference($value, $group, $propertyPath)
protected function walkReference($value, $group, $propertyPath, $traverse)
{
if (null !== $value) {
if (is_array($value)) {
foreach ($value as $key => $element) {
$this->walkReference($element, $group, $propertyPath.'['.$key.']');
}
} else if (!is_object($value)) {
if (!is_object($value) && !is_array($value)) {
throw new UnexpectedTypeException($value, 'object or array');
} else {
}
if ($traverse && (is_array($value) || $value instanceof \Traversable)) {
foreach ($value as $key => $element) {
$this->walkReference($element, $group, $propertyPath.'['.$key.']', $traverse);
}
}
if (is_object($value)) {
$metadata = $this->metadataFactory->getClassMetadata(get_class($value));
$this->walkObject($metadata, $value, $group, $propertyPath);
}

View File

@ -22,6 +22,7 @@ abstract class MemberMetadata extends ElementMetadata
public $name;
public $property;
public $cascaded = false;
public $collectionCascaded = false;
private $reflMember;
/**
@ -52,6 +53,7 @@ abstract class MemberMetadata extends ElementMetadata
if ($constraint instanceof Valid) {
$this->cascaded = true;
$this->collectionCascaded = $constraint->traverse;
} else {
parent::addConstraint($constraint);
}
@ -144,6 +146,17 @@ abstract class MemberMetadata extends ElementMetadata
return $this->cascaded;
}
/**
* Returns whether arrays or traversable objects stored in this member
* should be traversed and validated in each entry
*
* @return Boolean
*/
public function isCollectionCascaded()
{
return $this->collectionCascaded;
}
/**
* Returns the value of this property in the given object
*

View File

@ -237,7 +237,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($violations, $this->walker->getViolations());
}
public function testWalkCascadedPropertyValidatesArrays()
public function testWalkCascadedPropertyValidatesArraysByDefault()
{
$entity = new Entity();
$entityMetadata = new ClassMetadata(get_class($entity));
@ -269,6 +269,67 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($violations, $this->walker->getViolations());
}
public function testWalkCascadedPropertyValidatesTraversableByDefault()
{
$entity = new Entity();
$entityMetadata = new ClassMetadata(get_class($entity));
$this->factory->addClassMetadata($entityMetadata);
$this->factory->addClassMetadata(new ClassMetadata('ArrayIterator'));
// add a constraint for the entity that always fails
$entityMetadata->addConstraint(new FailingConstraint());
// validate array when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid());
$this->walker->walkPropertyValue(
$this->metadata,
'reference',
new \ArrayIterator(array('key' => $entity)),
'Default',
'path'
);
$violations = new ConstraintViolationList();
$violations->add(new ConstraintViolation(
'',
array(),
'Root',
'path[key]',
$entity
));
$this->assertEquals($violations, $this->walker->getViolations());
}
public function testWalkCascadedPropertyDoesNotValidateTraversableIfDisabled()
{
$entity = new Entity();
$entityMetadata = new ClassMetadata(get_class($entity));
$this->factory->addClassMetadata($entityMetadata);
$this->factory->addClassMetadata(new ClassMetadata('ArrayIterator'));
// add a constraint for the entity that always fails
$entityMetadata->addConstraint(new FailingConstraint());
// validate array when validating the property "reference"
$this->metadata->addPropertyConstraint('reference', new Valid(array(
'traverse' => false,
)));
$this->walker->walkPropertyValue(
$this->metadata,
'reference',
new \ArrayIterator(array('key' => $entity)),
'Default',
'path'
);
$violations = new ConstraintViolationList();
$this->assertEquals($violations, $this->walker->getViolations());
}
public function testWalkCascadedPropertyDoesNotValidateNullValues()
{
$this->metadata->addPropertyConstraint('reference', new Valid());