IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

des requêtes en fonction des paramètres passés


Sujet :

Symfony PHP

  1. #1
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut des requêtes en fonction des paramètres passés
    Bonjour,

    d'abord la situation:
    - une table animals en relation oneToMany avec deux autres tables ( species et diets )
    - un utilisateur choisi selon quels critères lui sera renvoyée une liste d'animaux (toutes les espèces de vertébrés herbivores par ex)

    Donc deux champs dans un formulaire à remplir ou non.
    Je récupère les données dans le controller ( les id pour les tables )

    Si l'utilisateur choisit uniquement le premier champ ( ex les vertébrés ) et laisse l'autre vide, je ferai une requête qui va sortir tous les animaux vertébrés,
    et le controller renvoie le résultat ( je crée une méthode avec createQuery() )
    S' il choisit uniquement le deuxième, ....une autre requête.
    S'il choisit les deux, je ne sais pas comment faire (je suppose un select from select ? )! mais il faudra une autre requête c'est sûr !

    Donc deux champs => 3 requêtes
    Trois champs => 7 requêtes
    Quatre champs => ...(je ne me souviens plus des cours sur les suites en math du genre Un+1 = 2Un + 1 mais pas sûr )

    J'ai un peu du mal à voir quelle serait la méthode !!! Mais c'est un problème classique
    Je ne peux imaginer que ce soit aussi lourd !

  2. #2
    Expert confirmé Avatar de Séb.
    Profil pro
    Inscrit en
    mars 2005
    Messages
    3 997
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mars 2005
    Messages : 3 997
    Points : 5 665
    Points
    5 665
    Par défaut
    Il faut construire une requête unique dynamiquement.

    Dur de te donner un exemple parlant sans avoir tes tables/colonnes et formulaire de recherche.
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  3. #3
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut
    La requête unique et dynamique , j'imaginais bien quelque chose comme ça, mais je ne vois pas comment c'est fait !
    du coup , voici ma BDD . le formulaire est fait en React.js
    Nom : bdd.png
