From a9987ce3411f0f268b16b081994dc7fdad313441 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 18 Jun 2020 21:22:57 +0200 Subject: [PATCH] collect all transformation failures --- .../Validator/Constraints/FormValidator.php | 5 +- .../FormValidatorFunctionalTest.php | 60 +++++++++++++++++++ .../Constraints/FormValidatorTest.php | 34 ----------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 4447b2e54a..8f7acb35d8 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -147,7 +147,10 @@ class FormValidator extends ConstraintValidator foreach ($form as $child) { if (!$child->isSynchronized()) { $childrenSynchronized = false; - break; + + $fieldFormConstraint = new Form(); + $this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath()); + $validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $fieldFormConstraint); } } 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 b51b34bb32..d4ca0cb1bf 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Constraints; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +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\TextType; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; @@ -329,6 +332,63 @@ class FormValidatorFunctionalTest extends TestCase $this->assertCount(0, $violations); } + + public function testSubmitFormChoiceInvalid() + { + $form = $this->formFactory->create(DateType::class, null, [ + 'widget' => 'choice', + 'years' => [2021], + ]); + + $form->submit([ + 'year' => '2020', + 'month' => '13', + 'day' => '13', + ]); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertCount(2, $form->getErrors()); + $this->assertSame('This value is not valid.', $form->getErrors()[0]->getMessage()); + $this->assertSame($form->get('year'), $form->getErrors()[0]->getOrigin()); + $this->assertSame('This value is not valid.', $form->getErrors()[1]->getMessage()); + $this->assertSame($form->get('month'), $form->getErrors()[1]->getOrigin()); + } + + public function testDoNotAddInvalidMessageIfChildFormIsAlreadyNotSynchronized() + { + $formBuilder = $this->formFactory->createBuilder() + ->add('field1') + ->add('field2') + ->addModelTransformer(new CallbackTransformer( + function () { + }, + function () { + throw new TransformationFailedException('This value is invalid.'); + } + )); + $formBuilder->get('field2')->addModelTransformer(new CallbackTransformer( + function () { + }, + function () { + throw new TransformationFailedException('This value is invalid.'); + } + )); + $form = $formBuilder->getForm(); + + $form->submit([ + 'field1' => 'foo', + 'field2' => 'bar', + ]); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertCount(0, $form->getErrors()); + $this->assertTrue($form->get('field1')->isValid()); + $this->assertCount(0, $form->get('field1')->getErrors()); + $this->assertFalse($form->get('field2')->isValid()); + $this->assertCount(1, $form->get('field2')->getErrors()); + } } class Foo diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index f789fbe1e4..69f4efac17 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -362,40 +362,6 @@ class FormValidatorTest extends ConstraintValidatorTestCase ->assertRaised(); } - // https://github.com/symfony/symfony/issues/4359 - public function testDontMarkInvalidIfAnyChildIsNotSynchronized() - { - $object = new \stdClass(); - $object->child = 'bar'; - - $failingTransformer = new CallbackTransformer( - function ($data) { return $data; }, - function () { throw new TransformationFailedException(); } - ); - - $form = $this->getBuilder('name', '\stdClass') - ->setData($object) - ->addViewTransformer($failingTransformer) - ->setCompound(true) - ->setDataMapper(new PropertyPathMapper()) - ->add( - $this->getBuilder('child') - ->addViewTransformer($failingTransformer) - ) - ->getForm(); - - // Launch transformer - $form->submit(['child' => 'foo']); - - $this->assertTrue($form->isSubmitted()); - $this->assertFalse($form->isSynchronized()); - $this->expectNoValidate(); - - $this->validator->validate($form, new Form()); - - $this->assertNoViolation(); - } - public function testHandleGroupSequenceValidationGroups() { $object = new \stdClass();