Symfony2: Cómo obtener errores de validación de formularios después de vincular la solicitud al formulario

110

Aquí está mi saveActioncódigo (donde el formulario pasa los datos)

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

Mi pregunta es: ¿cómo obtengo los errores si $form->isValid()devuelve false?

putolaruan
fuente

Respuestas:

117

Tienes dos formas posibles de hacerlo:

  • no redirigir al usuario en caso de error y mostrarlo {{ form_errors(form) }}dentro del archivo de plantilla
  • acceder a la matriz de errores como $form->getErrors()
nefo_x
fuente
22
Hice lo segundo que sugirió, pero form-> getErrors () devuelve una matriz en blanco.
putolaruan
2
También hice el primero (w / php templates <? Php echo $ view ['form'] -> errors ($ form)?>) ¡Pero aún está vacío!
putolaruan
59
@mives Debe establecer error_bubblingen verdadero en su tipo de formulario estableciendo explícitamente la opción para todos y cada uno de los campos.
kgilden
5
Si está utilizando validadores personalizados, Symfony no devuelve los errores generados por esos validadores en $ form-> getErrors ().
Jay Sheth
13
También puede $form->getErrors(true)incluir errores de formularios secundarios
Chris
103

Symfony 2.3 / 2.4:

Esta función obtiene todos los errores. Los del formulario como "El token CSRF no es válido. Intente volver a enviar el formulario". así como errores adicionales en los hijos del formulario que no tienen ningún error de propagación.

private function getErrorMessages(\Symfony\Component\Form\Form $form) {
    $errors = array();

    foreach ($form->getErrors() as $key => $error) {
        if ($form->isRoot()) {
            $errors['#'][] = $error->getMessage();
        } else {
            $errors[] = $error->getMessage();
        }
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = $this->getErrorMessages($child);
        }
    }

    return $errors;
}

Para obtener todos los errores como una cadena:

$string = var_export($this->getErrorMessages($form), true);

Symfony 2.5 / 3.0:

$string = (string) $form->getErrors(true, false);

Documentos:
https://github.com/symfony/symfony/blob/master/UPGRADE-2.5.md#form https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md#form (en la parte inferior: The method Form::getErrorsAsString() was removed)

Dar la vuelta
fuente
1
Esta parece la respuesta más correcta para Symfony 2.4 actual.
Slava Fomin II
@Flip it Works perfectamente en 2.5
iarroyo
1
Gran respuesta, pero $errors[$child->getName()] = $this->getErrorMessages($child);estaba lanzando una excepción, ya getErrorMessages le faltaba a Symfony \ Bundle \ FrameworkBundle \ Controller \ Controller componente. Así que lo reemplacé con$form_errors[$child->getName()] = $child->getErrorsAsString();
Ahad Ali
3
@AhadAli es una función recursiva, por lo que cuando coloca el fragmento de código en la clase donde necesita esta funcionalidad, podrá llamarse a sí mismo. Su "solución" le impedirá alcanzar las formas anidadas. Funcionó para otras 37 personas, también debería funcionar para usted;)
Flip
@Flip Ah, lo siento, solo estaba mirando $this->getErrorMessages()y pensé que se llama directamente dentro de un controlador y parte de la api de Symfony.
Ahad Ali
47

A continuación se muestra la solución que funcionó para mí. Esta función está en un controlador y devolverá una matriz estructurada de todos los mensajes de error y el campo que los causó.

Symfony 2.0:

private function getErrorMessages(\Symfony\Component\Form\Form $form) {
    $errors = array();
    foreach ($form->getErrors() as $key => $error) {
        $template = $error->getMessageTemplate();
        $parameters = $error->getMessageParameters();

        foreach($parameters as $var => $value){
            $template = str_replace($var, $value, $template);
        }

        $errors[$key] = $template;
    }
    if ($form->hasChildren()) {
        foreach ($form->getChildren() as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    }

    return $errors;
}

Symfony 2.1 y versiones posteriores:

private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();

    if ($form->hasChildren()) {
        foreach ($form->getChildren() as $child) {
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    } else {
        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }   
    }

    return $errors;
}
Icode4food
fuente
5
Gist.github.com/2011671 mejorado, pero aún no es lo que quiero. Quiero que las claves de matriz sean nombres de campo, pero no lo son.
umpirsky
9
@SalmanPK Twig no se hace referencia en ninguna parte del código anterior. No creo haber entendido tu comentario.
Icode4food
1
Aquí hay una solución para la esencia anterior, esto funciona bajo Symfony 2.1.7. gist.github.com/WishCow/5101428
K. Norbert
Parece que $this->getFormErrorsdebe haber un error tipográfico $this->getErrorMessagesen tu muestra en Symfony2.1
Mick
@umpirsky Para obtener el nombre del campo, obtuve esto: $ child-> getConfig () -> getOptions () ['label'] Me tomó una eternidad averiguarlo ...
jsgoupil
35

Use el Validador para obtener los errores de una entidad específica

if( $form->isValid() )
{
    // ...
}
else
{
    // get a ConstraintViolationList
    $errors = $this->get('validator')->validate( $user );

    $result = '';

    // iterate on it
    foreach( $errors as $error )
    {
        // Do stuff with:
        //   $error->getPropertyPath() : the field that caused the error
        //   $error->getMessage() : the error message
    }
}

Referencia de API:

Olivier 'Ölbaum' Scherler
fuente
Gracias, lo que necesitaba +1
Phill Pafford
4
No estoy seguro de que sea un buen enfoque validar cada entidad por separado. ¿Qué pasa si tienes una forma jerárquica compleja? El segundo problema es que la validación ocurre dos veces.
Slava Fomin II
3
@SlavaFominII - "El segundo problema es que la validación ocurre dos veces" - Buen punto, ¡nada se actualiza! ¡La misma lista de errores después!
BentCoder
20

Para obtener mensajes adecuados (traducibles), actualmente usando SF 2.6.3, aquí está mi función final (ya que ninguna de las anteriores parece funcionar):

 private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();
    foreach ($form->getErrors(true, false) as $error) {
        // My personnal need was to get translatable messages
        // $errors[] = $this->trans($error->current()->getMessage());
        $errors[] = $error->current()->getMessage();
    }

    return $errors;
}

ya que el método Form :: getErrors () ahora devuelve una instancia de FormErrorIterator , a menos que cambie el segundo argumento ($ flatten) a verdadero . (Luego devolverá una instancia de FormError , y tendrá que llamar al método getMessage () directamente, sin el método current ():

 private function getErrorMessages(\Symfony\Component\Form\Form $form) {      
    $errors = array();
    foreach ($form->getErrors(true, true) as $error) {
        // My personnal need was to get translatable messages
        // $errors[] = $this->trans($error->getMessage());
        $errors[] = $error->getMessage();
    }

    return $errors;
}

)

En realidad, lo más importante es establecer el primer argumento en verdadero para obtener los errores. Dejar el segundo argumento ($ flatten) en su valor predeterminado ( verdadero ) devolverá instancias de FormError , mientras que devolverá instancias de FormErrorIterator cuando se establezca en falso.

Cedo
fuente
Bonito, usando el mismo material.
Dañado orgánico
no es :) @KidBinary
Cedo
Absolutamente hermoso, amigo
:)
Una mejor opción es: $ errores = array_map (function ($ item) {return $ item-> current () -> getMessage ();}, $ campaignForm-> getErrors (verdadero, falso));
Enrique Quero
Buena solución para Symfony 2.7
Yann Chabot
16

Por mis mensajes flash con los que estaba feliz $form->getErrorsAsString()

Editar (de Benji_X80): para uso de SF3 $form->getErrors(true, false);

Tjorriemorrie
fuente
3
Sé que es una respuesta antigua, pero para referencia futura: This method should only be used to help debug a form.( fuente )
cheesemacfly
getErrorsAsString () está en desuso en 3.0, use: $ form-> getErrors (true, false);
Benji_X80
15