Affichages : 57
Taille : 58,8 Ko

    C'est bien ça que tu veux quand tu parle de BDD?
    Pour le formulaire, tu veux quoi ?
    Il n'y a vraiment pas d'exemples pour savoir à quoi ça ressemble une requête de ce genre ?

  4. #4
    Expert confirmé Avatar de Séb.
    Profil pro
    Inscrit en
    mars 2005
    Messages
    3 997
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mars 2005
    Messages : 3 997
    Points : 5 665
    Points
    5 665
    Par défaut
    Oui pour les tables/colonnes/bdd c'est ça. Pour le formulaire, savoir ce que l'user peut saisir/chercher aurait aidé à faire une requête plus parlante, mais là c'est suffisant.

    Bon, ci-dessous exemples de requêtes sortant tous les animaux, ou seulement ceux correspondant à une espèce et/ou une diet. Affiche bien à chaque fois le $sql pour bien comprendre ce qui se passe.

    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $idspecies = isset($_GET['species']) ? $pdo->quote($_GET['species']) : 'species_idspecies';
    $iddiet = isset($_GET['diet']) ? $pdo->quote($_GET['diet']) : 'diet_iddiet';
    $sql = <<<SQL
        SELECT ALL id, name
        FROM animals
        WHERE TRUE
            AND species_idspecies = {$idspecies}
            AND diet_iddiet = {$iddiet}
        SQL;

    J'ai quelques helpers SQL (des closures) pour réduire le nombre de lignes :

    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $issetor = fn (&$value, $column) => isset($value) ? $pdo->quote($value) : $column;
     
    $sql = <<<SQL
        SELECT ALL id, name
        FROM animals
        WHERE TRUE
            AND species_idspecies = {$issetor($_GET['species'], 'species_idspecies')}
            AND diet_iddiet = {$issetor($_GET['diet'], 'diet_iddiet')}
        SQL;

    Voilà, ces 2 exemples vont te générer des requêtes...

    Si rien n'est sélectionné :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT ALL id, name
    FROM animals
    WHERE TRUE
        AND species_idspecies = species_idspecies
        AND diet_iddiet = diet_iddiet

    Toutes les colonnes matchent => Pas de filtre, et rassure-toi, c'est une situation prise en compte par l'optimiseur des moteurs de bdd, il n'y aura pas de vérifs inutiles sur toutes tes lignes

    Si un champ du formulaire est valorisé, mettons l'espèce, tu auras :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT ALL id, name
    FROM animals
    WHERE TRUE
        AND species_idspecies = 2345
        AND diet_iddiet = diet_iddiet

    Le filtre est appliqué sur le species_idspecies, le diet_iddiet n'est pas filtrant.

    Si les 2 champs sont renseignés :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT ALL id, name
    FROM animals
    WHERE TRUE
        AND species_idspecies = 2345
        AND diet_iddiet = 3

    Les 2 champs seront bien filtrants.

    Au final, pas besoin de x requêtes, juste d'ajouter à la requête un "AND ..." pour chaque nouveau critère.

    Il n'y a vraiment pas d'exemples pour savoir à quoi ça ressemble une requête de ce genre ?
    Jamais vu, mais pas non plus vraiment cherché.


    PS : je viens de voir que tu avais posté sur le sous-forum Symfony, je ne sais pas s'il existe des solutions Symfony pour gérer cela
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  5. #5
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut
    C'est bien le genre de requête que je cherchais !
    Je ne connaissais pas le WHERE TRUE AND species_idspecies = {$idspecies}...Je vais aller regarder ça de plus près.

    Le formulaire est simple: l'utilisateur peut choisir une espèce, un régime alimentaire ou un continent
    Et justement, si on rajoute le choix des continents (1 ou plusieurs ), j'ai du mal à voir ce que ça donne en dynamique avec une relation many to many!

    Pour Symfony, je récupère les id des champs choisis, je fais un traitement ( si NULL ...) et j'applique une méthode qui exécute la requête sql avec les paramètres
    que je renseigne. méthode = requête dynamique

    On peut faire une requête en sql dans Symfony (au pire si je n'y arrive pas ) !

  6. #6
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut
    Bon, pour l'instant, je n'arrive pas à faire le bon sql:

    ça fonctionne si je mets quelque chose dans les deux champs, mais si je n'en mets qu'un alors ça me renvoie un tableau vide.
    Je ne sais comment retranscrire, avec symfony , je fais:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    public function findAnimals($species, $diets): array
    {
    $entityManager =  $this->getEntityManager();
     
            $query = $entityManager->createQuery(
                'SELECT a.id
                FROM App\Entity\Animals a
                WHERE a.diets = :diets
                    AND a.species = :species'
            )->setParameters(array(
                'diets' => $diets,
                'species' => $species
            ));
     
            return $query->getResult();
    }

    WHERE a.diets = :diets ça pose un problème pour Doctrine !!!

  7. #7
    Expert confirmé Avatar de Séb.
    Profil pro
    Inscrit en
    mars 2005
    Messages
    3 997
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mars 2005
    Messages : 3 997
    Points : 5 665
    Points
    5 665
    Par défaut
    Et justement, si on rajoute le choix des continents (1 ou plusieurs ), j'ai du mal à voir ce que ça donne en dynamique avec une relation many to many!
    Il suffit d'ajouter la jointure et un AND au WHERE :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $issetor = fn (&$value, $column) => isset($value) ? $pdo->quote($value) : $column;
     
    $sql = <<<SQL
        SELECT DISTINCT id, name
        FROM animals
        INNER JOIN animalContinent ON animals.id = animalContinent.animal_id
        WHERE TRUE
            AND species_idspecies = {$issetor($_GET['species'], 'species_idspecies')}
            AND diet_iddiet = {$issetor($_GET['diet'], 'diet_iddiet')}
            AND animalContinent.continent_idcontinent = {$issetor($_GET['continent']), 'animalContinent.continent_idcontinent')}
        SQL;
    Inconvénient ici : tu fais une jointure inutile si pas de filtre sur le continent, mais cela reste largement acceptable si tu n'as pas des millions de lignes

    Pour éviter cela on pourrait reformuler la requête avec un autre helper, comme un $if(), et inclure le filtre dans le critère de jointure (on fait d'1 pierre 2 coups) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $issetor = fn (&$value, $column) => isset($value) ? $pdo->quote($value) : $column;
    $if = fn ($condition, $if_true, $if_false = '') => $condition ? $if_true : $if_false;
     
    $sql = <<<SQL
        SELECT DISTINCT id, name
        FROM animals
        {$if(isset($_GET['continent']), "INNER JOIN animalContinent ON animals.id = animalContinent.animal_id AND animalContinent.continent_idcontinent = {$pdo->quote($_GET['continent'])}")}
        WHERE TRUE
            AND species_idspecies = {$issetor($_GET['species'], 'species_idspecies')}
            AND diet_iddiet = {$issetor($_GET['diet'], 'diet_iddiet')}
        SQL;
    Note le SELECT DISTINCT à la place du SELECT ALL, pour éviter les doublons potentiels de la jointure n:n
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  8. #8
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut
    J'ai encore du mal à comprendre:

    si dans ma requête je passe plusieurs id de continents, il va falloir une boucle quelque part pour récupérer tous les animaux qui appartiennent à ces continents !
    Ce que tu me montres, pour moi, ne fonctionne que si l'utilisateur ne sélectionne qu'un continent .

    Je doute qu'on puisse faire des boucles dans du sql.
    Si je me trompe, je veux bien apprendre comment on fait.

  9. #9
    Expert confirmé Avatar de Séb.
    Profil pro
    Inscrit en
    mars 2005
    Messages
    3 997
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : mars 2005
    Messages : 3 997
    Points : 5 665
    Points
    5 665
    Par défaut
    Ce que tu me montres, pour moi, ne fonctionne que si l'utilisateur ne sélectionne qu'un continent .
    Ce point n'a jamais été abordé. C'est pour ça que je te demandais ton formulaire
    Dans le principe il faut remplacer les "= ..." par des "IN(...)" et construire la liste d'IDs à placer dans le IN().

    Je doute qu'on puisse faire des boucles dans du sql.
    On peut => https://dev.mysql.com/doc/refman/8.0/en/loop.html
    Mais ce n'est pas une question de boucle ici.
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  10. #10
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut
    Ha oui !
    j'ai oublié beaucoup de choses en sql ( et en plus je suis débutant )
    Mais les IN, j'aurai du y penser !!!

    Bon, je vais coder tout ça proprement et voir si tout fonctionne.

  11. #11
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    novembre 2020
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : novembre 2020
    Messages : 193
    Points : 87
    Points
    87
    Par défaut
    Bon, me revoilà !

    Alors le bilan: ça fonctionne et j'ai réussi à le faire en DQL ! MAIS !!!!

    Un exemple: j'ai choisi deux continents.
    Je vais trouver les animaux qui appartiennent à un ou l'autre continent , ou les deux !!

    Et dans le cas ou je souhaiterais que les animaux sélectionnés se trouvent exclusivement dans ces deux continents ? ( même chose avec trois ou quatre )
    Je vois encore pointer une boucle, mais peut-être à cause de mon faible niveau: je ne vois pas comment mettre de WHERE ... AND... autant de fois qu'il y a de continents

Discussions similaires

  1. Réponses: 0
    Dernier message: 19/08/2011, 10h36
  2. Réponses: 9
    Dernier message: 29/08/2008, 09h38
  3. Réponses: 3
    Dernier message: 22/08/2008, 00h13
  4. [MySQL] Suppression de données à partir des paramètres passés en lien
    Par cyril3d dans le forum PHP & Base de données
    Réponses: 15
    Dernier message: 01/04/2008, 15h52
  5. Réponses: 1
    Dernier message: 29/03/2006, 12h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo