Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony2] Jointure

joindre suivant un id

Sujet résolu
Anonyme
    12 septembre 2013 à 19:42:35

    Bonjour,

    j'ai un problème avec une jointure, je voudrais récupérer toutes les infos de mon article, donc jusque ici pas de problème par contre je voudrais dans cette même requête compter le nombre de rédacteur sur cette article, le problème c'est que je ne déclare pas de fonction au auteur, mais que dans la table auteur j'ai un id qui correspond à l'article.

    Le but étant de lister tout les articles sur une page avec le nombre de rédacteur par article, je dois donc faire une seul requête.

    Donc en gros je voudrais faire une jointure du style :

    LEFT JOIN auteur ON auteur.article_id = ARTICLE EN COURS

    Actuellement le code et celui ci dessous mais le problème c'est qu'il ne connait pas "auteur" vu qu'il n'est pas définit dans l'entity Article :

    public function getListeArticlee()
    {
        $qb = $this->createQueryBuilder('a')
                      ->leftJoin('a.redacteurs', 'r') // redacteurs n'hésite pas dans l'entity article, c'est une autre entity.
                      ->addSelect('COUNT(r.id) AS nb_redacteurs')
                      ->orderBy('a.dateCreation');
    
        $resultats = $qb->getQuery()
                        ->getResult();
    
        return $resultats;
    }

    Cordialement.

    • Partager sur Facebook
    • Partager sur Twitter
      13 septembre 2013 à 8:16:34

      Salut !   Si tu souhaites compter les rédacteurs d'un article, si tu n'en as pas beaucoup, tu peux les charger complètement (donc ->addSelect('r')), puis utiliser {{ article.redacteurs.count }} ou {{ article.redacteurs|length }}. Si tu utilises les associations "extra-paresseuses", cela ne chargera pas énormément plus le serveur (il n'y aura qu'une requête avec count() qui sera créé dans ce cas), et si tu n'as pas tant de rédacteurs par article, c'est pas trop dangereux, à mon humble avis.

      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        13 septembre 2013 à 13:35:29

        Le problème c'est que j'ai une erreur, vu que dans l'entity article il n'y a pas de relation avec l'entity rédacteur mais l'inverse oui.

        Le leftjoin du coup ci dessus ne fonctionne donc pas.

        En gros il y a deux tables, "article" qui contient l'id, et la table "redacteur" qui contient tout les rédacteurs des articles, cette table contient un champ article.id, qui permet de savoir pour qu'elle article le rédacteur est.

        -
        Edité par Anonyme 13 septembre 2013 à 13:37:07

        • Partager sur Facebook
        • Partager sur Twitter
          13 septembre 2013 à 13:37:01

          Et pourquoi ne pas rendre la relation bidirectionnelle, sinon carrément en changer le sens ?

          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            13 septembre 2013 à 13:42:54

            Faire en sorte que tu puisses récupérer les rédacteurs d'un article, en plus de pouvoir récupérer les articles d'un auteur précis ?  o_O

            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              13 septembre 2013 à 14:07:26

              Ok j'ai donc suivi le tuto :

              http://www.siteduzero.com/informatique/tutoriels/developpez-votre-site-web-avec-le-framework-symfony2/les-relations-bidirectionnelles

              Et j'ai donc ma requête qui est maintenant :

              $qb = $this->createQueryBuilder('a')
              	->orderBy('a.dateCreation');
              
              $resultats = $qb->getQuery()
              		->getResult();
              
              return $resultats;
              


              Et dans le twig j'ai mis : article.redacteur.count

              Ca fonctionne, par contre j'ai l'impression que c'est un peu plus long niveau chargement qu'avant !?

              • Partager sur Facebook
              • Partager sur Twitter
                13 septembre 2013 à 14:13:52

                Heu, je ne saisis pas tout à fait pourquoi tu n'as plus la jointure que tu avais avant ?

                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  13 septembre 2013 à 14:24:53

                  les valeurs sont générer avec 'a', vu que je suis en bidirectionnelle, si j'ai bien compris. En tout cas en enlevant la jointure ça fonctionne donc c'est que les rédacteurs sont chargés !?

                  • Partager sur Facebook
                  • Partager sur Twitter
                    13 septembre 2013 à 14:28:24

                    Les rédacteurs seront récupérés avec une requête supplémentaire si tu ne fais pas la jointure dans le repository, c'est pour ça que c'est un peu plus lent (et surtout au point que tu le remarques :-° )   Tu commences à m'embrouiller, là. Tu avais déjà une relation qui te permettait de partir d'un article et de récupérer ses auteurs ?

                    -
                    Edité par Ymox 13 septembre 2013 à 14:28:31

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      13 septembre 2013 à 15:39:58

                      Non je n'avais pas de relation mais je l'ai rajouté comme expliqué dans le tuto, en rajoutant dans l'entity Article un OneToMany vers l'entity Redacteur
                      • Partager sur Facebook
                      • Partager sur Twitter
                        13 septembre 2013 à 15:48:21

                        Pourquoi avoir enlevé ton leftJoin et addSelect alors ? As-tu regardé les requêtes que ta solution actuelle générait ?
                        • Partager sur Facebook
                        • Partager sur Twitter
                          13 septembre 2013 à 15:48:35

                          Donc maintenant, ta fonction comme mentionnée dans le premier message, avec la modification dont je t'ai parlé ensuite, devrait fonctionner ^^

                          Mais à QUAND le retour des avertissements pour réponse donnée entre-temps ?

                          -
                          Edité par Ymox 13 septembre 2013 à 15:53:45

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            13 septembre 2013 à 18:03:06

                            Avec le leftjoin, ça plante, j'ai donc fait un print_r() sur le resultat sous forme de "$qb->getQuery()->getArrayResult();"

                            Et j'ai un array en plus du coup tout plante au niveau de l'affichage :

                            Array
                            (
                                [0] => Array
                                    (
                                        [0] => Array
                                            (
                                                [id] => 1
                                                [dateCreation] => DateTime Object
                                                    (
                                                        [date] => 2013-08-11 15:23:50
                                                        [timezone_type] => 3
                                                        [timezone] => UTC
                                                    )
                            
                                                [statut] => 1
                                            )
                            
                                        [redacteurs] => 3
                                    )
                            
                            )


                            Mais juste pour comprendre, pourquoi en enlevant le leftjoin et addselect j'arrive a compter le nombre de rédacteur ?

                            Edit : Si je rajoute la requête sans le COUNT(*) mais avec 'r' j'obtiens tout mais toujours un problème de double array qui fausse l'affichage...

                            -
                            Edité par Anonyme 13 septembre 2013 à 18:12:56

                            • Partager sur Facebook
                            • Partager sur Twitter
                              13 septembre 2013 à 21:32:15

                              Bonsoir,

                              Tu arrives tout de même à récupérer ton nombre de rédacteur parce que Doctrine charge en lady loading tes données, autrement dit, il exécute une requête subsidiaire à chaque fois pour récupérer ce nombre. En terme de perf c'est pas terrible, il est largement préférable de mettre la jointure. Par contre, ce n'est pas COUNT(*) que tu dois utiliser mais COUNT(r) où r est l'alias donné lors du leftJoin , et ne pas oublier le groupBy peut-être (ou pas, je ne sais pas, à vérifier) et là tu récupérera le nombre directement donc pas |length à rajouter en twig

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Anonyme
                                13 septembre 2013 à 21:41:45

                                J'ai donc fait comme expliqué au niveau de la requête :

                                $qb = $this->createQueryBuilder('a')
                                	->addSelect('COUNT(r) AS nb_redacteur')
                                	->leftJoin('a.redacteurs', 'r')
                                	->orderBy('a.statut', 'ASC', 'r.dateCreation', 'ASC');

                                Le problème c'est que j'ai un array dans l'array, et je ne comprends pas pourquoi le addSelect mais met les infos dans un nouvelle array ?

                                La quand je fais dans le twig mes variables ne fonctionne plus : "article.nom", "article.nb_redacteur"

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  13 septembre 2013 à 21:46:32

                                  Ta fonction retourne quoi ? Tu retournes bien $qb->getQuery()->getResult() ?
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Anonyme
                                    13 septembre 2013 à 22:03:49

                                    Alors pour bien montre j'ai fais ceci :

                                    public function getListeArticle()
                                    {
                                    	$qb = $this->createQueryBuilder('a')
                                    				->addSelect('COUNT(r) AS nb_redacteur')
                                    				->leftJoin('a.redacteurs', 'r')
                                    				->orderBy('a.statut', 'ASC', 'a.dateCreation', 'ASC');
                                    
                                    	echo $qb;
                                    
                                    	$resultats = $qb->getQuery()
                                    					->getArrayResult(); // Normalement c'est getResult mais il met trop de temps à charger sur le print_r()
                                    
                                    	echo '<pre>';
                                    	print_r($resultats);
                                    	echo '<pre>';
                                    
                                    	die();
                                    
                                    	return $resultats;
                                    }

                                    Le echo retourne :

                                    SELECT a, COUNT(r) AS nb_redacteur FROM Projet\DefautBundle\Entity\Article a LEFT JOIN a.redacteurs r ORDER BY a.statut ASC

                                    Le print_r() :

                                    Array
                                    (
                                        [0] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [id] => 1
                                                        [nom] => Mon article
                                                        [dateCreation] => DateTime Object
                                                            (
                                                                [date] => 2013-08-11 15:23:50
                                                                [timezone_type] => 3
                                                                [timezone] => UTC
                                                            )
                                                        [statut] => 1
                                                    )
                                    
                                                [nb_redacteur] => 3
                                            )
                                    
                                    )

                                    Dans ma vue :

                                    {% for article in articles %}
                                        <td>{{ article.nom }}</td>
                                        <td>{{ article.statut }}</td>
                                        <td>{{ article.nb_redacteur }}</td>
                                        <td>{{ article.datecreation|date("Y-m-d H:i:s") }}</td>
                                    {% endfor %}

                                    Erreur :

                                     Key "nom" for array with keys "0, nb_redacteur" does not exist in ProjetDefautBundle:Default:liste_article.html.twig at line 30
                                    500 Internal Server Error - Twig_Error_Runtime 

                                    Voilà mais dans le vrai code j'utilise getResult(), c'est juste qu'avec le print_r ça plante délais très lent.

                                    -
                                    Edité par Anonyme 13 septembre 2013 à 22:06:51

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      13 septembre 2013 à 22:06:25

                                      Et si tu rajoute le groupBy ça donne quoi ?
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Anonyme
                                        13 septembre 2013 à 22:08:33

                                        ça ne change rien
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          13 septembre 2013 à 22:14:45

                                          Bon, dans ce cas, addSelect('r') directement, et dans la vue tu rajoutes |length , il semblerait que Doctrine n'ait pas implémenté COUNT en fait, selon la doc.

                                          EDIT: on me dit dans l'oreillette (la doc doctrine) que SIZE(collection) retourne le nombre d'élément d'une collection, donc c'est l'équivalent de notre count

                                          -
                                          Edité par Zazou 13 septembre 2013 à 22:17:59

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Anonyme
                                            13 septembre 2013 à 22:18:54

                                            Si le count fonctionne vu que dans l'array j'ai bien : nb_redacteur = 3 !?
                                            Mais ce qui est bizarre c'est l'histoire de l'array... 

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              13 septembre 2013 à 22:22:08

                                              Oui mais non, on dit que ça fonctionne quand on obtient le résultat attendu, ce n'est pas le cas ici ;) Que nous dit le résultat avec SIZE(r) ?

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                              Anonyme
                                                13 septembre 2013 à 22:27:00

                                                Exacte ^^

                                                J'ai une erreur avec SIZE :

                                                 [Semantical Error] line 0, col 15 near 'r) FROM Projet\DefautBundle\Entity\Article': Error: Invalid PathExpression. Must be a CollectionValuedAssociationField.
                                                500 Internal Server Error - QueryException
                                                1 linked Exception:
                                                
                                                    QueryException »
                                                



                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  13 septembre 2013 à 22:31:43

                                                  SIZE(a.redacteurs) et du coup tu peux enlever la jointure.
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Anonyme
                                                    13 septembre 2013 à 22:34:31

                                                    Encore le même problème... Double array :

                                                    Array
                                                    (
                                                        [0] => Array
                                                            (
                                                                [0] => Array
                                                                    (
                                                                        [id] => 1
                                                                        [nom] => Mon article !
                                                                        [dateCreation] => DateTime Object
                                                                            (
                                                                                [date] => 2013-08-11 15:23:50
                                                                                [timezone_type] => 3
                                                                                [timezone] => UTC
                                                                            )
                                                                        [statut] => 1
                                                                    )
                                                    
                                                                [1] => 3
                                                            )
                                                    }



                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      13 septembre 2013 à 22:35:38

                                                      Je ne sais pas exactement ce que tu fais mais ce n'est clairement pas normal ... Désolée je n'ai plus d'idée. :(

                                                      Eventuellement, vérifie tes entités et spécialement ta relation bidirectionnelle, est ce que tu n'as rien oublié, je pense notamment à la déclaration dans le constructeur de ton attribut à ArrayCollection.

                                                      -
                                                      Edité par Zazou 13 septembre 2013 à 22:37:13

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      Anonyme
                                                        13 septembre 2013 à 22:39:57

                                                        Oui je comprends vraiment pas non plus...

                                                        Au cas ou dans mon controller je fais :

                                                        $liste_articles = $this->getDoctrine()
                                                        		->getManager()
                                                        		->getRepository('ProjetDefautBundle:Article')
                                                        		->getListeArticle();
                                                        
                                                        		return $this->render('ProjetDefautBundle:Default:liste_article.html.twig', array(
                                                        								'articles'		=> $liste_articles,
                                                        	));



                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          13 septembre 2013 à 22:45:57

                                                          Ok, maintenant montre-nous la méthode getListeArticle() en entier et en normale (donc getResult) et dans ta vue, tu fais {{ dump(articles) }} , ça t'affiche quoi ?
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          Anonyme
                                                            14 septembre 2013 à 0:02:32

                                                            Voilà la méthode :

                                                            <?php
                                                            
                                                            namespace Projet\DefautBundle\Entity;
                                                            
                                                            use Doctrine\ORM\EntityRepository;
                                                            
                                                            /**
                                                             * ArticleRepository
                                                             *
                                                             * This class was generated by the Doctrine ORM. Add your own custom
                                                             * repository methods below.
                                                             */
                                                            class ArticleRepository extends EntityRepository
                                                            {
                                                            	public function getListeArticle()
                                                            	{
                                                            		$qb = $this->createQueryBuilder('a')
                                                            					->addSelect('SIZE(a.redacteurs) AS nb_redacteur')
                                                            					->orderBy('a.statut', 'ASC');
                                                            
                                                            		$resultats = $qb->getQuery()
                                                            						->getResult();
                                                            
                                                            		return $resultats;
                                                            	}
                                                            }

                                                            Le dump :

                                                            array (size=2)
                                                              0 => 
                                                                array (size=2)
                                                                  0 => 
                                                                    object(Projet\DefautBundle\Entity\Article)[403]
                                                                      private 'user' => 
                                                                        object(Projet\UserBundle\Entity\User)[302]
                                                                          ...
                                                                      private 'redacteurs' => 
                                                                        object(Doctrine\ORM\PersistentCollection)[460]
                                                                          ...
                                                                      private 'id' => int 1
                                                                      private 'nom' => string 'Mon article !' (length=20)
                                                                      private 'dateCreation' => 
                                                                        object(DateTime)[387]
                                                                          ...
                                                                      private 'statut' => int 1
                                                                  'nb_redacteur' => string '3' (length=1)
                                                              1 => 
                                                                array (size=2)
                                                                  0 => 
                                                                    object(Projet\DefautBundle\Entity\Article)[457]
                                                                      private 'user' => 
                                                                        object(Projet\UserBundle\Entity\User)[302]
                                                                          ...
                                                                      private 'redacteurs' => 
                                                                        object(Doctrine\ORM\PersistentCollection)[458]
                                                                          ...
                                                                      private 'id' => int 2
                                                                      private 'nom' => string 'article deux' (length=11)
                                                                      private 'dateCreation' => 
                                                                        object(DateTime)[456]
                                                                          ...
                                                                      private 'statut' => int 1
                                                                  'nb_redacteur' => string '1' (length=1)

                                                            Voilà hésite pas si tu as besoin d'autre chose, j'avoue être un peu perdu...



                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            [Symfony2] Jointure

                                                            × 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