[Validator] Fixed: @Valid does not recurse the traversal of collections anymore by default
This commit is contained in:
parent
5e87dd885c
commit
8f7e2f602c
@ -593,6 +593,28 @@
|
||||
* Core translation messages are changed. Dot is added at the end of each message.
|
||||
Overwritten core translations should be fixed if any. More info here.
|
||||
|
||||
* Collections (arrays or instances of `\Traversable`) in properties
|
||||
annotated with `Valid` are not traversed recursively by default anymore.
|
||||
|
||||
This means that if a collection contains an entry which is again a
|
||||
collection, the inner collection won't be traversed anymore as it
|
||||
happened before. You can set the BC behavior by setting the new property
|
||||
`deep` of `Valid` to `true`.
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
/** @Assert\Valid */
|
||||
private $recursiveCollection;
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
/** @Assert\Valid(deep = true) */
|
||||
private $recursiveCollection;
|
||||
```
|
||||
|
||||
### Session
|
||||
|
||||
* Flash messages now return an array based on their type. The old method is
|
||||
|
@ -20,3 +20,6 @@ CHANGELOG
|
||||
* [BC BREAK] ConstraintValidatorInterface method `isValid` has been renamed to
|
||||
`validate`, its return value was dropped. ConstraintValidator still contains
|
||||
`isValid` for BC
|
||||
* [BC BREAK] collections in fields annotated with `Valid` are not traversed
|
||||
recursively anymore by default. `Valid` contains a new property `deep`
|
||||
which enables the BC behavior.
|
||||
|
@ -21,4 +21,6 @@ use Symfony\Component\Validator\Constraint;
|
||||
class Valid extends Constraint
|
||||
{
|
||||
public $traverse = true;
|
||||
|
||||
public $deep = false;
|
||||
}
|
||||
|
@ -137,11 +137,11 @@ class GraphWalker
|
||||
}
|
||||
|
||||
if ($metadata->isCascaded()) {
|
||||
$this->walkReference($value, $propagatedGroup ?: $group, $propertyPath, $metadata->isCollectionCascaded());
|
||||
$this->walkReference($value, $propagatedGroup ?: $group, $propertyPath, $metadata->isCollectionCascaded(), $metadata->isCollectionCascadedDeeply());
|
||||
}
|
||||
}
|
||||
|
||||
public function walkReference($value, $group, $propertyPath, $traverse)
|
||||
public function walkReference($value, $group, $propertyPath, $traverse, $deep = false)
|
||||
{
|
||||
if (null !== $value) {
|
||||
if (!is_object($value) && !is_array($value)) {
|
||||
@ -152,7 +152,8 @@ class GraphWalker
|
||||
foreach ($value as $key => $element) {
|
||||
// Ignore any scalar values in the collection
|
||||
if (is_object($element) || is_array($element)) {
|
||||
$this->walkReference($element, $group, $propertyPath.'['.$key.']', $traverse);
|
||||
// Only repeat the traversal if $deep is set
|
||||
$this->walkReference($element, $group, $propertyPath.'['.$key.']', $deep, $deep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ abstract class MemberMetadata extends ElementMetadata
|
||||
public $property;
|
||||
public $cascaded = false;
|
||||
public $collectionCascaded = false;
|
||||
public $collectionCascadedDeeply = false;
|
||||
private $reflMember;
|
||||
|
||||
/**
|
||||
@ -52,7 +53,9 @@ abstract class MemberMetadata extends ElementMetadata
|
||||
|
||||
if ($constraint instanceof Valid) {
|
||||
$this->cascaded = true;
|
||||
/* @var Valid $constraint */
|
||||
$this->collectionCascaded = $constraint->traverse;
|
||||
$this->collectionCascadedDeeply = $constraint->deep;
|
||||
} else {
|
||||
parent::addConstraint($constraint);
|
||||
}
|
||||
@ -156,6 +159,17 @@ abstract class MemberMetadata extends ElementMetadata
|
||||
return $this->collectionCascaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether arrays or traversable objects stored in this member
|
||||
* should be traversed recursively for inner arrays/traversable objects
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isCollectionCascadedDeeply()
|
||||
{
|
||||
return $this->collectionCascadedDeeply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this property in the given object
|
||||
*
|
||||
|
@ -357,6 +357,77 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($violations, $this->walker->getViolations());
|
||||
}
|
||||
|
||||
public function testWalkCascadedPropertyDoesNotRecurseByDefault()
|
||||
{
|
||||
$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 iterator when validating the property "reference"
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid());
|
||||
|
||||
$this->walker->walkPropertyValue(
|
||||
$this->metadata,
|
||||
'reference',
|
||||
new \ArrayIterator(array(
|
||||
// The inner iterator should not be traversed by default
|
||||
'key' => new \ArrayIterator(array(
|
||||
'nested' => $entity,
|
||||
)),
|
||||
)),
|
||||
'Default',
|
||||
'path'
|
||||
);
|
||||
|
||||
$violations = new ConstraintViolationList();
|
||||
|
||||
$this->assertEquals($violations, $this->walker->getViolations());
|
||||
}
|
||||
|
||||
public function testWalkCascadedPropertyRecursesIfDeepIsSet()
|
||||
{
|
||||
$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 iterator when validating the property "reference"
|
||||
$this->metadata->addPropertyConstraint('reference', new Valid(array(
|
||||
'deep' => true,
|
||||
)));
|
||||
|
||||
$this->walker->walkPropertyValue(
|
||||
$this->metadata,
|
||||
'reference',
|
||||
new \ArrayIterator(array(
|
||||
// The inner iterator should now be traversed
|
||||
'key' => new \ArrayIterator(array(
|
||||
'nested' => $entity,
|
||||
)),
|
||||
)),
|
||||
'Default',
|
||||
'path'
|
||||
);
|
||||
|
||||
$violations = new ConstraintViolationList();
|
||||
$violations->add(new ConstraintViolation(
|
||||
'Failed',
|
||||
array(),
|
||||
'Root',
|
||||
'path[key][nested]',
|
||||
$entity
|
||||
));
|
||||
|
||||
$this->assertEquals($violations, $this->walker->getViolations());
|
||||
}
|
||||
|
||||
public function testWalkCascadedPropertyDoesNotValidateNestedScalarValues()
|
||||
{
|
||||
// validate array when validating the property "reference"
|
||||
|
Reference in New Issue
Block a user