Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony3] pagination

Sujet résolu
    22 mars 2019 à 17:15:43

    Bonjour,

    j'utilise KnpPaginatorBundle sur mon appli Symfony3.

    Je demande a afficher 2 éléments par page.

    Voici mon code :

            $liste_posts = $this->getDoctrine()->getRepository('AppBundle:Post')->findTrending();
    
            $posts = $this->get('knp_paginator')->paginate(
                $liste_posts,
                $request->query->get('page', $request->query->getInt('page', 1)),
                2);
    

    La variable $liste_posts retourne 4 éléments donc je devrai avoir 2 pages avec 2 éléments par page.

    Voici ce que j'obtiens quand j'affiche la variable $posts :


    Problème j'obtiens une pagination de 4 pages (au lieu de 2 page). Sur les 2 première page j'ai bien mes 2 éléments et sur la 3 ieme et 4 ieme page je n'ai aucun élément.

    Pourquoi est-ce que le système me rajoute 2 pages alors que je suis censé en avoir 2 au total ?

    Merci d'avance

    • Partager sur Facebook
    • Partager sur Twitter
      22 mars 2019 à 20:32:15

      Bonjour,

      Je ne sais pas ce que te renvoie ta méthode findTrending mais si c'est le résultat ça n'est pas bon. Le paginator doit avoir en premier argument un query. 

      Doc https://github.com/KnpLabs/KnpPaginatorBundle/blob/master/README.md

      Bon courage. 

      • Partager sur Facebook
      • Partager sur Twitter

      Celui qui aime à apprendre est bien près du savoir " Confucius

        23 mars 2019 à 9:04:38

        Oui oui je sais ma requête renvoie bien une Query, d'ailleurs vous pouvez voir sur l'image de mon premier message que "items" contient bien bien mes 2 posts de la première page.

            public function findTrending()
            {
                $qb = $this->createQueryBuilder('p')
                    ->addSelect('o')
                    ->join('p.opinions', 'o')
                    ->join('p.opinions', 'o2')
                    ->join('o2.post', 'p2')
                    ->where('p.private = FALSE')
                    ->groupBy('p, o')
                    ->orderBy('count(o2.id)', 'desc');
        
                return $qb
                    ->getQuery();
            }



        • Partager sur Facebook
        • Partager sur Twitter
          23 mars 2019 à 11:12:04

          Bonjour,

          Je pense que cela vient de ta requête elle-même car tu rajoutes select o. Essaies de faire un var_dump de liste_posts et donne nous le résultats, je ne serai pas surprise de voir un count = 7.

          Comme tu as une jointure entre p et opinions lorsque tu vas chercher p tu auras aussi o.

           Tiens nous au courant.

          • Partager sur Facebook
          • Partager sur Twitter

          Celui qui aime à apprendre est bien près du savoir " Confucius

            23 mars 2019 à 11:58:40

            Merci pour ton aide.

            En rajoutant le ->getResult() voici ce que me ressort le var_dump($liste_posts) :

            Il n'y a bien mes 4 Posts 

            • Partager sur Facebook
            • Partager sur Twitter
              23 mars 2019 à 12:39:58

              Salut

              Quel résultat est renvoyé si tu fais ça 

              public function findTrending()
              {
                  $qb = $this->createQueryBuilder('p')
                      ->join('p.opinions', 'o')
                      ->join('p.opinions', 'o2')
                      ->join('o2.post', 'p2')
                      ->where('p.private = FALSE')
                      ->groupBy('p, o')
                      ->orderBy('count(o2.id)', 'desc');
               
                  return $qb
                      ->getQuery();
              }



              • Partager sur Facebook
              • Partager sur Twitter
                23 mars 2019 à 12:50:02

                sans le getResult() :

                avec le getResult() :

                • Partager sur Facebook
                • Partager sur Twitter
                  23 mars 2019 à 12:52:59

                  Et ta pagination donne quoi si tu la dump ?

                  Je te conseil aussi de test ta pagination avec ça 

                  public function findTrending()
                  {
                      $qb = $this->createQueryBuilder('p');
                    
                      return $qb;
                  }

                  Et regarder si la pagination respecte bien le nombre par page et le nombre de résultat

                  -
                  Edité par heyden7611 23 mars 2019 à 12:54:39

                  • Partager sur Facebook
                  • Partager sur Twitter
                    23 mars 2019 à 13:11:13

                    Si je je dump la pagination :

                    Si je mets juste ceci :

                    public function findTrending()
                    {
                        $qb = $this->createQueryBuilder('p');
                       
                        return $qb;
                    }

                    La pagination fonctionne bien sans bug

                    • Partager sur Facebook
                    • Partager sur Twitter
                      23 mars 2019 à 13:20:35

                      Ok donc je peux avoir un dump rapidement de ça en mode getQuery()->getResult() ? 

                      public function findTrending()
                      {
                          $qb = $this->createQueryBuilder('p');
                          
                          return $qb;
                      }



                      • Partager sur Facebook
                      • Partager sur Twitter
                        23 mars 2019 à 13:31:53

                        D'accord on avance :) 

                        Donc maintenant fait ça

                        public function findTrending()
                        {
                            $qb = $this->createQueryBuilder('p')
                                ->leftJoin('p.opinions', 'o2')
                                ->where('p.private = :private')
                                ->setParameter('private', false)
                                ->orderBy('count(o2.id)', 'desc');
                          
                            return $qb;
                        }



                        • Partager sur Facebook
                        • Partager sur Twitter
                          23 mars 2019 à 13:41:08

                          An exception occurred while executing 'SELECT DISTINCT p0_.id AS id_0 FROM post p0_ LEFT JOIN opinion o1_ ON p0_.id = o1_.post_id WHERE p0_.private = ? ORDER BY count(o1_.id) DESC LIMIT 2' with params [0]:
                          
                          SQLSTATE[HY000]: General error: 3029 Expression #1 of ORDER BY contains aggregate function and applies to the result of a non-aggregated query

                          On ne peut pas faire ça, car il doit y avoir un group by pour faire le orderby
                          • Partager sur Facebook
                          • Partager sur Twitter
                            23 mars 2019 à 13:45:56

                            Donc 

                            public function findTrending()
                            {
                                $qb = $this->createQueryBuilder('p')
                                    ->leftJoin('p.opinions', 'o2')
                                    ->where('p.private = :private')
                                    ->setParameter('private', false)
                                     ->groupBy('o2')
                                    ->orderBy('count(o2.id)', 'desc');
                               
                                return $qb;
                            }



                            • Partager sur Facebook
                            • Partager sur Twitter
                              23 mars 2019 à 13:55:20

                              La ça ne fonctionne pas du tout, la pagination affiche 6 pages alors qu'a partir de la page 4 il n'y a plus rien.

                              Les posts retournés ne sont pas les bons, et le tri est mal fait.

                              J'explique la situation :

                              j'ai un Post qui peut avoir plusieurs Opinion (ManyToOne)

                              Je veux afficher sur ma page la liste des posts qui ont des Opinions et afficher les posts par ordre des posts avec le plus d'opinions. Et j'affiche également sur chaque post les opinions qu'il contient.

                              Pour faire ceci c'est cette requête qui me renvoi le bon résultat :

                                      $qb = $this->createQueryBuilder('p')
                                          ->addSelect('o')
                                          ->join('p.opinions', 'o')
                                          ->join('p.opinions', 'o2')
                                          ->join('o2.post', 'p2')
                                          ->where('p.private = FALSE')
                                          ->groupBy('p, o')
                                          ->orderBy('count(o2.id)', 'desc');



                              • Partager sur Facebook
                              • Partager sur Twitter
                                23 mars 2019 à 14:00:43

                                $qb = $this->createQueryBuilder('p')
                                    ->addSelect('o2')
                                    ->join('p.opinions', 'o2')
                                    ->where('p.private = FALSE')
                                    ->groupBy('p, o2')
                                    ->orderBy('count(o2.id)', 'desc');
                                Cette requête devrais être ok non ? 

                                 Je ne vois pas à quoi sert de mettre 2 fois la même chose

                                ->join('p.opinions', 'o')
                                ->join('p.opinions', 'o2')

                                De plus à quoi sert 

                                ->join('o2.post', 'p2')
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  23 mars 2019 à 14:07:57

                                  Supprime addSelect, groupBy et orderBy. 

                                  Regarde dans la doc doctrine tu peux mettre dans ta relation ManyTo une annotation pour que ça te renvoie un orderBy id desc.

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Celui qui aime à apprendre est bien près du savoir " Confucius

                                    23 mars 2019 à 14:17:40

                                    Non si je mets ceci :

                                            $qb = $this->createQueryBuilder('p')
                                            ->addSelect('o2')
                                            ->join('p.opinions', 'o2')
                                            ->where('p.private = FALSE')
                                            ->groupBy('p, o2')
                                            ->orderBy('count(o2.id)', 'desc');

                                    j'obtiens bien les posts qui ont des opinions, avec leurs opinions mais ils ne sont pas triés par ordre de popularité.

                                    Je te renvoie vers le post justement qui traité cette requête :

                                    https://openclassrooms.com/forum/sujet/symfony4-aide-sur-requete?page=1#message-93044836

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      23 mars 2019 à 16:41:59

                                      Re,

                                      Dans le lien que tu mets il utilise le Paginator natif de Doctrine et toi le knp, je pense que la différence est là.

                                      A tout hasard count = 7 correspondrait pas à nbr post + nbr opinions?

                                      PS: Essaie pour voir en lui passant le queryBuilder!

                                      -
                                      Edité par stoads 23 mars 2019 à 16:52:51

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Celui qui aime à apprendre est bien près du savoir " Confucius

                                        23 mars 2019 à 16:53:44

                                        Justement dans le lien c'est une ancienne version, j'ai supprimé le Paginator natif et je l'ai remplacé par Knp.

                                        Je viens de remarqué que le count = 7 est en faite le nombre d'Opinion et non le nombre de Post :(

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          23 mars 2019 à 17:04:37

                                          Ce qui est tout à fait normal tu select post et opinions donc le knp count tes deux select ie p et o.

                                          Peut etre passer par un subQuery afin de ne pas faire de addSelect...

                                          PS: Essaie ceci https://github.com/KnpLabs/KnpPaginatorBundle/blob/master/Resources/doc/manual_counting.md

                                          -
                                          Edité par stoads 23 mars 2019 à 17:20:30

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Celui qui aime à apprendre est bien près du savoir " Confucius

                                            23 mars 2019 à 18:22:46

                                            J'ai trouvé une solution de bidouille qui fonctionne.

                                            Voici ma requête :

                                                    $qb = $this->createQueryBuilder('p')
                                                        ->addSelect('o')
                                                        ->join('p.opinions', 'o')
                                                        ->join('p.opinions', 'o2')
                                                        ->join('o2.post', 'p2')
                                                        ->where('p.private = FALSE')
                                                        ->groupBy('p, o')
                                                        ->orderBy('count(o2.id)', 'desc');
                                            
                                                    return $qb;

                                            Voici ce que j'ai fais dans l'action :

                                                    $liste_posts = $this->getDoctrine()->getRepository('AppBundle:Post')->findTrending();
                                            
                                                    $posts = $this->get('knp_paginator')->paginate(
                                                        $liste_posts->getQuery(),
                                                        $request->query->get('page', $request->query->getInt('page', 1)),
                                                        2);
                                            
                                                    $posts->setTotalItemCount(count($liste_posts->getQuery()->getResult()));


                                            Je modifie le totalItemCount du paginator en lui passant le total de mes Posts et du coup tout fonctionne

                                            Qu'en pensez vous ?

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              23 mars 2019 à 20:14:17

                                              c'est exactement ce que je t'avais mis en lien sauf qu'il préconise de le faire dans le repository.

                                              Bonne continuation

                                              PS: c'est quoi comme cours?

                                              -
                                              Edité par stoads 23 mars 2019 à 20:15:50

                                              • Partager sur Facebook
                                              • Partager sur Twitter

                                              Celui qui aime à apprendre est bien près du savoir " Confucius

                                                23 mars 2019 à 20:37:34

                                                PS: c'est quoi comme cours?

                                                Comment ça ?

                                                • Partager sur Facebook
                                                • Partager sur Twitter

                                                [Symfony3] pagination

                                                × 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