web-dev-qa-db-fra.com

Symfony2: mon formulaire renvoie false à partir de isValid () mais tableau vide pour getErrors () à partir d'une condition de contrainte unique

J'ai une entité client qui ne dispose que d'un champ Email unique. J'essaie de modifier le courrier électronique d'un client et la validation fonctionne bien. Cependant, j'ai ceci dans mon contrôleur:

public function updateAction(Request $request, $id) {
    $em = $this->getDoctrine()->getManager();

    $entity = $em->getRepository('AcmeDemoBundle:Customer')->find($id);

    if (!$entity) {
        throw $this->createNotFoundException('Unable to find Customer entity.');
    }


    $editForm = $this->createForm(new CustomerType(), $entity);
    $editForm->bind($request);
    if ($editForm->isValid()) {
        $em->persist($entity);
        $em->flush();

        return $this->redirect($this->generateUrl('ticket_result'));
    }
    var_dump($editForm->getErrors());

    return $this->render('AcmeDemoBundle:Customer:edit.html.twig', array(
                'entity' => $entity,
                'edit_form' => $editForm->createView(),
    ));
}

Var_dump renvoie un tableau vide, mais le validateur définit une erreur unique et la fonction $editForm->isValid() renvoie false. Existe-t-il un moyen de vérifier cette erreur spécifique dans le contrôleur lors de la validation, pouvez-vous également expliquer pourquoi il renvoie un tableau d'erreur vide? Fondamentalement, je voudrais fournir l'option "fusion" si cette erreur se produit.

MODIFIER: voici le type de formulaire:

namespace Acme\DemoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class CustomerType extends AbstractType {


    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                ->add('email', 'email', array('required'=>true))
        ;

    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\DemoBundle\Entity\Customer',
            'cascade_validation' => true,
        ));
    }

    public function getName() {
        return 'acme_demobundle_customertype';
    }
}

Et le modèle de brindille:

{% extends 'AcmeDemoBundle::layout.html.twig' %}
{% block body -%}
    <h1>Customer edit</h1>



  <form action="{{ path('customer_update', { 'id': entity.id }) }}" method="post" {{ form_enctype(edit_form) }}>
        <input type="hidden" name="_method" value="PUT" />
        {{ form_widget(edit_form) }}
        <p>
            <button type="submit">Edit</button>
        </p>
    </form>

{% endblock %}

Voici ma validation:

Acme\DemoBundle\Entity\Customer:
    constraints:
      - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: 
          fields: email
          message: "A customer under that email address already exists"

    properties:
        email:
            - Email: ~
15
Boris_bulletdodger

Ok, j'ai trouvé une réponse ici:

Symfony2 formulaire non valide sans erreur

Il s'avère que chaque enfant du formulaire a ses propres erreurs séparées. Quand on fait un var_dump de 

$editForm->getChildren()['email']->getErrors()

Je reçois:

array (size=1)
  0 => 
    object(Symfony\Component\Form\FormError)[531]
      private 'message' => string 'A customer under that email address already exists' (length=50)
      protected 'messageTemplate' => string 'A customer under that email address already exists' (length=50)
      protected 'messageParameters' => 
        array (size=0)
          empty
      protected 'messagePluralization' => null

Je me demande toujours comment déterminer que l'erreur est due à un conflit unique sans analyser la chaîne de message d'erreur. 

4
Boris_bulletdodger

À des fins de débogage, vous pouvez utiliser $form->getErrorsAsString() au lieu de $form->getErrors() si vous utilisez Symfony 2. *

Cité de cette réponse :

$form->getErrorsAsString() ne devrait être utilisé que pour déboguer le formulaire ... it contiendra les erreurs de chaque élément enfant ce qui n'est pas le cas de $ form-> getErrors ().


MISE À JOUR 1:

"Avec les versions Symfony les plus récentes, vous devez utiliser $form->getErrors(true, false);. Le premier paramètre correspond à deep et le second à flatten" (voir le commentaire de @Roubi)

21
Denes Papp

Vous pouvez utiliser error_bubbling sur chaque champ pour masquer l'erreur jusqu'à votre formulaire $.

Sinon, vous pouvez aussi éviter les erreurs

foreach ($children as $child) {
            if ($child->hasErrors()) {
                $vars = $child->createView()->getVars();
                $errors = $child->getErrors();
                foreach ($errors as $error) {
                    $this->allErrors[$vars["name"]][] = $this->convertFormErrorObjToString($error);
                }
            }
}
1
Thomas Bennett

Les solutions suivantes fonctionnent pour moi:

$ form-> getErrors (true)

1
Shadi Akil

Dans Symfony 2.3, vous pouvez utiliser celui-ci:

if ($form->isValid()){
    # Code...
} else {
    foreach ($form->getIterator() as $key => $child) {
        if ($child instanceof Form) {
            foreach ($child->getErrors() as $error) {
                $errors[$key] = $error->getMessage();
            }
        }
    }
}

Cela vous donnera un tableau ($errors) avec les erreurs des enfants.

0
numerogeek

Vous pouvez essayer d'utiliser la fonction dump lorsque le formulaire est soumis et n'est pas valide. Je l'utilise comme ça

if($form->isSubmited() && $form->isValid()){
   //SAVE TO DATABASE AND DO YOUR STUFF
}else if($form->isSubmited()){
  //SUBMITED BUT WITH ERRORS
   dump($form->getErrors(true));
   die();

}

Notez que ceci est uniquement destiné au débogage, il vous montrera votre formulaire, les données qu'il contient et toutes les erreurs que tout champ pourrait avoir . En mode production, vous devez renvoyer l'erreur à la vue et la montrer à l'utilisateur.

0
Miguel Carvajal