Skip to content

Commit

Permalink
[Validator] Fixed: @Valid does not recurse the traversal of collectio…
Browse files Browse the repository at this point in the history
…ns anymore by default
  • Loading branch information
webmozart committed May 22, 2012
1 parent a0bfe45 commit f333cf6
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ CHANGELOG
* [BC BREAK] ConstraintValidatorInterface method `isValid` has been renamed to * [BC BREAK] ConstraintValidatorInterface method `isValid` has been renamed to
`validate`, its return value was dropped. ConstraintValidator still contains `validate`, its return value was dropped. ConstraintValidator still contains
`isValid` for BC `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.
2 changes: 2 additions & 0 deletions Constraints/Valid.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@
class Valid extends Constraint class Valid extends Constraint
{ {
public $traverse = true; public $traverse = true;

public $deep = false;
} }
7 changes: 4 additions & 3 deletions GraphWalker.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ protected function walkMember(MemberMetadata $metadata, $value, $group, $propert
} }


if ($metadata->isCascaded()) { 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 (null !== $value) {
if (!is_object($value) && !is_array($value)) { if (!is_object($value) && !is_array($value)) {
Expand All @@ -152,7 +152,8 @@ public function walkReference($value, $group, $propertyPath, $traverse)
foreach ($value as $key => $element) { foreach ($value as $key => $element) {
// Ignore any scalar values in the collection // Ignore any scalar values in the collection
if (is_object($element) || is_array($element)) { 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);
} }
} }
} }
Expand Down
14 changes: 14 additions & 0 deletions Mapping/MemberMetadata.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ abstract class MemberMetadata extends ElementMetadata
public $property; public $property;
public $cascaded = false; public $cascaded = false;
public $collectionCascaded = false; public $collectionCascaded = false;
public $collectionCascadedDeeply = false;
private $reflMember; private $reflMember;


/** /**
Expand Down Expand Up @@ -52,7 +53,9 @@ public function addConstraint(Constraint $constraint)


if ($constraint instanceof Valid) { if ($constraint instanceof Valid) {
$this->cascaded = true; $this->cascaded = true;
/* @var Valid $constraint */
$this->collectionCascaded = $constraint->traverse; $this->collectionCascaded = $constraint->traverse;
$this->collectionCascadedDeeply = $constraint->deep;
} else { } else {
parent::addConstraint($constraint); parent::addConstraint($constraint);
} }
Expand Down Expand Up @@ -156,6 +159,17 @@ public function isCollectionCascaded()
return $this->collectionCascaded; 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 * Returns the value of this property in the given object
* *
Expand Down
71 changes: 71 additions & 0 deletions Tests/GraphWalkerTest.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -357,6 +357,77 @@ public function testWalkCascadedPropertyDoesNotValidateTraversableIfDisabled()
$this->assertEquals($violations, $this->walker->getViolations()); $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() public function testWalkCascadedPropertyDoesNotValidateNestedScalarValues()
{ {
// validate array when validating the property "reference" // validate array when validating the property "reference"
Expand Down

0 comments on commit f333cf6

Please sign in to comment.