Description
After upgrading to 3.1.1, I get ContextErrorExceptions (instead of form validation errors) when I combine Form, DataTransformers and UniqueEntity validation over multiple fields.
To nail down the root cause I've created a new sample test project with 3 entities:
- Beer entity
- Cake entity
- Foobar Entity which has ManyToOne relation to Beer and Cake
Validation rule is applied to make sure the entity FooBar can only have unique Beer-Cake combinations. Because in our real-world example we are feeding the data using a restful api, this use-case requires us to use DataTransformers (to transform a beer-brand to an entity, and back)
Expected behavior is a FormErrorIterator to gracefully handle the error. In this code example: This beer-cake combination is already used.
Instead a ContextErrorException is thrown, the trans() function in IdentityTranslator.php casts the field $id to a string and breaks.
A workaround is to implement __toString() on the Beer/Cake entity, which works.
When downgrading again to 3.0 the same code works again like expected.
When executing my code sample, the first run of my test-command (easiest way for me to reproduce it on the cli) is succesful, second attempt throws a ContextErrorException where a FormError is expected. The Exception is thrown as a result of $form->submit().
Exception trace:
() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Translation/IdentityTranslator.php:55
Symfony\Component\Debug\ErrorHandler->handleError() at n/a:n/a
strtr() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Translation/IdentityTranslator.php:55
Symfony\Component\Translation\IdentityTranslator->trans() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php:194
Symfony\Component\Validator\Violation\ConstraintViolationBuilder->addViolation() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php:134
Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator->validate() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:843
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateInGroup() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:554
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateClassNode() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:357
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateObject() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:154
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validate() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php:51
Symfony\Component\Form\Extension\Validator\Constraints\FormValidator->validate() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:843
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateInGroup() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:554
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateClassNode() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:357
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateObject() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php:154
Symfony\Component\Validator\Validator\RecursiveContextualValidator->validate() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Validator/Validator/RecursiveValidator.php:117
Symfony\Component\Validator\Validator\RecursiveValidator->validate() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Validator/EventListener/ValidationListener.php:55
Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener->validateForm() at n/a:n/a
call_user_func() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/EventDispatcher.php:174
Symfony\Component\EventDispatcher\EventDispatcher->doDispatch() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/EventDispatcher.php:43
Symfony\Component\EventDispatcher\EventDispatcher->dispatch() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/EventDispatcher/ImmutableEventDispatcher.php:43
Symfony\Component\EventDispatcher\ImmutableEventDispatcher->dispatch() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php:655
Symfony\Component\Form\Form->submit() at /Users/john/Temp/entity-bug-test/src/AppBundle/Command/TestCommand.php:41
AppBundle\Command\TestCommand->execute() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:256
Symfony\Component\Console\Command\Command->run() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:831
Symfony\Component\Console\Application->doRunCommand() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:186
Symfony\Component\Console\Application->doRun() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:80
Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /Users/john/Temp/entity-bug-test/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:117
Symfony\Component\Console\Application->run() at /Users/john/Temp/entity-bug-test/bin/console:29
Some code snippets to reproduce:
Validation YML:
AppBundle\Entity\Foobar:
constraints:
- Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity:
fields: [beer, cake]
errorPath: cake
message: 'This beer-cake combination is already used'
FormType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('beer', TextType::class)
->add('cake', TextType::class)
;
$builder->get('beer')->addModelTransformer(new BeerTransformer($this->manager));
$builder->get('cake')->addModelTransformer(new CakeTransformer($this->manager));
}
Snippet of test code (command):
$formFactory = $this->getContainer()->get('form.factory');
$form = $formFactory->create(FoobarType::class, $foobar, array('method' => 'POST'));
$parameters = [
'beer' => 'Heineken',
'cake' => 'Grandmothers cake'
];
$form->submit($parameters, true);
if (!$form->isValid()) {
//Handle error
}