La función para Symfony 2.1 y versiones posteriores, sin ninguna función obsoleta:

/**
 * @param \Symfony\Component\Form\Form $form
 *
 * @return array
 */
private function getErrorMessages(\Symfony\Component\Form\Form $form)
{
    $errors = array();

    if ($form->count() > 0) {
        foreach ($form->all() as $child) {
            /**
             * @var \Symfony\Component\Form\Form $child
             */
            if (!$child->isValid()) {
                $errors[$child->getName()] = $this->getErrorMessages($child);
            }
        }
    } else {
        /**
         * @var \Symfony\Component\Form\FormError $error
         */
        foreach ($form->getErrors() as $key => $error) {
            $errors[] = $error->getMessage();
        }
    }

    return $errors;
}
stwe
fuente
Iba a publicar una nueva respuesta a esta publicación, pero parecía que me habías vencido. Tuve que revisar el código fuente para averiguar por qué no se encontraron las llamadas al método.
Dr.Knowitall
Me di cuenta de que esto no genera errores de elementos que tienen el burbujeo de errores establecido en verdadero. SF2.4
kinghfb
@stwe ¿cuál es el propósito de la primera IFdeclaración? ¿Por qué es mutuamente excluyente? Por lo que puedo ver: el formulario puede tener sus propios errores, así como los hijos.
Slava Fomin II
4

Mensajes de error de formulario traducidos (Symfony2.1)

He estado luchando mucho para encontrar esta información, así que creo que definitivamente vale la pena agregar una nota sobre la traducción de errores de formulario.

@Icode4foodLa respuesta devolverá todos los errores de un formulario. Sin embargo, la matriz que se devuelve no tiene en cuenta ni la pluralización ni la traducción del mensaje .

Puede modificar el bucle foreach de @Icode4foodrespuesta para tener un combo:

  • Obtener todos los errores de una forma particular
  • Devolver un error traducido
  • Tenga en cuenta la pluralización si es necesario

Aquí está:

foreach ($form->getErrors() as $key => $error) {

   //If the message requires pluralization
    if($error->getMessagePluralization() !== null) {
        $errors[] = $this->container->get('translator')->transChoice(
            $error->getMessage(), 
            $error->getMessagePluralization(), 
            $error->getMessageParameters(), 
            'validators'
            );
    } 
    //Otherwise, we do a classic translation
    else {
        $errors[] = $this->container->get('translator')->trans(
            $error->getMessage(), 
            array(), 
            'validators'
            );
    }
}

Esta respuesta se ha elaborado a partir de 3 publicaciones diferentes:

Mick
fuente
Solo probé tu versión y fue Fatal Error: Call to undefined method Symfony\Component\Form\FormError::getMessagePluralization(). Sospecho que esto es solo para Symfony 2.1.
Czar Pino
4

SYMFONY 3.X

Otros métodos SF 3.X dados aquí no me funcionaron porque podía enviar datos vacíos al formulario (pero tengo restricciones NotNull / NotBlanck). En este caso, la cadena de error se vería así:

string(282) "ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be blank.
ERROR: This value should not be null.
name:
    ERROR: This value should not be blank.
"

Lo cual no es muy útil. Entonces hice esto:

public function buildErrorArray(FormInterface $form)
{
    $errors = [];

    foreach ($form->all() as $child) {
        $errors = array_merge(
            $errors,
            $this->buildErrorArray($child)
        );
    }

    foreach ($form->getErrors() as $error) {
        $errors[$error->getCause()->getPropertyPath()] = $error->getMessage();
    }

    return $errors;
}

Lo que devolvería eso:

