diff --git a/src/Symfony/Component/Validator/Constraints/Composite.php b/src/Symfony/Component/Validator/Constraints/Composite.php index bd7030ee27a4..b5cf5376764c 100644 --- a/src/Symfony/Component/Validator/Constraints/Composite.php +++ b/src/Symfony/Component/Validator/Constraints/Composite.php @@ -83,6 +83,13 @@ public function __construct($options = null) $mergedGroups = []; foreach ($nestedConstraints as $constraint) { + if ($constraint instanceof self && !$constraint->groups) { + // this nested composite constraint is initialized without groups + // when it happens, this one and its nested constraints needs to be + // implicitly added in the default group + $constraint->groups = [self::DEFAULT_GROUP]; + } + foreach ($constraint->groups as $group) { $mergedGroups[$group] = true; } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php index fef129cfa749..1fb86fa669d9 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\Email; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Required; use Symfony\Component\Validator\Constraints\Valid; @@ -100,4 +102,16 @@ public function testAcceptRequiredConstraintAsOneElementArray() $this->assertEquals($collection1, $collection2); } + + public function testConstraintHasDefaultGroupWithOptionalValues() + { + $constraint = new Collection([ + 'foo' => new Required(), + 'bar' => new Optional(), + ]); + + $this->assertEquals(['Default'], $constraint->groups); + $this->assertEquals(['Default'], $constraint->fields['foo']->groups); + $this->assertEquals(['Default'], $constraint->fields['bar']->groups); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php index e0ccdba754b0..11913eb2307a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CollectionValidatorTest.php @@ -143,6 +143,29 @@ public function testExtraFieldsDisallowed() ->assertRaised(); } + public function testExtraFieldsDisallowedWithOptionalValues() + { + $constraint = new Optional(); + + $data = $this->prepareTestData([ + 'baz' => 6, + ]); + + $this->validator->validate($data, new Collection([ + 'fields' => [ + 'foo' => $constraint, + ], + 'extraFieldsMessage' => 'myMessage', + ])); + + $this->buildViolation('myMessage') + ->setParameter('{{ field }}', '"baz"') + ->atPath('property.path[baz]') + ->setInvalidValue(6) + ->setCode(Collection::NO_SUCH_FIELD_ERROR) + ->assertRaised(); + } + // bug fix public function testNullNotConsideredExtraField() { diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php index 2d42807821bb..3dd14e4bba2b 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php @@ -15,11 +15,12 @@ use Symfony\Component\Validator\Constraints\Composite; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Valid; class ConcreteComposite extends Composite { - public $constraints; + public $constraints = []; protected function getCompositeOption() { @@ -37,6 +38,30 @@ public function getDefaultOption() */ class CompositeTest extends TestCase { + public function testConstraintHasDefaultGroup() + { + $constraint = new ConcreteComposite([ + new NotNull(), + new NotBlank(), + ]); + + $this->assertEquals(['Default'], $constraint->groups); + $this->assertEquals(['Default'], $constraint->constraints[0]->groups); + $this->assertEquals(['Default'], $constraint->constraints[1]->groups); + } + + public function testNestedCompositeConstraintHasDefaultGroup() + { + $constraint = new ConcreteComposite([ + new ConcreteComposite(), + new ConcreteComposite(), + ]); + + $this->assertEquals(['Default'], $constraint->groups); + $this->assertEquals(['Default'], $constraint->constraints[0]->groups); + $this->assertEquals(['Default'], $constraint->constraints[1]->groups); + } + public function testMergeNestedGroupsIfNoExplicitParentGroup() { $constraint = new ConcreteComposite([