Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony3] Formulaire Imbriqué

Sujet résolu
    19 janvier 2018 à 16:56:21

    Bonjour,

    Je viens vers vous pour un problème rencontré sous symfony3. en effet, mon objectif est de réalisé un formulaire imbriqué entre 2 entités.

    Tout d'abord, j'ai une entité DemandeAbsence et ServiceNonAssure avec des propriétés dans chacune d'entre elles.

    Ensuite, j'ai une relation OneToMany qui va de DemandeAbsence vers ServiceNonAssure

    Entité DemandeAbsence:

        /**
         *
         * @Assert\Valid()
         * @Assert\Type(type="SequoiaBundle\Entity\ServiceNonAssure")
         *
         * @ORM\OneToMany(targetEntity="SequoiaBundle\Entity\ServiceNonAssure", mappedBy="demandeAbsence")
         * @ORM\JoinColumn(nullable=false)
         *
         */
        private $serviceNonAssures;

    Entité ServiceNonAssure:

        /**
         * @Assert\NotBlank(message="veuillez remplir ce champ ")
         * @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\DemandeAbsence", inversedBy="demandeAbsence", cascade={"persist"})
         * @ORM\JoinColumn(nullable=true)
         */
        private $demandeAbsence;

    Une fois cela réalisé, je génère mon formulaire depuis DemandeAbsence sous la forme de DemandeAbsenceType ,ainsi que celui pour ServiceNonAssure (ServiceNonAssureType).

    Je commence par le formulaire qui sera ensuite imbriqué dans DemandeAbsenceType 

    ServiceNonAssureType:

    class ServiceNonAssureType extends AbstractType
    {
        /**
         * {@inheritdoc}
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('dateServiceNonAssure', DateTimeType::class);
        }/**
         * {@inheritdoc}
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => ServiceNonAssure::class,
    
            ));
        }
    
        /**
         * {@inheritdoc}
         */
        public function getBlockPrefix()
        {
            return 'sequoiabundle_servicenonassure';
        }
    
    
    }
    

     et du coup maintenant celui de DemandeAbsenceType:

    public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
    
                ->add('document', EntityType::class, array('class' => 'SequoiaBundle:Document', 'choice_label' =>   'nomLong', 'multiple' => false ))
                ->add('dateSaisie', DateType::class, array('required' => true, 'label' => 'Fait le : '))
                ->add('absenceDebut', DateType::class, array('label' => 'A partir du'))
                ->add('absenceFin', DateType::class, array('label' => 'Jusqu\'au'))
                ->add('motif')
                ->add('serviceNonAssures', ServiceNonAssureType::class);
            $builder->add('Envoyer', SubmitType::class);
    
    
    
        }

    comme vous pouvez le voir j'ai rajouter le champ serviceNonAssure qui a pour type mon ServiceNonAssureType. Le problème désomais c'est quand je génére ma vue qui fonctionnement correctement , symfony me génère une erreur que voiçi.

    The form's view data is expected to be an instance of class SequoiaBundle\Entity\ServiceNonAssure, but is an instance of class Doctrine\Common\Collections\ArrayCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\Common\Collections\ArrayCollection to an instance of SequoiaBundle\Entity\ServiceNonAssure.


    Merci d'avance pour vos réponses :)






    • Partager sur Facebook
    • Partager sur Twitter
      19 janvier 2018 à 17:11:47

      Salut !

      Tu as une One((DemandeAbsence)ToMany(ServiceNonAssure), donc effectivement il te faudra probablement un CollectionType de ServiceNonAssureType au lieu d'un seul et unique ServiceNonAssureType.

      • Partager sur Facebook
      • Partager sur Twitter
        19 janvier 2018 à 17:37:27

        Pas mieux que Ymox :

        ->add('serviceNonAssures', CollectionType::class, array(
            'entry_type' => serviceNonAssuresType::class,
            'required' => false, 
            'allow_add'    => true,
            'allow_delete' => true,
            'by_reference' => false,
            'label' => false
        ))

        Pour le détail de chaque option, je te renvoie vers la doc officielle : http://symfony.com/doc/3.4/form/form_collections.html



        • Partager sur Facebook
        • Partager sur Twitter
          19 janvier 2018 à 18:20:51

          Merci de vos réponses :) 

          cependant le problème persiste :/

          modification réaliser au formulaire :

                  $builder
          
                      ->add('document', EntityType::class, array('class' => 'SequoiaBundle:Document', 'choice_label' =>   'nomLong', 'multiple' => false ))
                      ->add('dateSaisie', DateType::class, array('required' => true, 'label' => 'Fait le : '))
                      ->add('absenceDebut', DateType::class, array('label' => 'A partir du'))
                      ->add('absenceFin', DateType::class, array('label' => 'Jusqu\'au'))
                      ->add('motif')
                      ->add('serviceNonAssures', CollectionType::class, array('entry_type' => ServiceNonAssureType::class, 'required' => false, 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false , 'label' => false));
                  $builder->add('Envoyer', SubmitType::class);

          quand je soumet le formulaire plus cette erreur mais symfony me retourne une alerte au niveau du rendu :

          This value should be of type SequoiaBundle\Entity\ServiceNonAssure.
          veuillez remplir ce champ

          Comme si je n'avais pas préciser l'entité du formulaire à imbriquer :/


          -
          Edité par doctor50 19 janvier 2018 à 18:21:23

          • Partager sur Facebook
          • Partager sur Twitter
            19 janvier 2018 à 19:07:44

            Dans ton entité serviceNonAssure tu as cette relation ManyToOne

            @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\DemandeAbsence", inversedBy="demandeAbsence", cascade={"persist"})

            Tu as un champs "demandeAbsence" dans ton entité demandeAbsence ? Ce ne serait pas plutôt

            @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\DemandeAbsence", inversedBy="serviceNonAssures", cascade={"persist"})

            Il semble qu'il y a une erreur dans ton inversedBy... à vérifier.



            • Partager sur Facebook
            • Partager sur Twitter
              19 janvier 2018 à 19:27:25

              En effet , une erreur de relation était présente mais toujours le meme problème :/

              • Partager sur Facebook
              • Partager sur Twitter
                19 janvier 2018 à 19:34:30

                Essai de supprimer ta contrainte de validation, pour voir si ça ne viendrait pas de là

                @Assert\Type(type="SequoiaBundle\Entity\ServiceNonAssure")



                • Partager sur Facebook
                • Partager sur Twitter
                  19 janvier 2018 à 20:51:09

                  cette modification ne résous pas le problème :/

                  • Partager sur Facebook
                  • Partager sur Twitter
                    20 janvier 2018 à 2:30:36

                    Peux-tu nous partager tes deux entités ? Parce qu'à ce point je ne vois pas où est le problème...
                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 janvier 2018 à 11:42:22

                      Entité DemandeAbsence:

                      <?php
                      
                      namespace SequoiaBundle\Entity;
                      
                      use Doctrine\ORM\Mapping as ORM;
                      use Symfony\Component\Validator\Constraints as Assert;
                      
                      /**
                       * DemandeAbsence
                       *
                       * @ORM\Table(name="demande_absence")
                       * @ORM\Entity(repositoryClass="SequoiaBundle\Repository\DemandeAbsenceRepository")
                       */
                      class DemandeAbsence extends Formulaire
                      {
                      
                      
                      
                          /**
                           * @var \DateTime
                           *
                           * @ORM\Column(name="absenceDebut",type="date")
                           */
                          private $absenceDebut;
                      
                          /**
                           * @var string
                           *
                           * @ORM\Column(name="absenceFin",type="date")
                           */
                          private $absenceFin;
                      
                          /**
                           * @var string
                           *
                           * @ORM\Column(name="motif", type="string", length=100)
                           */
                          private $motif;
                      
                      
                          /**
                           *
                           * @Assert\Valid()
                           * @Assert\Type(type="SequoiaBundle\Entity\ServiceNonAssure")
                           *
                           * @ORM\OneToMany(targetEntity="SequoiaBundle\Entity\ServiceNonAssure", mappedBy="demandeAbsence", orphanRemoval=true, cascade="all")
                           * @ORM\JoinColumn(nullable=false)
                           *
                           */
                          private $serviceNonAssures;
                      
                          /**
                           * @ORM\OneToMany(targetEntity="SequoiaBundle\Entity\Recuperation", mappedBy="recuperation")
                           * @ORM\JoinColumn(nullable=false)
                           */
                          private $recuperations;
                      
                      
                      
                      
                      
                      
                          /**
                           * Set absenceDebut
                           *
                           * @param \DateTime $absenceDebut
                           *
                           * @return DemandeAbsence
                           */
                          public function setAbsenceDebut($absenceDebut)
                          {
                              $this->absenceDebut = $absenceDebut;
                      
                              return $this;
                          }
                      
                          /**
                           * Get absenceDebut
                           *
                           * @return \DateTime
                           */
                          public function getAbsenceDebut()
                          {
                              return $this->absenceDebut;
                          }
                      
                          /**
                           * Set absenceFin
                           *
                           * @param \DateTime $absenceFin
                           *
                           * @return DemandeAbsence
                           */
                          public function setAbsenceFin($absenceFin)
                          {
                              $this->absenceFin = $absenceFin;
                      
                              return $this;
                          }
                      
                          /**
                           * Get absenceFin
                           *
                           * @return \DateTime
                           */
                          public function getAbsenceFin()
                          {
                              return $this->absenceFin;
                          }
                      
                          /**
                           * Set motif
                           *
                           * @param string $motif
                           *
                           * @return DemandeAbsence
                           */
                          public function setMotif($motif)
                          {
                              $this->motif = $motif;
                      
                              return $this;
                          }
                      
                          /**
                           * Get motif
                           *
                           * @return string
                           */
                          public function getMotif()
                          {
                              return $this->motif;
                          }
                      
                          /**
                           * Add serviceNonAssure
                           *
                           * @param \SequoiaBundle\Entity\ServiceNonAssure $serviceNonAssure
                           *
                           * @return DemandeAbsence
                           */
                          public function addServiceNonAssure(\SequoiaBundle\Entity\ServiceNonAssure $serviceNonAssure)
                          {
                              $this->serviceNonAssures[] = $serviceNonAssure;
                      
                              return $this;
                          }
                      
                          /**
                           * Remove serviceNonAssure
                           *
                           * @param \SequoiaBundle\Entity\ServiceNonAssure $serviceNonAssure
                           */
                          public function removeServiceNonAssure(\SequoiaBundle\Entity\ServiceNonAssure $serviceNonAssure)
                          {
                              $this->serviceNonAssures->removeElement($serviceNonAssure);
                          }
                      
                          /**
                           * Get serviceNonAssures
                           *
                           * @return \Doctrine\Common\Collections\Collection
                           */
                          public function getServiceNonAssures()
                          {
                              return $this->serviceNonAssures;
                          }
                      
                          /**
                           * Add recuperation
                           *
                           * @param \SequoiaBundle\Entity\Recuperation $recuperation
                           *
                           * @return DemandeAbsence
                           */
                          public function addRecuperation(\SequoiaBundle\Entity\Recuperation $recuperation)
                          {
                              $this->recuperations[] = $recuperation;
                      
                              return $this;
                          }
                      
                          /**
                           * Remove recuperation
                           *
                           * @param \SequoiaBundle\Entity\Recuperation $recuperation
                           */
                          public function removeRecuperation(\SequoiaBundle\Entity\Recuperation $recuperation)
                          {
                              $this->recuperations->removeElement($recuperation);
                          }
                      
                          /**
                           * Get recuperations
                           *
                           * @return \Doctrine\Common\Collections\Collection
                           */
                          public function getRecuperations()
                          {
                              return $this->recuperations;
                          }
                      }
                      

                      DemandeAbsenceController:

                      <?php
                      
                      namespace SequoiaBundle\Controller;
                      
                      use SequoiaBundle\Entity\DemandeAbsence;
                      use SequoiaBundle\Form\DemandeAbsenceType;
                      use Symfony\Bundle\FrameworkBundle\Controller\Controller;
                      use Symfony\Component\BrowserKit\Response;
                      use Symfony\Component\HttpFoundation\Request;
                      use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
                      
                      
                      class DemandeAbsenceController extends Controller
                      {
                          public function ajouterAction(Request $request)
                          {
                              $uneDemandeAbsence = new DemandeAbsence();
                              $form = $this->get('form.factory')->create(DemandeAbsenceType::class, $uneDemandeAbsence);
                      
                              if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()){
                                  $em = $this->getDoctrine()->getManager();
                                  $em->persist($uneDemandeAbsence);
                                  $em->flush();
                      
                                  return $this->render('@Sequoia/DemandeAbsence/consulter.html.twig', array('pDemandeAbsence' => $uneDemandeAbsence));
                              }
                              return $this->render('@Sequoia/DemandeAbsence/ajouter.html.twig', array('form' => $form->CreateView()));
                          }
                      
                      
                      
                      
                      }
                      




                      Entité ServiceNonAssure:

                      <?php
                      
                      namespace SequoiaBundle\Entity;
                      
                      use Doctrine\ORM\Mapping as ORM;
                      use Symfony\Component\Validator\Constraints as Assert;
                      
                      /**
                       * ServiceNonAssure
                       *
                       * @ORM\Table(name="service_non_assure")
                       * @ORM\Entity(repositoryClass="SequoiaBundle\Repository\ServiceNonAssureRepository")
                       */
                      class ServiceNonAssure
                      {
                          /**
                           * @var int
                           *
                           * @ORM\Column(name="id", type="integer")
                           * @ORM\Id
                           * @ORM\GeneratedValue(strategy="AUTO")
                           */
                          private $id;
                      
                          /**
                           * @var \DateTime
                           *
                           * @ORM\Column(name="dateServiceNonAssure", type="datetime")
                           *
                           *
                           */
                          private $dateServiceNonAssure;
                      
                          /**
                           * @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\Classe", inversedBy="classe")
                           * @ORM\JoinColumn(nullable=true)
                           */
                          private $classe;
                      
                          /**
                           * @Assert\NotBlank(message="veuillez remplir ce champ")
                           * @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\DemandeAbsence", inversedBy="serviceNonAssures", cascade={"persist"})
                           * @ORM\JoinColumn(nullable=true)
                           */
                          private $demandeAbsence;
                      
                      
                      
                         
                      
                          /**
                           * Get id
                           *
                           * @return integer
                           */
                          public function getId()
                          {
                              return $this->id;
                          }
                      
                          /**
                           * Set dateServiceNonAssure
                           *
                           * @param \DateTime $dateServiceNonAssure
                           *
                           * @return ServiceNonAssure
                           */
                          public function setDateServiceNonAssure($dateServiceNonAssure)
                          {
                              $this->dateServiceNonAssure = $dateServiceNonAssure;
                      
                              return $this;
                          }
                      
                          /**
                           * Get dateServiceNonAssure
                           *
                           * @return \DateTime
                           */
                          public function getDateServiceNonAssure()
                          {
                              return $this->dateServiceNonAssure;
                          }
                      
                          /**
                           * Set classe
                           *
                           * @param \SequoiaBundle\Entity\Classe $classe
                           *
                           * @return ServiceNonAssure
                           */
                          public function setClasse(\SequoiaBundle\Entity\Classe $classe = null)
                          {
                              $this->classe = $classe;
                      
                              return $this;
                          }
                      
                          /**
                           * Get classe
                           *
                           * @return \SequoiaBundle\Entity\Classe
                           */
                          public function getClasse()
                          {
                              return $this->classe;
                          }
                      
                          /**
                           * Set demandeAbsence
                           *
                           * @param \SequoiaBundle\Entity\DemandeAbsence $demandeAbsence
                           *
                           * @return ServiceNonAssure
                           */
                          public function setDemandeAbsence(\SequoiaBundle\Entity\DemandeAbsence $demandeAbsence = null)
                          {
                              $this->demandeAbsence = $demandeAbsence;
                      
                              return $this;
                          }
                      
                          /**
                           * Get demandeAbsence
                           *
                           * @return \SequoiaBundle\Entity\DemandeAbsence
                           */
                          public function getDemandeAbsence()
                          {
                              return $this->demandeAbsence;
                          }
                      }
                      • Mon but est de finalement ajouter plusieurs date de service non assure au formulaire DemandeAbsence :)

                      -
                      Edité par doctor50 20 janvier 2018 à 12:42:16

                      • Partager sur Facebook
                      • Partager sur Twitter
                        21 janvier 2018 à 0:48:58

                        Je ne vois pas d'où vient le problème, rien ne m'a sauté aux yeux dans tes entités. Les formulaires semblent OK également... « et pourtant elle ne tourne pas »
                        • Partager sur Facebook
                        • Partager sur Twitter
                          21 janvier 2018 à 10:29:45

                          Le souci ne viendrait pas de ce que la propriété DemandeAbsence#serviceNonAssures n'est effectivement pas de type ServiceNonAssure parce qu'il s'agit d'une OneToMany, donc devrait être une collection ?

                          • Partager sur Facebook
                          • Partager sur Twitter
                            21 janvier 2018 à 11:11:17

                            Un autre problème de relation dans ton entité ServiceNonAssuré

                            /**
                             * @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\Classe", inversedBy="classe")
                             * @ORM\JoinColumn(nullable=true)
                             */
                             private $classe;

                            Dans ton entité Classe tu devrais avoir une relation OneToMany vers ServiceNonAssure ($serviceNonAssures). Du coup ta relation dans ServiceNonAssure a un mauvais inversedBy. Ce devrait être

                            * @ORM\ManyToOne(targetEntity="SequoiaBundle\Entity\Classe", inversedBy="ServiceNonAssures")

                            Dans ton entité DemandeAbsence, il faut aussi que tu modifies ta fonction

                            public function addServiceNonAssure(\SequoiaBundle\Entity\ServiceNonAssure $serviceNonAssure)
                            {
                                $this->serviceNonAssures[] = $serviceNonAssure;
                             
                                return $this;
                            }

                            en ajoutant l'enregistrement de l'entité inverse

                                public function addServiceNonAssure(\SequoiaBundle\Entity\ServiceNonAssure $serviceNonAssure)
                                {
                                    $this->serviceNonAssures[] = $serviceNonAssure;
                                    $serviceNonAssure->setDemandeAbsence($this);
                                    return $this;
                                }

                            C'est nécessaire lorsque l'option by_reference = false, ce qui est le cas lorsqu'on utilise collectionType::class avec allow_add = true

                            -
                            Edité par HarvestR 21 janvier 2018 à 11:22:30

                            • Partager sur Facebook
                            • Partager sur Twitter
                              21 janvier 2018 à 15:16:29

                              Merci encore de vos réponses.

                              Du coup, j'ai modifié les erreurs que j'avais réalisé.

                              Je ne peux toujours pas adapter le système car mon champ est invisible. Du coup j'ai regardé le tutorial de Alexandre Bacco ici:

                              https://openclassrooms.com/courses/developpez-votre-site-web-avec-le-framework-symfony/creer-des-formulaires-avec-symfony

                              j'ai alors un système qui permet d'ajouter les dates (ce qui est déjà une bonne chose). le problème maintenant est lors de la validation (je valide rien en bdd). j'ai alors regarder dans le profiler de symfony et il me retourne : 

                              ConstraintViolation {#1179 ▼
                                -message: "This value should be of type SequoiaBundle\Entity\ServiceNonAssure."



                              • Partager sur Facebook
                              • Partager sur Twitter
                                21 janvier 2018 à 15:30:17

                                C'est parce que ta contrainte de validation est fausse, tu n'attends pas une entité ServiceNonAssure, mais une collection d'entités ServiceNonAssure.

                                On en revient au même problème déjà évoqué, un soucis de constraint.

                                @Assert\Type(type="SequoiaBundle\Entity\ServiceNonAssure")

                                Regarde ICI pour les contraintes touchant aux collections.

                                -
                                Edité par HarvestR 21 janvier 2018 à 15:36:01

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  21 janvier 2018 à 15:39:04

                                  En effet en supprimant le @Assert\Type les données en base sont envoyés. j'ai plus qu'a recuperer ma liste de classe et le problème est integralement résolu.

                                  Un grand merci à toi et a Ymox également :)

                                  -
                                  Edité par doctor50 21 janvier 2018 à 16:31:19

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    21 janvier 2018 à 16:09:48

                                    Avec plaisir, n'oublie pas de mettre ce sujet en résolu (bouton en haut de la page) ;)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      21 janvier 2018 à 17:29:21

                                      Juste avant de mettre le sujet en résolu, quand je veux récupérer ma liste de classe (relation ManyToOne entre serviceNonAssure et Classe), je vois bien ma liste et je peux choisir la classe mais au moment de la validation, symfony m'indique :

                                      Expected argument of type "SequoiaBundle\Entity\Classe", "Doctrine\Common\Collections\ArrayCollection" given

                                      Le truc que je comprend pas c'est qu'il me demande de lui retourner un liste alors qu'en réaliter une seule Classe peut être assigné à un serviceNonAssure

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        22 janvier 2018 à 3:31:48

                                        Non, il reçoit une liste alors qu'il attend une entité (c'est le contraire en fait)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          22 janvier 2018 à 8:52:31

                                          Depuis ServiceNonAssure je fais ce forumlaire çi. j'arrive toujours pas à voir poourquoi je lui passe une collection alors que je lui passe un type Entity:

                                              public function buildForm(FormBuilderInterface $builder, array $options)
                                              {
                                                  $builder
                                                      ->add('dateServiceNonAssure' , DateType::class)
                                                      ->add('classe', EntityType::class, array('class' => 'SequoiaBundle\Entity\Classe', 'choice_label' => 'libelleClasse', 'multiple' => 'false'))
                                                  ;
                                          
                                          
                                              }

                                          Relation ManyToOne (ServiceNonAssure vers Classe)

                                          -
                                          Edité par doctor50 22 janvier 2018 à 19:20:15

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            23 janvier 2018 à 0:02:37

                                            En gros imbriqué une EntityType dans une ColectionType :)

                                            -
                                            Edité par doctor50 23 janvier 2018 à 0:17:34

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              23 janvier 2018 à 14:19:42

                                              C'est ça. au final, tu obtiens une collection d'entités, comme l'attend DemandeAbsence dans ce champs :

                                                  /**
                                                   *
                                                   * @Assert\Valid()
                                                   * @Assert\Type(type="SequoiaBundle\Entity\ServiceNonAssure")
                                                   *
                                                   * @ORM\OneToMany(targetEntity="SequoiaBundle\Entity\ServiceNonAssure", mappedBy="demandeAbsence", orphanRemoval=true, cascade="all")
                                                   * @ORM\JoinColumn(nullable=false)
                                                   *
                                                   */
                                                  private $serviceNonAssures;



                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                23 janvier 2018 à 19:17:12

                                                Merci , je vous embêtes plus ^^
                                                • Partager sur Facebook
                                                • Partager sur Twitter

                                                [Symfony3] Formulaire Imbriqué

                                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                • Editeur
                                                • Markdown