array(7) {
  ["data.name"]=>
  string(31) "This value should not be blank."
  ["data.street"]=>
  string(31) "This value should not be blank."
  ["data.zipCode"]=>
  string(31) "This value should not be blank."
  ["data.city"]=>
  string(31) "This value should not be blank."
  ["data.state"]=>
  string(31) "This value should not be blank."
  ["data.countryCode"]=>
  string(31) "This value should not be blank."
  ["data.organization"]=>
  string(30) "This value should not be null."
}
sbouba
fuente
3

También puede utilizar el servicio de validación para obtener infracciones de restricciones:

$errors = $this->get('validator')->validate($user);
antoinet
fuente
6
Esto validará el objeto pero no el formulario. Si, por ejemplo, el token CRSF fue la causa del error, el mensaje no se incluiría.
Icode4food
3

Mensajes de error de formulario traducidos (Symfony2.3)

Mi versión de resolver el problema:

/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);

En Symfony 2.5 puede obtener errores de todos los campos muy fácilmente:

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

Para Symfony 3.2 y superior use esto,

public function buildErrorArray(FormInterface $form)
{
    $errors = array();

    foreach ($form->getErrors() as $key => $error) {
        if ($form->isRoot()) {
            $errors['#'][] = $error->getMessage();
        } else {
            $errors[] = $error->getMessage();
        }
    }

    foreach ($form->all() as $child) {
        if (!$child->isValid()) {
            $errors[$child->getName()] = (string) $child->getErrors(true, false);
        }
    }
    return $errors;
}

Utilice str_replace si desea deshacerse del molesto texto ' Error: ' en cada texto de descripción de error.

$errors[$child->getName()] = str_replace('ERROR:', '', (string) $child->getErrors(true, false));
Anjana Silva
fuente
2

Si está utilizando validadores personalizados, Symfony no devuelve errores generados por esos validadores en $form->getErrors(). $form->getErrorsAsString()devolverá todos los errores que necesite, pero desafortunadamente su salida está formateada como una cadena, no como una matriz.

El método que utilice para obtener todos los errores (independientemente de su procedencia) depende de la versión de Symfony que esté utilizando.

La mayoría de las soluciones sugeridas implican la creación de una función recursiva que escanea todos los formularios secundarios y extrae los errores relevantes en una matriz. Symfony 2.3 no tiene la $form->hasChildren()función, pero la tiene $form->all().

Aquí hay una clase de ayuda para Symfony 2.3, que puede usar para extraer todos los errores de cualquier formulario. (Se basa en el código de un comentario de yapro sobre un ticket de error relacionado en la cuenta de github de Symfony).

namespace MyApp\FormBundle\Helpers;

use Symfony\Component\Form\Form;

class FormErrorHelper
{
    /**
     * Work-around for bug where Symfony (2.3) does not return errors from custom validaters,
     * when you call $form->getErrors().
     * Based on code submitted in a comment here by yapro:
     * https://github.com/symfony/symfony/issues/7205
     *
     * @param Form $form
     * @return array Associative array of all errors
     */
    public function getFormErrors($form)
    {
        $errors = array();

        if ($form instanceof Form) {
            foreach ($form->getErrors() as $error) {
                $errors[] = $error->getMessage();
            }

            foreach ($form->all() as $key => $child) {
                /** @var $child Form */
                if ($err = $this->getFormErrors($child)) {
                    $errors[$key] = $err;
                }
            }
        }

        return $errors;
    }
}

Código de llamada:

namespace MyApp\ABCBundle\Controller;

use MyApp\FormBundle\Helpers;

class MyController extends Controller
{
    public function XYZAction()
    {
        // Create form.

        if (!$form->isValid()) {
            $formErrorHelper = new FormErrorHelper();
            $formErrors = $formErrorHelper->getFormErrors($form);

            // Set error array into twig template here.
        }
    }

}
Jay Sheth
fuente
2

Basado en la respuesta de @Jay Seth, hice una versión de la clase FormErrors especialmente para Ajax Forms:

// src/AppBundle/Form/FormErrors.php
namespace AppBundle\Form;

class FormErrors
{

