Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème requette Symfony

    6 juillet 2020 à 22:51:26

    Bonsoir,

    Désolé si ma question a déjà été posé, j'ai cherché de partout et ne trouve pas de réponse (peut-être du fait que ça fait trop d'heures que je code).

    Tout d'abord merci de prendre le temps de lire et d'essayer d'y répondre.

    Voici mon problème, je code à l'heure actuelle un site sous Symfony, et j'aimerai savoir la disponibilité d'un bateau en fonction de ses réservations et des deux dates rentrés dans le champs de recherche, a l'heure actuelle presque tout fonctionne sauf lorsque les dates de ma recherche englobe les dates de réservation. J'arrive à comprendre ou est mon problème mais ne sait pas le retranscrire (de même je ne sais pas s'il vallait mieux que je mette mon sujet dans la partie SQL étant donné que c'est du Doctrine), voici ce que j'ai fait:

    $this->createQueryBuilder('Bateau')
            ->leftJoin('Bateau.reservationBateaux', 'r', 'WITH','Bateau.id = r.bateau')
            ->where('Bateau.visible = true')
            ->andWhere(':dateDebut NOT BETWEEN r.dateDebut AND r.dateFin')
            ->andWhere(':dateFin NOT BETWEEN r.dateDebut AND r.dateFin')
    
            /*->orWhere(':dateFin >= r.dateFin') //17/06  >= 03/07
            ->andWhere(':dateDebut <= r.dateDebut')// 31/07 <= 11/07*/
            ->orWhere('r.dateFin IS NULL')
            ->orWhere('r.dateDebut IS NULL')
            ->setParameter('dateFin', $recherche->getDateFin())
            ->setParameter('dateDebut', $recherche->getDateDebut());
    

    Encore une fois, je vous remercie de votre aide (j'ai mis en commentaire l'inverse de ce que je voudrai faire), je pense qu'il faudrait faire un EXCEPT en SQL mais je ne sais pas comment le faire en Doctrine.

    Bonne soirée

    -
    Edité par Smogg 6 juillet 2020 à 23:11:02

    • Partager sur Facebook
    • Partager sur Twitter
      6 juillet 2020 à 23:35:04

      Hello,

      a mon avis tes deux 'Andwhere' sont mal écrits, fait un truc du style

      ->andWhere('r.dateDebut NOT BETWEEN :dateDebut AND :dateFin')
      
      ->setParameters(['dateDebut' => $recherche->getDateFin(), 'dateFin' => $recherche->getDateFin()])

      EDIT: je suis pas 100% mais test aussi dans les parameters 
      $recherche->getDateFin()->format("d-m-Y")

      -
      Edité par armbar 6 juillet 2020 à 23:37:18

      • Partager sur Facebook
      • Partager sur Twitter
        7 juillet 2020 à 8:35:10

        Salut

        C'est un souci de logique, je pense. Si je mets des parenthèses, voici ce que donnerait la requête SQL :

        SELECT Bateau.*
            FROM Bateau
            LEFT JOIN Reservation r ON Bateau.Id = r.bateau_id
                AND Bateau.Id = r.bateau_id
            WHERE (Bateau.visible = true
                    AND :dateDebut NOT BETWEEN r.date_debutAND r.date_fin
                    AND :date_fin NOT BETWEEN r.dateDebut AND r.dateFin)
                OR r.date_fin IS NULL
                OR r.date_debut IS NULL

        Or, ce qu'il te faudrait serait plus du genre de ce qui suit.

        SELECT Bateau.*
            FROM Bateau
            LEFT JOIN Reservation r ON Bateau.Id = r.bateau_id
            WHERE Bateau.visible = true
                AND (:dateDebut NOT BETWEEN r.date_debutAND r.date_fin
                    OR r.date_debut IS NULL)
                AND (:date_fin NOT BETWEEN r.dateDebut AND r.dateFin
                    OR r.date_fin IS NULL)

        Pour ce faire :

        • shoote les troisième et quatrième paramètres du leftJoin() ;
        • change tes orWhere(…) en OR … directement à la suite des BETWEEN dans les andWhere().
        • Partager sur Facebook
        • Partager sur Twitter
          7 juillet 2020 à 12:01:34

          Bonjour,

          Merci pour vos réponses, après modification voici ce que j'ai fait mais me donne toujours le même résultat:

          return $this->createQueryBuilder('Bateau')
                  ->leftJoin('Bateau.reservationBateaux', 'r', 'WITH','Bateau.id = r.bateau' )
                  ->where('Bateau.visible = true');
                  ->andWhere(':dateDebut NOT BETWEEN r.dateDebut AND r.dateFin OR r.dateDebut IS NULL')
                  ->andWhere(':dateFin NOT BETWEEN r.dateDebut AND r.dateFin OR r.dateFin IS NULL')
                  ->setParameter('dateFin', $recherche->getDateFin())
                  ->setParameter('dateDebut', $recherche->getDateDebut());

          Comme je le répète, ça marche pour tous les cas sauf si je fais une recherche qui englobe ma réservation (ex: si j'ai une réservation du 07/07 au 10/07 et que je veux demander une réservation du 01/07 au 12/07) ce la me dit pas qu'il n'est pas disponible.

          Ymox a écrit:

          Salut

          C'est un souci de logique, je pense. Si je mets des parenthèses, voici ce que donnerait la requête SQL :

          SELECT Bateau.*
              FROM Bateau
              LEFT JOIN Reservation r ON Bateau.Id = r.bateau_id
                  AND Bateau.Id = r.bateau_id
              WHERE (Bateau.visible = true
                      AND :dateDebut NOT BETWEEN r.date_debutAND r.date_fin
                      AND :date_fin NOT BETWEEN r.dateDebut AND r.dateFin)
                  OR r.date_fin IS NULL
                  OR r.date_debut IS NULL

          Or, ce qu'il te faudrait serait plus du genre de ce qui suit.

          SELECT Bateau.*
              FROM Bateau
              LEFT JOIN Reservation r ON Bateau.Id = r.bateau_id
              WHERE Bateau.visible = true
                  AND (:dateDebut NOT BETWEEN r.date_debutAND r.date_fin
                      OR r.date_debut IS NULL)
                  AND (:date_fin NOT BETWEEN r.dateDebut AND r.dateFin
                      OR r.date_fin IS NULL)

          Pour ce faire :

          • shoote les troisième et quatrième paramètres du leftJoin() ;
          • change tes orWhere(…) en OR … directement à la suite des BETWEEN dans les andWhere().



          J'ai essayé de remplacer le WITH par ON mais cela ne fonctionne pas et me fait une erreur et de même si j'essaye d'enlever les 2 derniers paramètres de la jointure cela ne fonctionne pas (on dirait qu'il n'y a aucun changement dans le résultat si on met ou pas les 2 derniers paramètres).

          PS:

          armbar a écrit:

          Hello,

          a mon avis tes deux 'Andwhere' sont mal écrits, fait un truc du style

          ->andWhere('r.dateDebut NOT BETWEEN :dateDebut AND :dateFin')
          
          ->setParameters(['dateDebut' => $recherche->getDateFin(), 'dateFin' => $recherche->getDateFin()])

          EDIT: je suis pas 100% mais test aussi dans les parameters 
          $recherche->getDateFin()->format("d-m-Y")

          -
          Edité par armbar il y a environ 12 heures



          J'ai essayé de modifié setParameters mais ça ne fonctionne pas, il ne le veut pas sur une ligne, de même je n'ai pas qu'une seule date, je veux vérifier entre 2 dates

          -
          Edité par Smogg 7 juillet 2020 à 12:09:14

          • Partager sur Facebook
          • Partager sur Twitter
            7 juillet 2020 à 13:06:51

            Smogg a écrit:

            J'ai essayé de remplacer le WITH par ON mais cela ne fonctionne pas et me fait une erreur

            J'avais dit de shooter (donc d'enlever) les troisième et quatrième paramètres, pas de remplacer d'une manière ou d'une autre. Avec l'ORM de Doctrine, tu lies les relations entre elles, les histoires de comment ça se goupille au niveau des tables, c'est Doctrine qui s'en charge.

            Smogg a écrit:

            ex: si j'ai une réservation du 07/07 au 10/07 et que je veux demander une réservation du 01/07 au 12/07 […] ce la me dit pas qu'il n'est pas disponible

            Moi ça me paraît logique : tu as une réservation sur une semaine au milieu d'un mois et quelqu'un veut réserver tout le mois, c'est à mon avis effectivement pas possible vu qu'il y a une semaine déjà réservée.
            Du coup, la question est de savoir ce que tu souhaites faire dans ce cas.

            -
            Edité par Ymox 7 juillet 2020 à 13:07:37

            • Partager sur Facebook
            • Partager sur Twitter
              7 juillet 2020 à 13:28:46

              Ymox a écrit:

              Smogg a écrit:

              J'ai essayé de remplacer le WITH par ON mais cela ne fonctionne pas et me fait une erreur

              J'avais dit de shooter (donc d'enlever) les troisième et quatrième paramètres, pas de remplacer d'une manière ou d'une autre. Avec l'ORM de Doctrine, tu lies les relations entre elles, les histoires de comment ça se goupille au niveau des tables, c'est Doctrine qui s'en charge.

              Smogg a écrit:

              ex: si j'ai une réservation du 07/07 au 10/07 et que je veux demander une réservation du 01/07 au 12/07 […] ce la me dit pas qu'il n'est pas disponible

              Moi ça me paraît logique : tu as une réservation sur une semaine au milieu d'un mois et quelqu'un veut réserver tout le mois, c'est à mon avis effectivement pas possible vu qu'il y a une semaine déjà réservée.
              Du coup, la question est de savoir ce que tu souhaites faire dans ce cas.

              -
              Edité par Ymox il y a 18 minutes


              D'accord! J'ai donc enlevé les deux derniers paramètres comme indiqué, je ne savais pas.

              En faites, je ne veux pas que les bateaux apparaissent, si j'englobe les deux date dans ma recherche (date de début de reservation et date de fin), il me ressort les lignes mais j'aimerai ne pas les avoir.

              J'ai essayer ceci:

              orWhere(':dateFin >= r.dateFin')
              ->andWhere(':dateDebut <= r.dateDebut')

              Mais c'est l'inverse que j'aimerai (retirer les lignes qui ressortent avec cette requête)

              -
              Edité par Smogg 7 juillet 2020 à 13:34:11

              • Partager sur Facebook
              • Partager sur Twitter
                7 juillet 2020 à 14:38:10

                Ta requête est pour avoir les plages de disponibilité d'un bateau (donc avant de soumettre une réservation), ou pour savoir si une réservation donnée est possible (elle vient d'être soumise et on regarde si elle est valide) ? Parce que ce n'est pas exactement la même chose.

                Edit

                Si tu souhaites afficher un calendrier des réservations (première option), je prendrais toutes les réservations qui empiètent d'une manière ou d'une autre sur la plage de dates observée, donc soit la date de début de réservation est dans les limites de la plage observée, soit la date de fin de réservation est dedans. Reste le cas où les deux dates sont en dehors de la plage, le début avant et la fin après. Ce qui donne grosso modo pour la clause WHERE :

                WHERE bateau.visible = true
                -- commence pendant la plage
                    AND (:dateDebut BETWEEN r.dateDebut AND r.dateFin
                -- termine pendant la plage
                        OR :dateFin BETWEEN r.dateDebut AND r.dateFin
                -- commence avant et termine après la plage
                        OR r.dateDebut < :dateDebut AND r.dateFin > :dateFin
                -- pas de réservation
                        OR r.dateDebut IS NULL
                        AND r.dateFin IS NULL)

                Ceci devrait donc te permettre de récupérer les réservations à placer dans un calendrier entre une date de début et une date de fin. Par extension, tout ce qui est en-dehors de ce qui résultera de cette requête, c'est libre.

                Maintenant, il faut se rendre compte qu'avoir des moments libres, c'est pas aussi simple qu'avoir des moments réservés. Les moments réservés sont définis. Les moments libres, eux, sont en fonction des limites de la plage de dates, qui par définition est variable. Trouver le complément des réservations pour avoir les plages de libre, je ne crois pas qu'il y ait d'outil pour calculer ça. Imagine que tu aies des réservations un jour sur deux ou sur trois. Les jours de libres sont les autres, mais tu les détermines comment ? Compter le nombre, c'est simple, savoir lesquels, cela revient à boucher les trous… et c'est encore moins simple du moment qu'il faudrait le faire pour plusieurs bateaux.

                Dans le second cas, la requête peut être une simple question de compter les réservations entre le début et la fin (ainsi "qu'autour") de celle qu'on souhaite valider. Et il se trouve que c'est la même clause WHERE, à ceci près qu'on remplace bateau.visible = true par bateau.id = :leBateauChoisi.

                -
                Edité par Ymox 7 juillet 2020 à 19:40:46

                • Partager sur Facebook
                • Partager sur Twitter
                  7 juillet 2020 à 21:03:29

                  Ma requête est dans le but de voir si les bateaux sont disponible ou pas (j'ai fait un formulaire de recherche qui me permet de demander à l'utilisateur d'afficher la liste des bateaux disponible durant une période), je souhaite donc afficher les bateaux qui ne sont pas réservés durant la période demandé.

                  Il me faut donc vérifier si la date de début ne tombe pas durant la période d'une réservation, vérifier que la date de fin ne tombe pas durant une période de réservation et de vérifier que la réservation n'englobe pas une réservation. Si je fais cette requête là:

                  $this->createQueryBuilder('Bateau')
                          ->leftJoin('Bateau.reservationBateaux', 'r')
                          ->where('Bateau.visible = true')
                          ->andWhere(':dateDebut NOT BETWEEN r.dateDebut AND r.dateFin OR r.dateDebut IS NULL')
                          ->andWhere(':dateFin NOT BETWEEN r.dateDebut AND r.dateFin OR r.dateFin IS NULL')
                          ->setParameter('dateDebut', $recherche->getDateDebut());

                  Voici ma base de donnée:

                  table bateau:

                  Table BateauReservation

                  J'ai bien la liste des bateaux disponibles qui m'est retourné -> si je ne mets aucune date de disponible, j'ai tous les bateaux. Résultats:

                  J'ai bien la liste des bateaux disponibles qui m'est retourné si je mets la date de fin ou de fin dans la période de réservation (donc la liste des bateaux disponible en enlevant ceux qui sont déjà réservé). Résultat:

                  Et:

                  Si jamais j'englobe la date de début de réservation sur une réservation déjà passé, cela ne fonctionne pas (il me met tous les bateaux y compris ceux réservé dans la liste): Résultat (je ne devrais avoir qu'un seul bateau qui devrait apparaître):

                  J'ai essayé avec cette requête mais j'ai toujours le même résultat:

                  $this->createQueryBuilder('Bateau')
                          ->leftJoin('Bateau.reservationBateaux', 'r')
                          ->where('Bateau.visible = true')
                          ->andWhere(':dateDebut NOT BETWEEN r.dateDebut AND r.dateFin OR r.dateDebut IS NULL')
                          ->andWhere(':dateFin NOT BETWEEN r.dateDebut AND r.dateFin OR r.dateFin IS NULL')
                          ->orwhere(' r.dateDebut <= :dateDebut AND r.dateFin >= :dateFin')
                          ->setParameter('dateFin', $recherche->getDateFin())
                          ->setParameter('dateDebut', $recherche->getDateDebut());
                  

                  Comme dit dans la réponse, je cherche à trouvé la bateau de libre, surement dur a avoir mais je me doute qu'on peut y arriver.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 juillet 2020 à 21:11:44

                    Si l'idée est d'avoir uniquement une liste bateaux ayant des disponibilités dans la période observée, sans réel égard pour les périodes exactes de liberté, il pourrait bien suffire de mettre un NOT avant la parenthèse ligne 3 de mon précédent message.  ;)

                    Et sans le NOT, avec un count(bateau.id) et les dates de début et de fin de réservation comme paramètres, tu as la requête qui permet de savoir si la réservation est possible pour les dates choisies. Par contre, je reviens à la charge : pour savoir exactement quand c'est libre ou quand c'est à cheval sur d'autres trucs, c'est plus compliqué. Pas impossible, mais plus difficile.

                    -
                    Edité par Ymox 7 juillet 2020 à 21:14:28

                    • Partager sur Facebook
                    • Partager sur Twitter
                      7 juillet 2020 à 21:33:18

                      Donc j'ai essayé ceci:

                      $this->createQueryBuilder('Bateau')
                              ->leftJoin('Bateau.reservationBateaux', 'r')
                              ->where('Bateau.visible = true')
                              ->andWhere('NOT (:dateDebut BETWEEN r.dateDebut AND r.dateFin OR :dateFin BETWEEN r.dateDebut AND r.dateFin OR r.dateDebut < :dateDebut AND r.dateFin > :dateFin OR r.dateDebut IS NULL AND r.dateFin IS NULL)')
                              ->setParameter('dateFin', $recherche->getDateFin())
                              ->setParameter('dateDebut', $recherche->getDateDebut());


                      Si je mets soit la date de début, soit la date de fin dans la période de réservation, je n'ai aucun bateau.

                      J'ai essayé ceci:

                      $this->createQueryBuilder('Bateau')
                              ->leftJoin('Bateau.reservationBateaux', 'r')
                              ->where('Bateau.visible = true')
                              ->andWhere('NOT (:dateDebut BETWEEN r.dateDebut AND r.dateFin OR :dateFin BETWEEN r.dateDebut AND r.dateFin OR r.dateDebut < :dateDebut AND r.dateFin > :dateFin) OR r.dateDebut IS NULL AND r.dateFin IS NULL')
                              ->setParameter('dateFin', $recherche->getDateFin())
                              ->setParameter('dateDebut', $recherche->getDateDebut());

                      Cela ne marche pas si j'englobe.

                      Comme j'ai dit, je veux pas savoir quels dates sont disponible mais simplement savoir si le bateau est disponible pour toute la période demandé

                      Petite correction de ma part, les symboles n'étaient pas dans le bon sens. Ceci fonctionne correctement!

                      ->andWhere('NOT (:dateDebut BETWEEN r.dateDebut AND r.dateFin OR :dateFin BETWEEN r.dateDebut AND r.dateFin OR r.dateDebut >= :dateDebut AND r.dateFin <= :dateFin) OR r.dateDebut IS NULL AND r.dateFin IS NULL')
                                  ->setParameter('dateFin', $recherche->getDateFin())
                                  ->setParameter('dateDebut', $recherche->getDateDebut());

                      Merci encore de votre aide, c'était super gentil



                      -
                      Edité par Smogg 7 juillet 2020 à 22:29:36

                      • Partager sur Facebook
                      • Partager sur Twitter
                        8 juillet 2020 à 21:45:00

                        Ah oui, tu as changé l'ordre des paramètres pour les comparaisons. J'avais mis OR r.dateDebut < :dateDebut AND r.dateFin > :dateFin, tu as finalement mis OR :dateDebut >= r.dateDebut AND :dateFin <= r.dateFin, ce qui est du point de vue logique exactement la même chose. Par contre, dans la version qui ne fonctionnait pas, tu avais effectivement mis le contraire en ayant uniquement inversé les deux côtés de la comparaison sans changer le signe.

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Problème requette Symfony

                        × 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