115 votes

Symfony2 : Comment obtenir les erreurs de validation du formulaire après avoir lié la requête au formulaire

Voici mon code saveAction (où le formulaire transmet les données)

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

Ma question est : comment obtenir les erreurs si $form->isValid() renvoie false?

119voto

nefo_x Points 987

Vous avez deux façons possibles de le faire :

  • ne redirigez pas l'utilisateur en cas d'erreur et affichez {{ form_errors(form) }} dans le fichier de modèle
  • accédez au tableau d'erreurs comme $form->getErrors()

24 votes

J'ai fait la deuxième chose que vous avez suggérée mais form->getErrors() renvoie un tableau vide.

2 votes

J'ai également fait le premier (avec des modèles PHP errors($form) ?>) mais il est toujours vide !

59 votes

@mives Vous devez définir error_bubbling sur true dans votre type de formulaire en définissant explicitement l'option pour chaque champ.

105voto

Flip Points 1198

Symfony 2.3 / 2.4 :

Cette fonction récupère toutes les erreurs. Celles du formulaire comme "Le jeton CSRF est invalide. Veuillez essayer de soumettre à nouveau le formulaire." ainsi que les erreurs supplémentaires sur les enfants du formulaire qui n'ont pas de remontée d'erreur.

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

Pour obtenir toutes les erreurs sous forme de chaîne :

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

Symfony 2.5 / 3.0 :

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

Docs:
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 bas : La méthode Form::getErrorsAsString() a été supprimée)

1 votes

Cela ressemble à la réponse la plus correcte pour Symfony 2.4 actuel.

0 votes

@Flip cela fonctionne parfaitement sur 2.5

1 votes

Super réponse MAIS $erreurs[$child->getName()] = $this->getErrorMessages($child); lançait une exception, car la méthode getErrorMessages était manquante dans le composant Symfony\Bundle\FrameworkBundle\Controller\Controller. Je l'ai donc remplacée par $form_errors[$child->getName()] = $child->getErrorsAsString();

47voto

Icode4food Points 3318

Voici la solution qui a fonctionné pour moi. Cette fonction se trouve dans un contrôleur et renverra un tableau structuré de tous les messages d'erreur et du champ qui les a provoqués.

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 et versions ultérieures :

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

5 votes

Amélioré gist.github.com/2011671 mais ce n'est toujours pas ce que je veux. Je veux que les clés du tableau soient les noms des champs, mais ce n'est pas le cas.

9 votes

@SalmanPK Twig n'est référencé nulle part dans le code ci-dessus. Je ne crois pas comprendre votre commentaire.

1 votes

Voici une solution pour le précédent gist, cela fonctionne sous Symfony 2.1.7. gist.github.com/WishCow/5101428

36voto

Utilisez le validateur pour obtenir les erreurs pour une entité spécifique

if( $form->isValid() )
{
    // ...
}
else
{
    // obtenir une liste de violations de contrainte
    $errors = $this->get('validator')->validate( $user );

    $result = '';

    // itérer dessus
    foreach( $errors as $error )
    {
        // Faites quelque chose avec:
        //   $error->getPropertyPath() : le champ qui a causé l'erreur
        //   $error->getMessage() : le message d'erreur
    }
}

Référence API:

5 votes

Je ne suis pas certain que ce soit une bonne approche de valider chaque entité séparément. Et si vous avez un formulaire hiérarchique complexe? Le deuxième problème est que la validation se fait deux fois.

3 votes

@SlavaFominII - "Le deuxième problème est que la validation se produit deux fois" - Bon point, rien ne se rafraîchit! Même liste d'erreurs après!

15voto

stwe Points 538

La fonction pour symfony 2.1 et ultérieur, sans aucune fonction obsolète:

/**
 * @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;
}

0 votes

J'allais poster une nouvelle réponse à ce message, mais vous sembliez m'avoir devancé. J'ai dû regarder le code source pour comprendre pourquoi les appels de méthode n'étaient pas trouvés.

0 votes

J'ai remarqué que cela ne récupère pas les erreurs des éléments dont la propagation des erreurs est activée à true. SF2.4

0 votes

@stwe quel est le but de la première instruction IF? Pourquoi est-elle mutuellement exclusive? Autant que je puisse voir : le formulaire peut avoir ses propres erreurs ainsi que celles des enfants.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X