diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 72ce53a59236..a765276dd74e 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -110,7 +110,9 @@ public function validate($form, Constraint $formConstraint) foreach ($constraints as $constraint) { // For the "Valid" constraint, validate the data in all groups if ($constraint instanceof Valid) { - $validator->atPath('data')->validate($data, $constraint, $groups); + if (\is_object($data)) { + $validator->atPath('data')->validate($data, $constraint, $groups); + } continue; } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php index cdaa9ae0d10c..e73947ada308 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\FormBuilderInterface; @@ -28,6 +29,7 @@ use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory; use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader; @@ -293,6 +295,39 @@ public function testCascadeValidationToChildFormsUsingPropertyPaths() $this->assertSame('children[field2].data', $violations[1]->getPropertyPath()); } + public function testCascadeValidationToChildFormsWithTwoValidConstraints() + { + $form = $this->formFactory->create(ReviewType::class); + + $form->submit([ + 'rating' => 1, + 'title' => 'Sample Title', + ]); + + $violations = $this->validator->validate($form); + + $this->assertCount(1, $violations); + $this->assertSame('This value should not be blank.', $violations[0]->getMessage()); + $this->assertSame('children[author].data.email', $violations[0]->getPropertyPath()); + } + + public function testCascadeValidationToChildFormsWithTwoValidConstraints2() + { + $form = $this->formFactory->create(ReviewType::class); + + $form->submit([ + 'title' => 'Sample Title', + ]); + + $violations = $this->validator->validate($form); + + $this->assertCount(2, $violations); + $this->assertSame('This value should not be blank.', $violations[0]->getMessage()); + $this->assertSame('data.rating', $violations[0]->getPropertyPath()); + $this->assertSame('This value should not be blank.', $violations[1]->getMessage()); + $this->assertSame('children[author].data.email', $violations[1]->getPropertyPath()); + } + public function testCascadeValidationToChildFormsUsingPropertyPathsValidatedInSequence() { $form = $this->formFactory->create(FormType::class, null, [ @@ -451,3 +486,62 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setDefault('data_class', Foo::class); } } + +class Review +{ + public $rating; + public $title; + public $author; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('title', new NotBlank()); + $metadata->addPropertyConstraint('rating', new NotBlank()); + } +} + +class ReviewType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('rating', IntegerType::class, [ + 'constraints' => [new Valid()], + ]) + ->add('title') + ->add('author', CustomerType::class, [ + 'constraints' => [new Valid()], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('data_class', Review::class); + } +} + +class Customer +{ + public $email; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('email', new NotBlank()); + } +} + +class CustomerType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('email') + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('data_class', Customer::class); + } +}