bug #37345 [Form] collect all transformation failures (xabbuh)

This PR was merged into the 3.4 branch.

Discussion
----------

[Form] collect all transformation failures

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #37262
| License       | MIT
| Doc PR        |

Commits
-------

a9987ce341 collect all transformation failures
This commit is contained in:
Fabien Potencier 2020-06-20 09:14:20 +02:00
commit cc145e2d9c
3 changed files with 64 additions and 35 deletions

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();