    /**
     * @param \Symfony\Component\Form\Form $form
     *
     * @return array $errors
     */
    public function getArray(\Symfony\Component\Form\Form $form)
    {
        return $this->getErrors($form, $form->getName());
    }

    /**
     * @param \Symfony\Component\Form\Form $baseForm
     * @param \Symfony\Component\Form\Form $baseFormName
     *
     * @return array $errors
     */
    private function getErrors($baseForm, $baseFormName) {
        $errors = array();
        if ($baseForm instanceof \Symfony\Component\Form\Form) {
            foreach($baseForm->getErrors() as $error) {
                $errors[] = array(
                    "mess"      => $error->getMessage(),
                    "key"       => $baseFormName
                );
            }

            foreach ($baseForm->all() as $key => $child) {
                if(($child instanceof \Symfony\Component\Form\Form)) {
                    $cErrors = $this->getErrors($child, $baseFormName . "_" . $child->getName());
                    $errors = array_merge($errors, $cErrors);
                }
            }
        }
        return $errors;
    }
}

Uso (por ejemplo, en su acción):

$errors = $this->get('form_errors')->getArray($form);

Versión de Symfony: 2.8.4

Ejemplo de respuesta JSON:

{
    "success": false,
    "errors": [{
        "mess": "error_message",
        "key": "RegistrationForm_user_firstname"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_lastname"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_email"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_zipCode"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_user_password_password"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_terms"
    }, {
        "mess": "error_message2",
        "key": "RegistrationForm_terms"
    }, {
        "mess": "error_message",
        "key": "RegistrationForm_marketing"
    }, {
        "mess": "error_message2",
        "key": "RegistrationForm_marketing"
    }]
}

El objeto de error contiene el campo "clave", que es la identificación del elemento DOM de entrada, por lo que puede completar fácilmente los mensajes de error.

Si tiene formularios secundarios dentro del formulario principal, no olvide agregar la cascade_validationopción dentro del formulario principal setDefaults.

Ladrón
fuente
1

Para Symfony 2.1 en adelante para su uso con la visualización de errores de Twig, modifiqué la función para agregar un FormError en lugar de simplemente recuperarlos, de esta manera tienes más control sobre los errores y no tienes que usar error_bubbling en cada entrada individual. Si no lo configura de la siguiente manera, {{form_errors (form)}} permanecerá en blanco:

/**
 * @param \Symfony\Component\Form\Form $form
 *
 * @return void
 */
private function setErrorMessages(\Symfony\Component\Form\Form $form) {      

    if ($form->count() > 0) {
        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                if( isset($this->getErrorMessages($child)[0]) ) {
                    $error = new FormError( $this->getErrorMessages($child)[0] );
                    $form->addError($error);
                }
            }
        }
    }

}
País de las maravillas duro
fuente
1

$ form-> getErrors () funciona para mí.

ahyong
fuente
1

Se me ocurrió esta solución. Funciona perfectamente con el último Symfony 2.4 .

Intentaré dar algunas explicaciones.

Usando un validador separado

Creo que es una mala idea usar una validación separada para validar entidades y devolver mensajes de violación de restricciones, como lo sugirieron otros escritores.

  1. Necesitará validar manualmente todas las entidades, especificar grupos de validación, etc. Con formas jerárquicas complejas no es práctico en absoluto y se les escapará de las manos rápidamente.

  2. De esta manera, estará validando el formulario dos veces: una vez con el formulario y una vez con un validador separado. Esta es una mala idea desde la perspectiva del desempeño.

Sugiero iterar recursivamente el tipo de formulario con sus hijos para recopilar mensajes de error.

Usando algunos métodos sugeridos con declaración IF exclusiva

Algunas respuestas sugeridas por otros autores contienen declaraciones IF mutuamente excluyentes como esta: if ($form->count() > 0)o if ($form->hasChildren()).

Por lo que puedo ver, todos los formularios pueden tener errores al igual que los niños. No soy un experto con el componente Symfony Forms , pero en la práctica no obtendrá algunos errores del formulario en sí, como el error de protección CSRF o el error de campos adicionales . Sugiero eliminar esta separación.

