Skip to content

Commit

Permalink
[Validator] Implemented traversing of \Traversable objects using the @…
Browse files Browse the repository at this point in the history
…Valid constraint. Can be disabled by setting the @Valid option 'traverse' to false
  • Loading branch information
Bernhard Schussek authored and fabpot committed Jan 28, 2011
1 parent 803dd58 commit 0c3ca26
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 21 deletions.
14 changes: 1 addition & 13 deletions src/Symfony/Component/Validator/Constraints/Valid.php
Expand Up @@ -15,19 +15,7 @@

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}
Expand Down
18 changes: 11 additions & 7 deletions src/Symfony/Component/Validator/GraphWalker.php
Expand Up @@ -129,20 +129,24 @@ protected function walkMember(MemberMetadata $metadata, $value, $group, $propert
}

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)) {
if (!is_object($value) && !is_array($value)) {
throw new UnexpectedTypeException($value, 'object or array');
}

if ($traverse && (is_array($value) || $value instanceof \Traversable)) {
foreach ($value as $key => $element) {
$this->walkReference($element, $group, $propertyPath.'['.$key.']');
$this->walkReference($element, $group, $propertyPath.'['.$key.']', $traverse);
}
} else if (!is_object($value)) {
throw new UnexpectedTypeException($value, 'object or array');
} else {
}

if (is_object($value)) {
$metadata = $this->metadataFactory->getClassMetadata(get_class($value));
$this->walkObject($metadata, $value, $group, $propertyPath);
}
Expand Down
13 changes: 13 additions & 0 deletions src/Symfony/Component/Validator/Mapping/MemberMetadata.php
Expand Up @@ -22,6 +22,7 @@ abstract class MemberMetadata extends ElementMetadata
public $name;
public $property;
public $cascaded = false;
public $collectionCascaded = false;

This comment has been minimized.

Copy link
@tomat

tomat Aug 2, 2011

Is there a reason that this property was not added to MemberMetadata::__sleep()?

private $reflMember;

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

if ($constraint instanceof Valid) {
$this->cascaded = true;
$this->collectionCascaded = $constraint->traverse;
} else {
parent::addConstraint($constraint);
}
Expand Down Expand Up @@ -144,6 +146,17 @@ public function isCascaded()
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
*
Expand Down
63 changes: 62 additions & 1 deletion tests/Symfony/Tests/Component/Validator/GraphWalkerTest.php
Expand Up @@ -237,7 +237,7 @@ public function testWalkCascadedPropertyValidatesReferences()
$this->assertEquals($violations, $this->walker->getViolations());
}

public function testWalkCascadedPropertyValidatesArrays()
public function testWalkCascadedPropertyValidatesArraysByDefault()
{
$entity = new Entity();
$entityMetadata = new ClassMetadata(get_class($entity));
Expand Down Expand Up @@ -269,6 +269,67 @@ public function testWalkCascadedPropertyValidatesArrays()
$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());
Expand Down

0 comments on commit 0c3ca26

Please sign in to comment.