Partage
  • Partager sur Facebook
  • Partager sur Twitter

[SYMFONY2] Recherche avancée

Sujet résolu
    18 juin 2012 à 16:27:23

    Bonjour,

    Je voudrais faire un formulaire de recherche avancée sur des aliments en fonction de leur nature(attribut de l'entite Aliment (vegetale ou animale) et selon le nom des producteurs (j'ai une entité Producteur).

    Pour cela, j'ai créé dans mon contrôleur une fonction rechercheAvanceeAction :
    <?php
        public function rechercheavanceeAction()
        {
            $em = $this->container->get('doctrine.orm.entity_manager');
    
            $dql = "SELECT prod FROM MonBundle:Producteur prod ORDER BY prod.nom";
            $this->param['producteurs'] = $em->createQuery($dql)->getResult();
    
            $this->param['natures'] = array('vegetale' => 'vegetale', 'animale' => 'animale');
    
            $request= $this->getRequest();
            
            $this->param['post'] = false;
    
            $p['producteurs']   = "tous";
            $p['nature']        = "toutes";
    
          if($request->getMethod() == 'POST') {
    
                $this->param['post'] = true;
                $p['producteur']    = $request->get('prodcteur');
                $p['nature']        = $request->get('nature');
    
                $this->param['aliments']    = $em->getRepository('MoBundle:Aliment')->getRechercheAvancee($p);
            }
            else {
                $this->param['aliments']   = false;
            }
    
            $this->param['p'] = $p;
    
            return $this->render('MonBundle:Aliment:recherche_avancee.html.twig', $this->param);
        }
    


    Et dans mon AlimentRepository :

    <?php
    
    
        public function getRechercheAvancee($p = null)
        {
            $em = $this->getEntityManager();
    
            $dql = "SELECT a, prod FROM MonBundle:Aliment a"
                . " JOIN a.producteur prod"
                ;
            
            if($p['producteur'] != 'tous'){
                $dql .= " AND prod.id = " . $p['producteur'];
            }
    
            if($p['nature'] != 'toutes'){
                $dql .= " AND a.nature = " . $p['nature'];
            }
            
            $dql .= " ORDER BY a.nom ASC";
    
            $query = $em->createQuery($dql);
            return $query->getResult();
        }
    



    La vue s'affiche bien, mais quand je selectionne la nature vegetale (par exemple), j'ai l'erreur suivante :
    [Semantical Error] line 0, col 265 near 'vegetale ORDER': Error: 'vegetale' is not defined.


    Bon je comprends bien que le probleme vient de la definion de param['natures'] mais je ne vois pas pourquoi.

    Merci beaucoup
    • Partager sur Facebook
    • Partager sur Twitter
      18 juin 2012 à 16:29:35

      Salut !

      Je parie que la valeur de $p['nature'] est une chaîne de caractères. Or, tu ne l'encadres pas de guillemets, et je me doute de ce que ce soit ça qui pose problème…
      • Partager sur Facebook
      • Partager sur Twitter
        18 juin 2012 à 16:57:06

        <? php
                if($p['nature'] != 'toutes'){
                    $dql .= " AND a.nature = " . " $p['nature'] ";
                }
        


        Comme ca ?
        • Partager sur Facebook
        • Partager sur Twitter
          18 juin 2012 à 18:01:03

          <?php $dql .= " AND a.nature = '" . $p['nature'] . "'";
          
          • Partager sur Facebook
          • Partager sur Twitter
            18 juin 2012 à 18:17:38

            OK merci! je n'ai plus d'erreur, mais par contre comme résultats, je n'ai rien si je sélectionne animale (alors qu'en base de données, j'en ai bien quelques uns) et si je selectionne "toutes" ou "vegetale", j'obtiens la liste d'aliments d'origine "vegetale" dans tous les cas ...
            • Partager sur Facebook
            • Partager sur Twitter
              18 juin 2012 à 18:21:35

              Tu peux voir la requête en cliquant dans la barre qui s'affiche en bas de fenêtre avec Symfony en mode développement. Si je me souviens bien, c'est l'icône tout à droite de la barre.

              Tout ça pour dire que tu as probablement un autre petit souci.
              • Partager sur Facebook
              • Partager sur Twitter
                18 juin 2012 à 18:32:20

                Ok, le problème; je pense, vient du fait qu'il faut que les aliments soient reliés à un producteur pour que la requête fonctionne.
                Mais comment contourner cette contrainte ?
                • Partager sur Facebook
                • Partager sur Twitter
                  18 juin 2012 à 18:38:02

                  Je pense qu'utiliser RIGHT JOIN pourrait faire l'affaire, si aucun de tes aliments végétaux n'ont effectivement pas de producteur.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 juin 2012 à 19:24:13

                    Salut,

                    La façon dont tu construis ta requête est vraiment moche, c'est exactement pour ça que Doctrine fourni un QueryBuilder. Tu devrais l'utiliser, avec l'utilisation des paramètres ça t'aurait éviter la première erreur.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      18 juin 2012 à 19:33:11

                      Malheureusement, j'ai l'impression qu'il n'y a pas de RIGHT JOIN en DQL

                      Je vais essayer de refaire la requete en utilisant Query Builder, je vous tiens au courant!

                      Merci
                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 juin 2012 à 19:46:29

                        Non ça n'a pas de sens, réfléchissez en objets et pas en tables, je ne me répéterai jamais assez.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 juin 2012 à 19:50:39

                          Salut.

                          C'est normal la faute dans le get ligne 21 de ton premier code ?

                          <?php $p['producteur'] = $request->get('prodcteur');
                          


                          Un "u" oublié dans "producteur". Ca fait que tu cherches toujours à avoir un producteur d'id inconnu dans ta requête.

                          @+
                          • Partager sur Facebook
                          • Partager sur Twitter
                            18 juin 2012 à 19:53:22

                            Si si, il y a bien RIGHT JOIN. Mais je pense que c'et parce que tu as écrit ta requête SELECT a, prod au lieu de SELECT a FROM MonBundle:Aliment RIGHT JOIN MonBundle:Producteur ON -- aucune idée exacte de comment faire une jointure en DQL…

                            Ensuite, je voulais te laisser faire à ta manière, mais c'est vrai qu'utiliser un QueryBuilder est intéressant. Je m'attendais à un lien vers de la documentation, mais non, donc le voilà si tu veux tenter. En gros, c'est une manière d'écrire le DQL avec des fonctions PHP, donc passer de l'un à l'autre est encore assez facile.

                            Citation : winzou

                            Non ça n'a pas de sens, réfléchissez en objets et pas en tables, je ne me répéterai jamais assez.

                            En attendant, QueryBuilder propose un équivalent de RIGHT JOIN, et c'est probablement ce qu'il faut quelque fois. On n'a ni parlé de tables, ni de colonnes, pourtant ?

                            :pastaper:
                            • Partager sur Facebook
                            • Partager sur Twitter
                              18 juin 2012 à 20:04:41

                              Je vais essayer de refaire la requete en utilisant Query Builder, je vous tiens au courant!
                              • Partager sur Facebook
                              • Partager sur Twitter
                                18 juin 2012 à 20:13:47

                                Ymox où tu vois que le RIGHT JOIN est supporté ?

                                En SQL, un RIGHT JOIN permet de retourner des lignes de la table jointe qui n'ont pas de correspondance dans la table d'origine.

                                En Doctrine, il permettrait quoi ?? Avec ou sans jointure, Doctrine retourne une liste d'objets. Un [LEFT] JOIN permet juste de faire $unObjet->getAutresObjets() sans déclencher de requête supplémentaire. Mais un RIGHT JOIN permettrait de faire quoi ? null->getAutresObjets() ?
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  18 juin 2012 à 20:19:33

                                  Pas faux… :waw::honte::'(

                                  D'autant plus que ce n'est pas du tout ce que cherche à faire Clarisse123…

                                  Bon, je reviendrai quand j'aurai dormi  :ange:


                                  Mes excuses
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    18 juin 2012 à 22:11:22

                                    Re!
                                    Donc voici ma requête écrite en Query Builder (ma situation réelle étant un peu plus compliquée : j'ai une entité Etiquette reliée à Aliment par une relation OneToOne, entité Etiquette étant elle-même liée (aussi par une relation OneToOne), à une entité EtiquetteType (via l'attribut etiquette_type dans Etiquette), à une entité Ville et enfin, à une entité Etablissement.

                                    Tous les aliments ont une nature, mais tous n'ont pas d'étiquette.

                                    (Laissons tomber le producteur du début).

                                    On doit pouvoir rechercher un aliment par sa nature (liste déroulante) (même si l'aliment ne possède pas d'étiquette), par sa ville(liste déroulante), par son établissement (liste déroulante) et par le type d'etiquette (via des cases à cocher).

                                    J'ai l'erreur suivante :
                                    Invalid parameter format, : given, but :<name> or ?<num> expected.



                                    Mais bon, j'aimerais savoir si ce que j'ai écrit est à peu près correct, parce que je n'ai pas encore l'habitude d'écrire des requêtes.

                                    Voici mon AlimentRepository

                                    <?php
                                    public function getAnnuaireAvance($p = null)
                                        {
                                            $qb = $this->createQueryBuilder('a')
                                            ->join('a.etiquette', 'e')
                                            ->addSelect('e')
                                            ->join('e.etiquette_type', 'et')
                                            ->addSelect('et')
                                            ->where('a.nom =:nom')
                                            ->setParameter('nom', '$p[nom]')
                                            ->andWhere('a.nature=:nature')
                                            ->setParameter('nature', '$p[nature]');        
                                    
                                    
                                            if(sizeof($p['etiquette_types']) > 0)
                                            {
                                                foreach ($p['etiquette_types'] as $etiquette_type_id) 
                                                {
                                                    $qb->andWhere('et.id = $etiquette_type_id ');
                                                }
                                            }
                                    
                                            if(($p['ville'] != 'toutes') || ($p['etablissement'] != 'tous') ))
                                            {        
                                                $qb->join('e.ville', 'vi')
                                                   ->join('e.etablissement', 'et')
                                                   ->addSelect(array('vi', 'et'));
                                    
                                                    if($p['ville'] != 'toutes')
                                                    {
                                                       $qb->andWhere('vi.id = $p[ville]');
                                                    }
                                    
                                                    if($p['etablissement'] != 'tous')
                                                    {
                                                       $qb->andWhere('et.id = $p[etablissement]');
                                                    }
                                    
                                            }
                                    
                                            $qb->orderBy('a.nom', 'ASC');
                                    
                                         
                                            return $qb->getQuery()->getResult();
                                        }
                                    

                                    Merci beaucoup
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      18 juin 2012 à 22:24:52

                                      Salut.

                                      Indice : revois presque tous tes andWhere, et aussi un setParameter ou deux tant que tu y es. :)

                                      @+
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        19 juin 2012 à 12:02:44

                                        Puis-je avoir un autre indice ? :euh: parce que j'ai bien mis des guillements pour le nom et la nature, comme me l'avait dit Ymox, ensuite pour les andWhere je ne vois vraiment pas pourquoi ça devrait être écrit différemment :(
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          19 juin 2012 à 13:43:11

                                          '$p[nature]' ça te choque pas ?

                                          Et utilise des arguments pour chaque variable que tu veux insérer dans ta requête, c'est à ça que ça sert.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            20 juin 2012 à 15:48:35

                                            J'ai fait les modifications (qui étaient d'ordre syntaxique) et ça marche!

                                            Merci beaucoup!
                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            [SYMFONY2] Recherche avancée

                                            × 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