[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:
parent
803dd58002
commit
0c3ca26e6e
@ -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}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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());
|
||||
|
Reference in New Issue
Block a user