diff --git a/src/Symfony/Component/Validator/ConstraintProviderInterface.php b/src/Symfony/Component/Validator/ConstraintProviderInterface.php new file mode 100644 index 0000000000..c081d3ad13 --- /dev/null +++ b/src/Symfony/Component/Validator/ConstraintProviderInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator; + +use Symfony\Component\Validator\Mapping\ClassMetadata; + +/** + * Makes it possible to define dynamic constraints for an object. + */ +interface ConstraintProviderInterface +{ + /** + * Lets the user create dynamic constraints + * + * @param Mapping\ClassMetadata + */ + function loadDynamicValidatorMetadata(ClassMetadata $metadata); +} diff --git a/src/Symfony/Component/Validator/Validator.php b/src/Symfony/Component/Validator/Validator.php index d20a623256..2327aa1c0b 100644 --- a/src/Symfony/Component/Validator/Validator.php +++ b/src/Symfony/Component/Validator/Validator.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Mapping\ClassMetadataFactoryInterface; +use Symfony\Component\Validator\Mapping\ClassMetadata; /** * The default implementation of the ValidatorInterface. @@ -57,6 +58,13 @@ class Validator implements ValidatorInterface public function validate($object, $groups = null) { $metadata = $this->metadataFactory->getClassMetadata(get_class($object)); + + if ($object instanceof ConstraintProviderInterface) { + $dynamicMetadata = new ClassMetadata(get_class($object)); + $dynamicMetadata->mergeConstraints($metadata); + $object->loadDynamicValidatorMetadata($dynamicMetadata); + $metadata = $dynamicMetadata; + } $walk = function(GraphWalker $walker, $group) use ($metadata, $object) { return $walker->walkObject($metadata, $object, $group, ''); diff --git a/tests/Symfony/Tests/Component/Validator/Fixtures/DynamicConstraintsEntity.php b/tests/Symfony/Tests/Component/Validator/Fixtures/DynamicConstraintsEntity.php new file mode 100644 index 0000000000..41bfe44d39 --- /dev/null +++ b/tests/Symfony/Tests/Component/Validator/Fixtures/DynamicConstraintsEntity.php @@ -0,0 +1,30 @@ +validationEnabled = $enabled; + } + + public function getSecondValue() + { + return null; + } + + public function loadDynamicValidatorMetadata(ClassMetadata $metadata) + { + if ($this->validationEnabled) { + $metadata->addPropertyConstraint('firstValue', new FailingConstraint()); + $metadata->addGetterConstraint('secondValue', new FailingConstraint()); + } + } +} diff --git a/tests/Symfony/Tests/Component/Validator/ValidatorTest.php b/tests/Symfony/Tests/Component/Validator/ValidatorTest.php index 86c8ee98a6..38af8e31ba 100644 --- a/tests/Symfony/Tests/Component/Validator/ValidatorTest.php +++ b/tests/Symfony/Tests/Component/Validator/ValidatorTest.php @@ -15,10 +15,12 @@ require_once __DIR__.'/Fixtures/Entity.php'; require_once __DIR__.'/Fixtures/FailingConstraint.php'; require_once __DIR__.'/Fixtures/FailingConstraintValidator.php'; require_once __DIR__.'/Fixtures/FakeClassMetadataFactory.php'; +require_once __DIR__.'/Fixtures/DynamicConstraintsEntity.php'; use Symfony\Tests\Component\Validator\Fixtures\Entity; use Symfony\Tests\Component\Validator\Fixtures\FakeClassMetadataFactory; use Symfony\Tests\Component\Validator\Fixtures\FailingConstraint; +use Symfony\Tests\Component\Validator\Fixtures\DynamicConstraintsEntity; use Symfony\Component\Validator\Validator; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; @@ -121,6 +123,38 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase $this->assertEquals($violations, $result); } + + public function testValidate_constraintProvider() + { + $entity = new DynamicConstraintsEntity(); + $metadata = new ClassMetadata(get_class($entity)); + $this->factory->addClassMetadata($metadata); + + $entity->setValidation(true); + + $violations = new ConstraintViolationList(); + $violations->add(new ConstraintViolation( + '', + array(), + $entity, + 'firstValue', + '' + )); + $violations->add(new ConstraintViolation( + '', + array(), + $entity, + 'secondValue', + '' + )); + + $this->assertEquals($violations, $this->validator->validate($entity)); + + $entity->setValidation(false); + + $violations = new ConstraintViolationList(); + $this->assertEquals($violations, $this->validator->validate($entity)); + } public function testValidateProperty() {