[Validator] Implemented handling of arrays and Traversables in LegacyExecutionContext::validate()

This commit is contained in:
Bernhard Schussek 2014-02-19 11:56:27 +01:00
parent 09f744b89c
commit ee1adadbfb
7 changed files with 163 additions and 8 deletions

View File

@ -12,6 +12,8 @@
namespace Symfony\Component\Validator\Context;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\Traverse;
use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Exception\InvalidArgumentException;
use Symfony\Component\Validator\ExecutionContextInterface as LegacyExecutionContextInterface;
use Symfony\Component\Validator\Group\GroupManagerInterface;
@ -100,7 +102,33 @@ class LegacyExecutionContext extends ExecutionContext implements LegacyExecution
*/
public function validate($value, $subPath = '', $groups = null, $traverse = false, $deep = false)
{
// TODO handle $traverse and $deep
if (is_array($value)) {
$constraint = new Traverse(array(
'traverse' => true,
'deep' => $deep,
));
return $this
->getValidator()
->inContext($this)
->atPath($subPath)
->validateValue($value, $constraint, $groups)
;
}
if ($traverse && $value instanceof \Traversable) {
$constraints = array(
new Valid(),
new Traverse(array('traverse' => true, 'deep' => $deep)),
);
return $this
->getValidator()
->inContext($this)
->atPath($subPath)
->validateValue($value, $constraints, $groups)
;
}
return $this
->getValidator()

View File

@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\Context\ExecutionContext;
use Symfony\Component\Validator\ExecutionContextInterface;
use Symfony\Component\Validator\MetadataFactoryInterface;
use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory;
@ -1416,6 +1417,100 @@ abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase
$this->assertSame('Violation in Group 2', $violations[0]->getMessage());
}
public function testValidateInContext()
{
$test = $this;
$entity = new Entity();
$entity->reference = new Reference();
$callback1 = function ($value, ExecutionContextInterface $context) {
$context->validate($value->reference, 'subpath');
};
$callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
$test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
$test->assertNull($context->getPropertyName());
$test->assertSame('subpath', $context->getPropertyPath());
$test->assertSame('Group', $context->getGroup());
$test->assertSame($test->referenceMetadata, $context->getMetadata());
$test->assertSame($test->metadataFactory, $context->getMetadataFactory());
$test->assertSame($entity, $context->getRoot());
$test->assertSame($entity->reference, $context->getValue());
$test->assertSame($entity->reference, $value);
$context->addViolation('Message %param%', array('%param%' => 'value'));
};
$this->metadata->addConstraint(new Callback(array(
'callback' => $callback1,
'groups' => 'Group',
)));
$this->referenceMetadata->addConstraint(new Callback(array(
'callback' => $callback2,
'groups' => 'Group',
)));
$violations = $this->validator->validate($entity, 'Group');
/** @var ConstraintViolationInterface[] $violations */
$this->assertCount(1, $violations);
$this->assertSame('Message value', $violations[0]->getMessage());
$this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
$this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters());
$this->assertSame('subpath', $violations[0]->getPropertyPath());
$this->assertSame($entity, $violations[0]->getRoot());
$this->assertSame($entity->reference, $violations[0]->getInvalidValue());
$this->assertNull($violations[0]->getMessagePluralization());
$this->assertNull($violations[0]->getCode());
}
public function testValidateArrayInContext()
{
$test = $this;
$entity = new Entity();
$entity->reference = new Reference();
$callback1 = function ($value, ExecutionContextInterface $context) {
$context->validate(array('key' => $value->reference), 'subpath');
};
$callback2 = function ($value, ExecutionContextInterface $context) use ($test, $entity) {
$test->assertSame($test::REFERENCE_CLASS, $context->getClassName());
$test->assertNull($context->getPropertyName());
$test->assertSame('subpath[key]', $context->getPropertyPath());
$test->assertSame('Group', $context->getGroup());
$test->assertSame($test->referenceMetadata, $context->getMetadata());
$test->assertSame($test->metadataFactory, $context->getMetadataFactory());
$test->assertSame($entity, $context->getRoot());
$test->assertSame($entity->reference, $context->getValue());
$test->assertSame($entity->reference, $value);
$context->addViolation('Message %param%', array('%param%' => 'value'));
};
$this->metadata->addConstraint(new Callback(array(
'callback' => $callback1,
'groups' => 'Group',
)));
$this->referenceMetadata->addConstraint(new Callback(array(
'callback' => $callback2,
'groups' => 'Group',
)));
$violations = $this->validator->validate($entity, 'Group');
/** @var ConstraintViolationInterface[] $violations */
$this->assertCount(1, $violations);
$this->assertSame('Message value', $violations[0]->getMessage());
$this->assertSame('Message %param%', $violations[0]->getMessageTemplate());
$this->assertSame(array('%param%' => 'value'), $violations[0]->getMessageParameters());
$this->assertSame('subpath[key]', $violations[0]->getPropertyPath());
$this->assertSame($entity, $violations[0]->getRoot());
$this->assertSame($entity->reference, $violations[0]->getInvalidValue());
$this->assertNull($violations[0]->getMessagePluralization());
$this->assertNull($violations[0]->getCode());
}
public function testGetMetadataFactory()
{
$this->assertSame($this->metadataFactory, $this->validator->getMetadataFactory());

View File

@ -12,9 +12,7 @@
namespace Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Traverse;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
use Symfony\Component\Validator\Mapping\GenericMetadata;

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Traverse;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Context\ExecutionContextManagerInterface;
@ -41,6 +42,8 @@ class ContextualValidator extends AbstractValidator implements ContextualValidat
public function atPath($subPath)
{
$this->defaultPropertyPath = $this->context->getPropertyPath($subPath);
return $this;
}
/**
@ -62,6 +65,18 @@ class ContextualValidator extends AbstractValidator implements ContextualValidat
return $this->context->getViolations();
}
public function validateCollection($collection, $groups = null, $deep = false)
{
$constraint = new Traverse(array(
'traverse' => true,
'deep' => $deep,
));
$this->traverseValue($collection, $constraint, $groups);
return $this->context->getViolations();
}
/**
* Validates a property of a value against its current value.
*

View File

@ -24,17 +24,21 @@ class LegacyValidator extends Validator implements LegacyValidatorInterface
public function validate($value, $groups = null, $traverse = false, $deep = false)
{
if (is_array($value)) {
return $this->validateValue($value, new Traverse(array(
$constraint = new Traverse(array(
'traverse' => true,
'deep' => $deep,
)), $groups);
));
return $this->validateValue($value, $constraint, $groups);
}
if ($traverse && $value instanceof \Traversable) {
return $this->validateValue($value, array(
$constraints = array(
new Valid(),
new Traverse(array('traverse' => true, 'deep' => $deep)),
), $groups);
);
return $this->validateValue($value, $constraints, $groups);
}
return $this->validateObject($value, $groups);

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\Constraints\Traverse;
use Symfony\Component\Validator\Context\ExecutionContextManagerInterface;
use Symfony\Component\Validator\NodeTraverser\NodeTraverserInterface;
use Symfony\Component\Validator\MetadataFactoryInterface;
@ -42,6 +43,20 @@ class Validator extends AbstractValidator
return $this->contextManager->stopContext()->getViolations();
}
public function validateCollection($collection, $groups = null, $deep = false)
{
$this->contextManager->startContext($collection);
$constraint = new Traverse(array(
'traverse' => true,
'deep' => $deep,
));
$this->traverseValue($collection, $constraint, $groups);
return $this->contextManager->stopContext()->getViolations();
}
public function validateProperty($object, $propertyName, $groups = null)
{
$this->contextManager->startContext($object);

View File

@ -35,7 +35,7 @@ interface ValidatorInterface
*/
public function validateObject($object, $groups = null);
// public function validateCollection($collection, $groups = null);
public function validateCollection($collection, $groups = null, $deep = false);
/**
* Validates a property of a value against its current value.