Cours pratique d'initiation à PHP/MySQL | Sommaire ![]() |
Pour la recherche de rounds dans la base, on va avoir besoin :
Le formulaire search_form.html doit permettre à l'utilisateur de chercher :
On veut aussi pouvoir chercher tous les rounds joués par un joueur donné sur une map donnée (par exemple tous les rounds joués par "Bob L'Éponge" sur la map "Raven Office"). De façon générale on veut pouvoir affiner les recherches en donnant plusieurs critères de recherche.
Comme on a déjà créé un formulaire pour la saisie des rounds et que le formulaire de recherche va beaucoup lui ressembler, on commence par faire une copie de insert_form.html en la renommant search_form.html et on y fait les 4 modifications suivantes :
Le script search_action.php va procéder en 8 étapes :
Comme les étapes 3 à 8 ont déjà été implémentées dans le script select_all.php (ce sont les étapes 2 à 7 de ce script) on va utiliser ce dernier comme point de départ pour le script search_action.php.
Faire une copie du fichier select_all.php et la renommer search_action.php.
Dans search_action.php, remplacer le titre Liste de tous les rounds par Résultat de la recherche.
Evidemment, si on clique maintenant sur le bouton "Chercher" de notre formulaire de recherche on obtiendra toujours la liste de tous les rounds (essayer). Il faut donc maintenant modifier la requête SELECT dans le script search_action.php pour qu'elle prenne en compte les critères de recherche saisis dans le formulaire.
Par exemple, pour chercher tous les rounds joués sur la map saisie dans le champ "map" du formulaire, on fabrique la requête :
<?php
$map = $_GET['map'];
$ma_requete = "SELECT * FROM `rounds` WHERE `map`='$map' ORDER BY `date`,`num_round`";
...
?>
<HTML> <BODY> ... </BODY> </HTML> <?php
...
?>
|
La clause WHERE map='$map' de la requête SELECT permet de ne sélectionner que les enregistrements de la table rounds pour lesquels la valeur de la colonne map est égale à à celle de la variable PHP $map (chaîne de caractères).
Modifier la requête SELECT fabriquée par le script search_action.php et faire afficher cette requête AVANT de l'envoyer au serveur MySQL.
Tester la recherche sur différents noms de maps. Que se passe-t-il si on laisse le champ "map" vide ? Est-ce le comportement attendu ?
En résumé, les problèmes qu'on doit résoudre pour cette recherche sur le champ "map" sont :
<?php
$map = $_GET['map'];
#$ma_requete = "SELECT * FROM `rounds` WHERE `map`='$map' ORDER BY `date`,`num_round`";
$ma_requete = "SELECT * FROM `rounds`";
if ($map != "") {
$ma_requete .= " WHERE `map`='$map'";
}
$ma_requete .= " ORDER BY `date`,`num_round`";
echo $ma_requete;
...
?>
... |
<?php
$map = $_GET['map'];
$ma_requete = "SELECT * FROM `rounds`";
if ($map != "") {
#$ma_requete .= " WHERE `map`='$map'";
$ma_requete .= " WHERE `map` LIKE '%$map%'";
}
$ma_requete .= " ORDER BY `date`,`num_round`";
echo $ma_requete;
...
?>
... |
Faire les modifications nécessaires dans le script search_action.php et tester ...
On veut maintenant prendre en compte le critère de date :
<?php
$jour = $_GET['jour'];
$mois = $_GET['mois'];
$annee = $_GET['annee'];
$map = $_GET['map'];
$ma_requete = "SELECT * FROM `rounds` WHERE `date` LIKE '%$annee-%$mois-%$jour'";
if ($map != "") {
$ma_requete .= " AND `map` LIKE '%$map%'";
}
$ma_requete .= " ORDER BY `date`,`num_round`";
echo $ma_requete;
...
?>
... |
N.B. : ATTENTION, on ne peut avoir qu'une seule clause WHERE ! On doit donc remplacer l'instruction $ma_requete .= " WHERE map LIKE '%$map%'"; par $ma_requete .= " AND map LIKE '%$map%'";.
Modifier le script search_action.php et tester.
Modifier le script search_action.php pour qu'il cherche les rounds gagnés par le joueur saisi dans le champ "joueur" du formulaire. Tester.
Maintenant on voudrait que la requête SELECT cherche tous les rounds auxquels le joueur a participé et pas seulement ceux où il a fini 1er :
<?php
$jour = $_GET['jour'];
$mois = $_GET['mois'];
$annee = $_GET['annee'];
$map = $_GET['map'];
$joueur = $_GET['joueur'];
$ma_requete = "SELECT * FROM `rounds` WHERE `date` LIKE '%$annee-%$mois-%$jour'";
if ($map != "") {
$ma_requete .= " AND `map` LIKE '%$map%'";
}
if ($joueur != "") {
$ma_requete .= " AND `place1` LIKE '%$joueur%'";
$ma_requete .= " OR `place2` LIKE '%$joueur%'";
...
$ma_requete .= " OR `place6` LIKE '%$joueur%'";
}
$ma_requete .= " ORDER BY `date`,`num_round`";
echo $ma_requete;
...
?>
... |
Modifier le script search_action.php et tester. Rechercher tous les rounds joués par un joueur donné à une date donnée. Tiens, il se trouve qu'on obtient même les rounds joués par ce joueur mais à une autre date !?!
Pour comprendre le phénomène qu'on vient d'observer, il faut d'abord bien comprendre ce que fait le moteur du serveur MySQL lorsqu'il reçoit une requête de la forme :
SELECT * FROM `rounds` WHERE premier_test OR second_test
Voici comment il procède : il passe en revue les enregistrements de la table SQL rounds les uns après les autres et, pour chacun, effectue d'abord le premier_test.
Maintenant, on voudrait savoir comment se comporte le moteur SQL lorsqu'il reçoit une requête de la forme :
SELECT * FROM `rounds` WHERE test A AND test B OR test C
Cette fois la clause WHERE contient les opérateurs logiques AND et OR. Le point essentiel ici est que l'opérateur AND est prioritaire sur l'opérateur OR. En fait, tout se passe comme si on avait la requête :
SELECT * FROM `rounds` WHERE premier_test OR second_test
où le premier_test est test A AND test B et le second_test est test C. Si un enregistrement réussit le premier_test (pour cela il doit réussir les 2 tests : test A et test B), alors il est sélectionné mais s'il échoue alors il peut encore se rattrapper en passant le test C.
En fait, la requête
SELECT * FROM `rounds` WHERE test A AND test B OR test C
est rigoureusement équivalente à la requête :
SELECT * FROM `rounds` WHERE (test A AND test B) OR test C
Pour vérifier qu'on a bien compris, rien de tel qu'un peu de pratique sur un exemple concret. Supposons que la table rounds contienne les enregistrements suivants :
date | place1 | place2 |
---|---|---|
2002-11-21 | Bob | Reznor |
2002-11-21 | eProm | Bob |
2003-01-13 | Bob | Shakal |
2003-01-13 | Reznor | Bob |
Trouver (en utilisant votre moteur SQL intégré) ceux qui vont être sélectionnés par la requête :
SELECT * FROM `rounds` WHERE date='2002-11-21' AND place1='Bob' OR place2='Bob'
Il y en a 3 ! Si l'objectif de la requête ci-dessus était de sélectionner seulement les rounds joués le 2002-11-21 où Bob a fini soit 1er soit 2ème c'est raté ! N'oublions pas que tout se passe comme si on avait des parenthèses autour de date='2002-11-21' AND place1='Bob'. Elle est donc rigoureusement équivalente à la requête :
SELECT * FROM `rounds` WHERE (date='2002-11-21' AND place1='Bob') OR place2='Bob'
Mais si on veut que cette requête renvoie les rounds souhaités, c'est autour de place1 = 'Bob' OR place2 = 'Bob' qu'on doit mettre des parenthèses :
SELECT * FROM `rounds` WHERE date='2002-11-21' AND (place1='Bob' OR place2='Bob')
Vérifier (toujours en utilisant votre moteur SQL intégré) que cette dernière requête sélectionne bien les rounds joués le 2002-11-21 où Bob a fini soit 1er soit 2ème.
Compte-tenu des explications (un peu longues il est vrai) ci-dessus, modifier le script search_action.php pour que la recherche de tous les rounds joués par un joueur donné à une date donnée fonctionne. Ne pas oublier de tester ...
On veut maintenant prendre en compte le critère Numéro de round. La solution ci-dessous est-elle correcte ?
<?php
$jour = $_GET['jour'];
$mois = $_GET['mois'];
$annee = $_GET['annee'];
$num_round = $_GET['num_round'];
$ma_requete = "SELECT * FROM `rounds` WHERE `date` LIKE '%$annee-%$mois-%$jour'";
if ($num_round != "") {
$ma_requete .= " AND `num_round` LIKE '%$num_round%'";
}
...
?>
... |
Par exemple si on veut avoir la liste des premiers rounds joués à chaque rencontre, on va saisir 1 dans le champ "num_round". Que va-t-il se passer si la table rounds contient des enregistrements dont la colonne num_round a la valeur 10 ?
Dans le cas des champs numériques, il vaut donc mieux utiliser la solution :
<?php
...
if ($num_round != "") {
$ma_requete .= " AND `num_round`='$num_round'";
}
...
?>
... |
Modifier le script search_action.php pour prendre en compte le critère Numéro de round. Tester.
Modifier le script search_action.php pour prendre en compte le critère Nombre de joueurs. Tester.
Finalement, on veut pouvoir sélectionner les rounds joués sur un ou plusieurs jeux donnés. Pour cela on doit commencer par modifier le formulaire search_form.html en remplaçant les 4 boutons de type "radio" (dont un à la fois seulement peut être enfoncé) par des "cases à cocher". De plus, par défaut, on voudrait que la recherche s'effectue sur l'ensemble des jeux donc il faut que, par défaut, toutes ces "cases à cocher" soient cochées.
Dans le formulaire search_form.html, faire les 3 modifications suivantes pour chacune des balises <INPUT> de type "radio" :
<INPUT type="checkbox" name="CS" value="1" checked>
Visualiser ce nouveau formulaire.
Dans le script search_action.php, la détection de l'état des cases à cocher (cochée ou pas cochée) fonctionne de la façon suivante :
Pour le vérifier, il suffit de placer les instructions
<?php
print_r($_GET);
exit;
...
?>
... |
au début du script search_action.php et de faire quelques essais (ne pas oublier de les retirer ensuite).
La prise en compte de l'état des cases à cocher pour la fabrication de la requête SQL peut se faire de la façon suivante :
<?php
$jour = $_GET['jour'];
$mois = $_GET['mois'];
$annee = $_GET['annee'];
$ma_requete = "SELECT * FROM `rounds` WHERE `date` LIKE '%$annee-%$mois-%$jour'";
if ( ! isset($_GET['CS']) ) {
$ma_requete .= " AND `jeu`<>'CS'";
}
if ( ! isset($_GET['SoF2']) ) {
$ma_requete .= " AND `jeu`<>'SoF2'";
}
...
?>
... |
La fonction isset() permet de savoir si une variable ou un élément de tableau est défini ou pas. Elle renvoie TRUE si c'est le cas et FALSE sinon. Ici on fait le test suivant :
if ( ! isset($_GET['CS']) ) { ... }
On a placé l'opérateur de négation ! devant la valeur renvoyée par la fonction isset() ce qui revient à faire le test : « si l'élément de tableau $_GET['CS'] n'est pas défini alors... »
Modifier le script search_action.php pour prendre en compte l'état des cases à cocher du formulaire search_form.html. Tester.
N.B. : A aucun moment on n'a utilisé la valeur de l'élément de tableau $_GET['CS']. Au fait quelle est cette valeur (quand elle existe) ?
Page d'accueil de Hervé Pagès | Contact : herve.pages@free.fr |