Usando estructura de resultado desnormalizada

Algunos autores sugieren poner todos los errores dentro de una matriz simple. Entonces, todos los mensajes de error del formulario en sí y de sus hijos se agregarán a la misma matriz con diferentes estrategias de indexación: basados ​​en números para los propios errores del tipo y basados ​​en nombres para los errores secundarios. Sugiero utilizar la estructura de datos normalizada del formulario:

errors:
    - "Self error"
    - "Another self error"

children
    - "some_child":
        errors:
            - "Children error"
            - "Another children error"

        children
            - "deeper_child":
                errors:
                    - "Children error"
                    - "Another children error"

    - "another_child":
        errors:
            - "Children error"
            - "Another children error"

De esa manera, el resultado se puede iterar fácilmente más adelante.

Mi solución

Así que aquí está mi solución a este problema:

use Symfony\Component\Form\Form;

/**
 * @param Form $form
 * @return array
 */
protected function getFormErrors(Form $form)
{
    $result = [];

    // No need for further processing if form is valid.
    if ($form->isValid()) {
        return $result;
    }

    // Looking for own errors.
    $errors = $form->getErrors();
    if (count($errors)) {
        $result['errors'] = [];
        foreach ($errors as $error) {
            $result['errors'][] = $error->getMessage();
        }
    }

    // Looking for invalid children and collecting errors recursively.
    if ($form->count()) {
        $childErrors = [];
        foreach ($form->all() as $child) {
            if (!$child->isValid()) {
                $childErrors[$child->getName()] = $this->getFormErrors($child);
            }
        }
        if (count($childErrors)) {
            $result['children'] = $childErrors;
        }
    }

    return $result;
}

Espero que ayude a alguien.

Slava Fomin II
fuente
@weaverryan, ¿puedes echar un vistazo a mi solución, por favor? ¿Es válido o hay inconvenientes o conceptos erróneos? ¡Gracias!
Slava Fomin II
1

SYMFONY 3.1

Simplemente implementé un método estático para manejar la visualización de errores.

static function serializeFormErrors(Form\Form $form)
{
    $errors = array();
    /**
     * @var  $key
     * @var Form\Form $child
     */
    foreach ($form->all() as $key => $child) {
        if (!$child->isValid()) {
            foreach ($child->getErrors() as $error) {
                $errors[$key] = $error->getMessage();
            }
        }
    }

    return $errors;
}

Esperando ayudar

Shigiang Liu
fuente
1

Symfony 3 y más reciente

Recientemente hice una función que crea un árbol de errores de forma. Esto será útil para devolver la lista de errores al front-end. Esto se basa en los tipos de formulario que tienen:

'error_bubbling' => false

Código:

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

Salida:

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.
                )

        )

)

Aviso : Sé que los errores de los campos de nivel más profundo se pueden sobrescribir si el nivel superior tiene errores, pero esto es a propósito para mi uso.

Krzysztof Trzos
fuente
Perfecto para var_dump, gracias
ReaperSoon
0

Para Symfony 2.1:

Esta es mi solución final juntando muchas otras soluciones:

protected function getAllFormErrorMessages($form)
{
    $retval = array();
    foreach ($form->getErrors() as $key => $error) {
        if($error->getMessagePluralization() !== null) {
            $retval['message'] = $this->get('translator')->transChoice(
                $error->getMessage(), 
                $error->getMessagePluralization(), 
                $error->getMessageParameters(), 
                'validators'
            );
        } else {
            $retval['message'] = $this->get('translator')->trans($error->getMessage(), array(), 'validators');
        }
    }
    foreach ($form->all() as $name => $child) {
        $errors = $this->getAllFormErrorMessages($child);
        if (!empty($errors)) {
           $retval[$name] = $errors; 
        }
    }
    return $retval;
}
Fernando PG
fuente