Partage
  • Partager sur Facebook
  • Partager sur Twitter

Symfony ManyToMany with attributes

Sujet résolu
    21 septembre 2022 à 13:50:10

    Bonjour,

    J'essaye tant bien que mal de rattacher les modules d'un partenaire sur mon entité PartenaireModule mais je n'y parviens pas puisqu'il faut qu'il crée autant de relation qu'il y aura de modules associés. 

    Un partenaire a plusieurs modules et un module appartient a plusieurs partenaires.

    D'ou cette table intermédiaire : PartenaireModule. Je comprends qu'il s'agit certainement d'un problème dans mes entités mais je ne parviens pas à le corriger. Voici mes entités ainsi que mon formulaire. Je précise que lorsque je mets "multiple" => false ça fonctionne bien.


    Mon erreur :

    Expected argument of type "?App\Entity\Module", "Doctrine\Common\Collections\ArrayCollection" given at property path "modules".


    Mon entité Module : 

    #[ORM\Entity(repositoryClass: ModuleRepository::class)]
    class Module
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
    
        #[ORM\Column(length: 250)]
        private ?string $nom = null;
    
        #[ORM\Column]
        private ?bool $statut = null;
    
        #[ORM\OneToMany(mappedBy: 'Modules', targetEntity: PartenaireModule::class)]
        private Collection $partenaireModules;
    
        public function __construct()
        {
            $this->partenaireModules = new ArrayCollection();
        }


    Mon entité PartenaireModule : 

    #[ORM\Entity(repositoryClass: PartenaireModuleRepository::class)]
    class PartenaireModule
    {
        #[ORM\Id]
        #[ORM\GeneratedValue]
        #[ORM\Column]
        private ?int $id = null;
    
        #[ORM\Column]
        private ?bool $is_active = true;
    
        #[ORM\ManyToOne(inversedBy: 'partenaireModules')]
        private ?Partenaire $Partenaires = null;
    
        #[ORM\ManyToOne(inversedBy: 'partenaireModules')]
        private ?Module $Modules = null;
    


    Voici comment mes données devraient être mappées dans la table PartenaireModule:


    -> module_id, partenaire_id, is_active, id


    Toute aide ou piste pour m'aider sera la bienvenue :)

    Merci



    -
    Edité par MarineBoidé 26 septembre 2022 à 15:37:38

    • Partager sur Facebook
    • Partager sur Twitter
      23 septembre 2022 à 15:33:29

      personne pour m'éclairer sur le sujet ?
      • Partager sur Facebook
      • Partager sur Twitter
        24 septembre 2022 à 12:37:59

        Bonjour,

        Le hasard car je passais par là ! Pour ce genre de questions, tu dois utiliser le forum php. Demande au modérateur de déplacer ton sujet.

        Précise aussi ta version de Symfony.

        Tu indiques des relations ManyToMany mais dans ton code on ne les voit pas : il n'y a que des ManyToOne ou inverse ? donc effectivement problème ... ou alors tu veux faire une relation ManyToMany avec attribut qui serait $is_active. Ce qui me semble bizarre c'est que tu n'as pas dans ce cas le targetEntity dans chaque relation ManyToOne ?

        As tu utilisé le maker bundle pour créer tes entités ? c'est le plus simple en suivant les indications.

        A+

        -
        Edité par monkey3d 25 septembre 2022 à 7:18:09

        • Partager sur Facebook
        • Partager sur Twitter
          24 septembre 2022 à 17:36:23

          Bonjour,

          Déplacement vers un forum plus approprié

          Le sujet est déplacé de la section Let's talk! vers la section PHP

          • Partager sur Facebook
          • Partager sur Twitter
            24 septembre 2022 à 23:58:20

            Salut

            Ce que tu mentionnes me fait penser à une ManyToMany avec attribut, ce qui en ferait une "OneToManyToOne".

            A mon avis, je te propose de regarder du côté de CollectionType. Comme tu le montres et d'après le code, un Module peut avoir plusieurs PartenaireModule, mais chacun de ceux-ci n'ont qu'un Partenaire. Donc une collection de PartenaireModule, au niveau du formulaire de Module (comme de Partenaire si jamais).

            • Partager sur Facebook
            • Partager sur Twitter
              26 septembre 2022 à 15:32:09

              Bonjour à tous,

              Merci d'avoir pris le temps de me répondre et d'avoir déplacé ma question ! 

              @Monkey3d effectivement ce que je souhaite mettre en place ce sont des relations manytomany avec attributs.

              J'ai bien utilisé le makerbundle pour mettre en place mes relations.

              De ce que je comprends il devrait y avoir des targetEntity également du côté ManyToOne?

              @Ymox yes j'ai essayé d'implémenter cette notion de Collection dans le formulaire de l'ajout du partenaire en incluant donc le formulaire du PartenaireModule. Je partage un peu plus de code pour illustrer mes propos.

              C'est d'ailleurs cette implémentation de la collection dans le formulaire qui me donne cette erreur.

              Mon formulaire de création Partenaire:

              namespace App\Form;
              
              use App\Entity\Partenaire;
              use Symfony\Component\Form\AbstractType;
              use Symfony\Component\Form\Extension\Core\Type\CollectionType;
              use Symfony\Component\Form\Extension\Core\Type\SubmitType;
              use Symfony\Component\Form\FormBuilderInterface;
              use Symfony\Component\OptionsResolver\OptionsResolver;
              
              
              
              class PartenaireType extends AbstractType
              {
                  public function buildForm(FormBuilderInterface $builder, array $options): void
                  {
                      $builder
                          ->add('nom')
                          ->add('statut')
                          ->add('partenaireModules', CollectionType::class, [
                              'entry_type' => PartenaireModuleType::class,
                              'by_reference' => false,
                              'allow_add' => true,
                              'allow_delete' => true,
                          ])
                          //->add('modules', EntityType::class, [
                          //    'class' => Modules::class,
                          //    'choice_label' => 'nom',
                          //    'label' => 'Modules par défaut',
                          //    'expanded' => true,
                          //    'multiple' => true,
                          //    'property_path' => PartenairesModules::class,
                           //])
                           ;
                  }
              
                  public function configureOptions(OptionsResolver $resolver): void
                  {
                      $resolver->setDefaults([
                          'data_class' => Partenaire::class,
                      ]);
                  }
              }


              Mon formulaire PartenaireModule : 

              namespace App\Form;
              
              use App\Entity\PartenaireModule;
              use Symfony\Component\Form\AbstractType;
              use Symfony\Component\Form\FormBuilderInterface;
              use Symfony\Component\OptionsResolver\OptionsResolver;
              use Symfony\Bridge\Doctrine\Form\Type\EntityType;
              use App\Entity\Module;
              
              class PartenaireModuleType extends AbstractType
              {
                  public function buildForm(FormBuilderInterface $builder, array $options): void
                  {
                      $builder
                          ->add('modules', EntityType::class, [
                                'class' => Module::class,
                                'choice_label' => 'nom',
                                'label' => 'Modules par défaut',
                                'expanded' => true,
                                'multiple' => true,
                               ])
                      ;
                  }
              
                  public function configureOptions(OptionsResolver $resolver): void
                  {
                      $resolver->setDefaults([
                          'data_class' => PartenaireModule::class,
                      ]);
                  }
              }

              J'avoue que je désespère un peu je lis et je relis les docs mais surement que je dois passer à côté de quelque chose d'important.

              Ou bien c'est dans ma vue qu'il y a un problème. Je sais plus ou chercher :) 

              Si vous repassez par là ce serait top merciii 

              • Partager sur Facebook
              • Partager sur Twitter
                26 septembre 2022 à 15:40:00

                monkey3d a écrit:

                Tu peux ajouter des targetEntity ? 

                cf la doc : https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/association-mapping.html

                A+


                Toujours cette même erreur : 

                Expected argument of type "?App\Entity\Module", "Doctrine\Common\Collections\ArrayCollection" given at property path "module".

                Je vous passe ma vue tout de même voir si c'est cohérent avec ce que je veux faire : 

                {{ form_start(form) }}
                    {{ form_row(form.nom) }}
                    {{ form_row(form.statut) }}
                    {{ (dump(form.partenaireModules.vars.prototype.module)) }}
                   {{ form_row(form.partenaireModules.vars.prototype.module) }}
                    {{ form_row(form.partenaireModules) }}
                    
                
                
                    
                    <button class="btn">{{ button_label|default('Save') }}</button>
                {{ form_end(form) }}



                -
                Edité par MarineBoidé 26 septembre 2022 à 16:15:09

                • Partager sur Facebook
                • Partager sur Twitter
                  26 septembre 2022 à 17:16:56

                  Si je comprends bien tu as un array collection pour module donc tu devrais faire une boucle :

                  https://symfony.com/doc/current/form/form_collections.html

                  A+

                  • Partager sur Facebook
                  • Partager sur Twitter
                    26 septembre 2022 à 22:02:00

                    Je n'avais pas fait assez attention.

                    Le souci est que dans PartenaireModuleType, tu as mis le champ modules au pluriel et tu permets de lui mettre plusieurs valeurs. Or, un seul objet PartenaireModule ne permet de ne créer qu'une paire de Partenaire avec un unique Module, c'est le fait qu'un Partenaire et/ou qu'un Module puissent chacun avoir plusieurs PartenaireModule qui permet ainsi cette "OneToManyToOne". Explicité un peu autrement, on a donc One(Partenaire)ToMany(PartenaireModule), One(Module)ToMany(PartenaireModule), ainsi que Many(PartenaireModule)ToOne(Partenaire) et Many(PartenaireModule)ToOne(Module).

                    Les relations partant de PartenaireModule étant bien des ManyToOne, les propriétés modules et Partenaires de PartenaireModule n'ont pas de raison d'être au pluriel et les champs de formulaires n'ont pas de raison d'avoir 'multiple' => true.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      26 septembre 2022 à 22:28:03

                      Ymox a écrit:

                      Je n'avais pas fait assez attention.

                      Le souci est que dans PartenaireModuleType, tu as mis le champ modules au pluriel et tu permets de lui mettre plusieurs valeurs. Or, un seul objet PartenaireModule ne permet de ne créer qu'une paire de Partenaire avec un unique Module, c'est le fait qu'un Partenaire et/ou qu'un Module puissent chacun avoir plusieurs PartenaireModule qui permet ainsi cette "OneToManyToOne". Explicité un peu autrement, on a donc One(Partenaire)ToMany(PartenaireModule), One(Module)ToMany(PartenaireModule), ainsi que Many(PartenaireModule)ToOne(Partenaire) et Many(PartenaireModule)ToOne(Module).

                      Les relations partant de PartenaireModule étant bien des ManyToOne, les propriétés modules et Partenaires de PartenaireModule n'ont pas de raison d'être au pluriel et les champs de formulaires n'ont pas de raison d'avoir 'multiple' => true.


                      Oui tu as raison c'est exactement ça. Il y a une incohérence dans ce que j'attends et ce que j'aimerais finalement avoir.

                      Ma question est donc la suivante car je n'y vois plus clair dans ce que je peux et ce que je dois faire pour pouvoir attitrer plusieurs modules pour un partenaire :

                      CF Ma table PartenaireModule peut avoir plusieurs même partenaire mais avec des modules différents.

                      Je sais très bien le faire avec une relation ManyToMany mais sachant que je veux ajouter un champ is_active il me fallait passer par une OneToManyToOne... et c'est la que la magie se complique :) 

                      • Partager sur Facebook
                      • Partager sur Twitter
                        27 septembre 2022 à 3:51:39

                        Si tu parles en terme d'ajout cela se fait en suivant la doc avec le lien que je t'ai indiqué ci-dessus.

                        Pour ma part j'ai plusieurs cas ou j'utilise le type de relation avec attributs : par exemple dans le cas d'un livre de cuisine où j'ai des manytoone entre Recette et Ingredient. L'entité intermédiaire portant entre autres la quantité d'ingrédient nécessaire dans une recette.

                        Si tu suis la doc tu y arriveras sans problème.

                        A+

                        • Partager sur Facebook
                        • Partager sur Twitter
                          27 septembre 2022 à 11:06:00

                          Bon après réflexion j'ai opté pour une autre méthode.

                          J'aimerai connaitre votre avis sur celle-ci et m'accorder un petit temps sur le dernier blocage.

                          J'ai abandonné l'idée de passer par une collection de formulaire et ai plutôt passé le champ que je souhaitais en mapped => false

                          Ce qui donne le formulaire d'ajout d'un partenaire comme ceci : 

                           public function buildForm(FormBuilderInterface $builder, array $options): void
                              {
                                  $builder
                                      ->add('nom')
                                      ->add('statut')
                                      ->add('modules', EntityType::class, [
                                          'class' => Module::class,
                                          'choice_label' => 'nom',
                                          'label' => 'Modules par défaut',
                                          'expanded' => true,
                                          'multiple' => true,
                                          'mapped' => false,
                                      ])

                          Ensuite j'arrive bien à créer mon lien entre mon partenaire id et mon module id dans ma table de jointure mais seulement en multiple => false.

                          En multiple => true cela ne m'enregiste que la première réponse soit la première ligne du tableau.

                          Je sais qu'il manque quelque chose dans mon controller mais je ne parviens pas après plusieurs test à m'en dépatouiller ! 

                           #[Route('/new', name: 'app_partenaire_new', methods: ['GET', 'POST'])]
                              public function new(Request $request, PartenaireRepository $partenaireRepository, EntityManagerInterface $entityManager): Response
                              {
                                  $partenaire = new Partenaire();
                                  $partenaireModule = new PartenaireModule();
                          
                          
                                  $form = $this->createForm(PartenaireType::class, $partenaire);
                                  $form->handleRequest($request);
                                  
                          
                                  if ($form->isSubmitted() && $form->isValid()) {
                          
                          
                                      $partenaireRepository->add($partenaire, true);
                                      
                                      $modules= $form->get('modules')->getData();
                          
                                      foreach ($modules as $module){
                          
                                          $partenaireModule = new PartenaireModule();
                                          $partenaire->getId();
                                          $partenaireModule->setPartenaire($partenaire);
                                          $partenaireModule->setModule($module);
                                          }
                          
                          
                                  
                          
                                      $entityManager->persist($partenaireModule);
                                      $entityManager->flush();
                              
                                      
                          
                                      return $this->redirectToRoute('app_partenaire_index', [], Response::HTTP_SEE_OTHER);
                                  }
                          
                                  return $this->renderForm('partenaire/new.html.twig', [
                                      'partenaire' => $partenaire,
                                      'form' => $form,
                                  ]);
                              }

                          Est ce que je suis dans le bon chemin :) ? et si oui que me manque t'il pour finaliser mon enregistrement comme je le souhaite

                          Merciiii

                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 septembre 2022 à 15:28:05

                            Je vous remercie pour votre aide. après encore une nouvelle reflexion je ne pense pas avoir besoin d'un attribut supplémentaire pour faire fonctionner mon application.

                            Merci à vous

                            je poste une autre question cette fois sur un formulaire symfony dont j'aimerai que le submit automatiquement mais avec quelques compléxités ^^:) 

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Symfony ManyToMany with attributes

                            × 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