⌛ This article is now 2 years and 6 months old, a quite long time during which techniques and tools might have evolved. Please contact us to get a fresh insight of our expertise!
Display Symfony form errors, without any submit
Imagine our database contains some invalid entries and we build a form allowing us to complete the entity: how can our users know which fields are invalid and need completion?!
Building a Form with that invalid entity and displaying it to the user is not enough, no errors are going to be displayed until the user submit the form.
In Symfony, form validation is done when the form is submitted thanks to the ValidationListener
POST_SUBMIT handler.
Upon submit, an action is basically splitted in two paths:
- either the form is valid (
$form->isValid()
) and we redirect; - either it’s not and the form is displayed again, with nice errors alongside the submitted data.
What if we want this second path, with all the invalid states of our data, as soon as the form is displayed the first time?
Here is how I did it, hope it helps!
Section intitulée submit-the-form-artificiallySubmit the form artificially
We are going to change the typical action logic a bit, to introduce a new code path when the form is not submitted:
$form = $this->createForm(EmployeeType::class, $employee);
$form->handleRequest($request);
- if ($form->isSubmitted() && $form->isValid()) {
- // Save the object
- return $this->redirectToRoute('home');
+ if ($form->isSubmitted()) {
+ if ($form->isValid()) {
+ // Save the object
+ return $this->redirectToRoute('home');
+ }
+ } else {
+ $form->submit(null, false);
}
The important call is $form->submit(null, false);
. It will trick the form to run all the “submit” events, including the ValidationListener
POST_SUBMIT
. So all our initial data (the $employee
object here) are run against validation and our user knows what’s missing.
But I would not write an article just to show this. There is a catch: the CSRF protection is also triggered and will return an error, because the token is not part of the initial data (and that’s the same for all the fields added dynamically).
One way of dealing with it without disabling this important security feature is to get a valid token from the token manager attached to the form. This is kind of hacky but as we do it only when the form is not submitted, there is no issue:
$csrfManager = $form->getConfig()->getOption('csrf_token_manager');
$csrfId = $form->getConfig()->getOption('csrf_token_id');
$csrfField = $form->getConfig()->getOption('csrf_field_name');
$tokenId = $csrfId ?: ($form->getName() ?: \get_class($form->getConfig()->getType()->getInnerType()));
$form->submit([$csrfField => (string) $csrfManager->getToken($tokenId)], false);
(We use the same logic as FormTypeCsrfExtension
.)
With this version, our initial page load displays the complete form with nice errors on fields that need to be completed and no unsolicited CSRF error.
Section intitulée final-action-codeFinal action code
The complete action code is:
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
// Save the object
return $this->redirectToRoute('home');
}
} else {
// Build the CSRF like FormTypeCsrfExtension to fake form submit (used to display initial errors)
$csrfManager = $form->getConfig()->getOption('csrf_token_manager');
$csrfId = $form->getConfig()->getOption('csrf_token_id');
$csrfField = $form->getConfig()->getOption('csrf_field_name');
$tokenId = $csrfId ?: ($form->getName() ?: \get_class($form->getConfig()->getType()->getInnerType()));
$form->submit([$csrfField => (string) $csrfManager->getToken($tokenId)], false);
}
At the moment, I don’t see any other place this could be done (FormExtension
or FormEvent
), so if needed on multiple forms and actions, a refactoring must be done.
This feature / need has not gained much attention on Github when it was suggested so I guess this is not a common need – anyway I hope it solves something for you!
Commentaires et discussions
Nos formations sur ce sujet
Notre expertise est aussi disponible sous forme de formations professionnelles !
Symfony avancée
Découvrez les fonctionnalités et concepts avancés de Symfony
Ces clients ont profité de notre expertise
JoliCode continue d’accompagner les équipes web d’Afflelou en assurant la maintenance des différentes applications constituant la plateforme Web B2C. Nous mettons en place des bonnes pratiques avec PHPStan et Rector, procédons à la montée de version de PHP et Symfony, optimisons le code grâce au profiling, et collaborons avec l’infogéreur pour les…
L’équipe de Finarta a fait appel à JoliCode pour le développement de leur plateforme Web. Basée sur le framework Symfony 2, l’application est un réseau privé de galerie et se veut être une place de communication et de vente d’oeuvres d’art entre ses membres. Pour cela, de nombreuses règles de droits ont été mises en places et une administration poussée…
Notre mission a été particulièrement passionnante car Faume a pris la décision de migrer d’un modèle “agence” vers un modèle “SaaS”. Nous avons été sollicité pour challenger leur architecture actuelle basée sur Symfony et examiner leur feuille de route. Après un audit technique, nous avons identifié les principaux chantiers et scénarios…