Symfony2 : How to get form validation errors after binding the request to the form

Viewed 232012

Here's my saveAction code (where the form passes the data to)

public function saveAction()
{
    $user = OBUser();

    $form = $this->createForm(new OBUserType(), $user);

    if ($this->request->getMethod() == 'POST')
    {
        $form->bindRequest($this->request);
        if ($form->isValid())
            return $this->redirect($this->generateUrl('success_page'));
        else
            return $this->redirect($this->generateUrl('registration_form'));
    } else
        return new Response();
}

My question is: how do I get the errors if $form->isValid() returns false?

21 Answers

Translated Form Error Messages (Symfony2.3)

My version of solving the problem:

/src/Acme/MyBundle/Resources/config/services.yml

services:
    form_errors:
        class: Acme\MyBundle\Form\FormErrors

/src/Acme/MyBundle/Form/FormErrors.php

<?php
namespace Acme\MyBundle\Form;

class FormErrors
{
    public function getArray(\Symfony\Component\Form\Form $form)
    {
        return $this->getErrors($form);
    }

    private function getErrors($form)
    {
        $errors = array();

        if ($form instanceof \Symfony\Component\Form\Form) {

            // соберем ошибки элемента
            foreach ($form->getErrors() as $error) {

                $errors[] = $error->getMessage();
            }

            // пробежимся под дочерним элементам
            foreach ($form->all() as $key => $child) {
                /** @var $child \Symfony\Component\Form\Form */
                if ($err = $this->getErrors($child)) {
                    $errors[$key] = $err;
                }
            }
        }

        return $errors;
    }
}

/src/Acme/MyBundle/Controller/DefaultController.php

$form = $this->createFormBuilder($entity)->getForm();
$form_errors = $this->get('form_errors')->getArray($form);
return new JsonResponse($form_errors);

In Symfony 2.5 you can get all fields errors very easy:

    $errors = array();
    foreach ($form as $fieldName => $formField) {
        foreach ($formField->getErrors(true) as $error) {
            $errors[$fieldName] = $error->getMessage();
        }
    }

Symfony 3 and newer

I recently made a function which creates a tree of form errors. This will be helpful for returning list of errors back to front-end. This is based on form types having:

'error_bubbling' => false

Code:

public static function getFormErrorsTree(FormInterface $form): array
{
    $errors = [];

    if (count($form->getErrors()) > 0) {
        foreach ($form->getErrors() as $error) {
            $errors[] = $error->getMessage();
        }
    } else {
        foreach ($form->all() as $child) {
            $childTree = self::getFormErrorsTree($child);

            if (count($childTree) > 0) {
                $errors[$child->getName()] = $childTree;
            }
        }
    }

    return $errors;
}

Output:

Array
(
    [name] => Array
        (
            [0] => This value is not valid.
        )

    [emails] => Array
        (
            [0] => Array
                (
                    [0] => Given e-mail is not valid.
                    [1] => Given e-mail is not valid #2.
                )
            [1] => Array
                (
                    [0] => Given e-mail is not valid.
                    [1] => Given e-mail is not valid #2.
                )

        )

)

Notice: I know that errors from deeper level fields can be overwritten if higher level has errors, but this is on purpose for my usage.

For Symfony 5 I got this working :

public function getErrorMessages(Form $form) {
  
    $errors = [];        

    foreach ($form->all() as $child) {
        foreach ($child->getErrors() as $error) {
                $name = $child->getName();
                $errors[$name] = $error->getMessage();
        }
    }

    return $errors;
}

I got this kind of JSON thing with it :

errors: {
    firstname: "The firstname must be between 2 and 30 characters long.",
    lastname: "The lastname must be between 2 and 40 characters long."
    subject: "Please choose a subject."
    text: "Empty messages are not allowed."
}

It's nice and sweet enough for me, but I guess it will not pick up errors at the global level, like timed out tokens or other stuff like that. Anyway, I've been quite a bit longtime looking for a solution suiting my case, and I'm happy contributing here hoping it'll help some developer somewhere sometime somehow.

Related