From 0ca27ccfdee584d3cee9aaa548dc04112ddaea66 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 27 Dec 2016 11:46:45 +0100 Subject: [PATCH] add groups support to the Valid constraint --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Component/Validator/Constraints/Valid.php | 23 ++++++++---- .../Validator/Constraints/ValidValidator.php | 37 +++++++++++++++++++ .../Validator/Mapping/GenericMetadata.php | 2 +- .../Validator/Tests/Constraints/ValidTest.php | 16 +++++--- .../Tests/Validator/AbstractTest.php | 35 ++++++++++++++++++ 6 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 src/Symfony/Component/Validator/Constraints/ValidValidator.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 782ee436e037c..8eff88c6bbfed 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 3.4.0 ----- + * added support for validation groups to the `Valid` constraint * not setting the `strict` option of the `Choice` constraint to `true` is deprecated and will throw an exception in Symfony 4.0 * setting the `checkDNS` option of the `Url` constraint to `true` is deprecated in favor of constant values and will throw an exception in Symfony 4.0 diff --git a/src/Symfony/Component/Validator/Constraints/Valid.php b/src/Symfony/Component/Validator/Constraints/Valid.php index 439da3ae0056a..893942377851f 100644 --- a/src/Symfony/Component/Validator/Constraints/Valid.php +++ b/src/Symfony/Component/Validator/Constraints/Valid.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\Exception\ConstraintDefinitionException; /** * @Annotation @@ -24,15 +23,23 @@ class Valid extends Constraint { public $traverse = true; - public function __construct($options = null) + public function __get($option) { - if (is_array($options) && array_key_exists('groups', $options)) { - throw new ConstraintDefinitionException(sprintf( - 'The option "groups" is not supported by the constraint %s', - __CLASS__ - )); + if ('groups' === $option) { + // when this is reached, no groups have been configured + return null; } - parent::__construct($options); + return parent::__get($option); + } + + /** + * {@inheritdoc} + */ + public function addImplicitGroupName($group) + { + if (null !== $this->groups) { + parent::addImplicitGroupName($group); + } } } diff --git a/src/Symfony/Component/Validator/Constraints/ValidValidator.php b/src/Symfony/Component/Validator/Constraints/ValidValidator.php new file mode 100644 index 0000000000000..45ac69d91d196 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/ValidValidator.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; + +/** + * @author Christian Flothmann + */ +class ValidValidator extends ConstraintValidator +{ + public function validate($value, Constraint $constraint) + { + if (!$constraint instanceof Valid) { + throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Valid'); + } + + $violations = $this->context->getValidator()->validate($value, null, array($this->context->getGroup())); + + foreach ($violations as $violation) { + $this->context->buildViolation($violation->getMessage(), $violation->getParameters()) + ->atPath($violation->getPropertyPath()) + ->addViolation(); + } + } +} diff --git a/src/Symfony/Component/Validator/Mapping/GenericMetadata.php b/src/Symfony/Component/Validator/Mapping/GenericMetadata.php index ff1cb6d37f89e..a14b6578e359c 100644 --- a/src/Symfony/Component/Validator/Mapping/GenericMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/GenericMetadata.php @@ -131,7 +131,7 @@ public function addConstraint(Constraint $constraint) )); } - if ($constraint instanceof Valid) { + if ($constraint instanceof Valid && null === $constraint->groups) { $this->cascadingStrategy = CascadingStrategy::CASCADE; if ($constraint->traverse) { diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ValidTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ValidTest.php index 83722fd2df0e0..9928bd82d0225 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ValidTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ValidTest.php @@ -19,11 +19,17 @@ */ class ValidTest extends TestCase { - /** - * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException - */ - public function testRejectGroupsOption() + public function testGroupsCanBeSet() { - new Valid(array('groups' => 'foo')); + $constraint = new Valid(array('groups' => 'foo')); + + $this->assertSame(array('foo'), $constraint->groups); + } + + public function testGroupsAreNullByDefault() + { + $constraint = new Valid(); + + $this->assertNull($constraint->groups); } } diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php index 77a7cc6c2bdc6..90b384a3111bd 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/AbstractTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\GroupSequence; +use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Traverse; use Symfony\Component\Validator\Constraints\Valid; @@ -670,4 +671,38 @@ public function testCollectionConstraitViolationHasCorrectContext() $this->assertCount(1, $violations); $this->assertSame($constraint, $violations[0]->getConstraint()); } + + public function testNestedObjectIsNotValidatedIfGroupInValidConstraintIsNotValidated() + { + $entity = new Entity(); + $entity->firstName = ''; + $reference = new Reference(); + $reference->value = ''; + $entity->childA = $reference; + + $this->metadata->addPropertyConstraint('firstName', new NotBlank(array('groups' => 'group1'))); + $this->metadata->addPropertyConstraint('childA', new Valid(array('groups' => 'group1'))); + $this->referenceMetadata->addPropertyConstraint('value', new NotBlank()); + + $violations = $this->validator->validate($entity, null, array()); + + $this->assertCount(0, $violations); + } + + public function testNestedObjectIsValidatedIfGroupInValidConstraintIsValidated() + { + $entity = new Entity(); + $entity->firstName = ''; + $reference = new Reference(); + $reference->value = ''; + $entity->childA = $reference; + + $this->metadata->addPropertyConstraint('firstName', new NotBlank(array('groups' => 'group1'))); + $this->metadata->addPropertyConstraint('childA', new Valid(array('groups' => 'group1'))); + $this->referenceMetadata->addPropertyConstraint('value', new NotBlank(array('groups' => 'group1'))); + + $violations = $this->validator->validate($entity, null, array('Default', 'group1')); + + $this->assertCount(2, $violations); + } }