Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :Listes déroulantes reliées en PHP
Dans cette
formation Php, nous souhaitons aboutir le développement des
listes déroulantes en cascade. Nous avions apporté la solution par le
code client Javascript. La seconde
liste déroulante attend le choix émis au travers de la première, pour se remplir en conséquence. Aujourd'hui, nous souhaitons que l'offre réagisse en fonction des mises à jour en
base de données. Si de nouveaux éléments sont insérés, ils doivent être dynamiquement proposés par ces
listes reliées entre elles. Dans la
formation Javascript, nous n'avions pu que simuler ce principe. Le code client ne peut pas attaquer les
bases de données.
Sources et présentation de la problématique
Avant de débuter, il est donc nécessaire de récupérer les travaux précédents ainsi que les informations de base de données.
La décompression fournit le fichier de la page Web principale à la racine. Il est nommé
index.php. Il est accompagné de ses ressources externes dans les sous dossiers. Nous y reviendrons en temps voulu.
Comme nous l'avait enseigné la
formation pour débuter la programmation en Php, ce projet doit être référencé dans
EasyPhp. Un nom doit lui être attribué et l'adresse issue de l'explorateur Windows doit être renseignée. Bien sûr les deux serveur,
Http et
Database, doivent être démarrés.
Dès lors, l'application serveur apparaît dans la liste des projets émulés par
EasyPhp.
- Cliquer sur son lien pour accéder à sa page d'accueil,
Une
liste déroulante se propose en haut de la page Web, au-dessus des deux calques destinés à la restitution des informations.
- Cliquer sur cette liste déroulante pour déployer son contenu,
Vous accédez ainsi à l'énumération de quelques départements. Notre source de données archive en effet des idées de sorties.
- Cliquer sur l'un des départements pour émettre un choix,
Aussitôt, une image miniature représentant la zone géographique, se charge dans le cadre de droite. Et dans le même temps, une seconde
liste déroulante apparaît. Cette dernière est bien entendu reliée à la première. Elle ne propose que les villes appartenant au département sélectionné. Si vous changez de département dans la première
liste déroulante, le contenu des villes dans la seconde s'adapte automatiquement.
En revanche, si vous validez un choix de ville à l'aide de la seconde
liste déroulante, vous constatez que la page est réinitialisée. Un
PostBack est effectivement généré pour transmettre ces données au serveur. Et comme nous l'avions appris, un
PostBack est un aller-retour vers le serveur. En conséquence, il recharge intégralement la page Web.
Nous pallierons ce défaut dans une prochaine formation grâce à des techniques de
programmation Ajax. Nous traiterons les données réceptionnées sur le serveur à l'aide d'une page externe qui restituera son traitement en lieu et place. De fait, nous conservons l'affichage que nous avions défini.
Nous proposons désormais de constater les imbrications de code ayant conduit à ce résultat. En effet, il va s'agir dans cette formation de
remplir dynamiquement ces
listes déroulantes, en fonction des potentielles mises à jour de la
base de données.
- A la racine du dossier de décompression, cliquer droit sur le fichier index.php,
- Dans le menu contextuel, choisir de l'ouvrir avec un éditeur tel que le Notepad++,
Entre les lignes 46 et 61 pour un éditeur Notepad, vous notez la présence du
formulaire Html avec sa
méthode Post, appelant la
page index.php elle-même. La première
liste déroulante est nommée
choix_dep. Elle est remplie de façon statique. Nous devrons pallier cette méthode pour l'implémenter en fonction des données issues de la
base de données. La seconde
liste déroulante n'existe pas encore. Un choix de département dans la première
liste déroulante appelle la
fonction Javascript charger_villes. Cette dernière est écrite à partir de la ligne 92 pour un éditeur Notepad. Elle questionne la
fonction retour_villes d'un script externe situé dans le
sous dossier js. C'est en fonction des valeurs qu'elle retourne, les villes correspondant au département choisi, qu'elle construit à la volée cette seconde
liste déroulante.
- A la racine du dossier de décompression, double cliquer sur le sous dossier js pour l'ouvrir,
- Puis, cliquer droit sur le fichier villes_dep.js,
- Dans le menu contextuel, choisir de l'ouvrir avec un éditeur comme le Notepad,
Vous y notez effectivement la présence de la
fonction retour_villes :
function retour_villes(le_dep)
{
var chaine_villes="";
switch(le_dep)
{
case "07":
chaine_villes = "Alba la Romaine|Annonay ...";
break;
case "26":
chaine_villes = "Bourg de Péage|Bourg lès Valence| ...";
break;
case "38":
chaine_villes = "Bourgoin Jallieu|Chamrousse|Echirolles| ...";
break;
case "69":
chaine_villes = "Condrieu|Ecully| ...";
break;
case "73":
chaine_villes = "Chambéry|Le bourget du lac| ...";
break;
}
return chaine_villes;
}
Cette fonction attend le numéro du département correspondant au choix de l'internaute émis depuis la liste déroulante. En fonction de ce numéro, elle retourne dans une chaîne de texte, toutes les villes liées. C'est ainsi qu'elles sont réceptionnées par le
code Javascript pour construire et remplir la seconde
liste déroulante en cascade.
Désormais, ces informations doivent devenir dynamiques. Les villes peuvent évoluer et s'enrichir mais les départements aussi. Nous proposons donc de questionner la
base de données et de récréer ce
script à la volée. Nous savons
créer et écrire dans des fichiers, comme nous l'avons appris au travers de formations Php. Ainsi, à chaque choix de l'internaute dans la première
liste déroulante, le contenu de la seconde s'adaptera sans solliciter le serveur. Nous gardons à l'esprit l'importance de bien équilibrer les charges pour les sites Web jouissant d'un fort trafic.
Importer les données en base MySql
Pour atteindre l'objectif de cette formation, nous devons disposer de données. Elles sont proposées au
format SQL dans le
sous dossier bdd du dossier de décompression. Il s'agit de remplir la
table liste_id de la
base de données ids que nous avions créée au travers de la
formation Php pour importer des données en base MySql. Si cette table et cette base de données n'existent pas, vous devez vous y référer pour les créer.
- Depuis l'interface d'EasyPhp, cliquer sur le bouton Open du module MySql Administration,
- Dans le volet gauche de PhpMyAdmin, cliquer sur le lien de la base de données ids,
- Puis, en haut de la fenêtre, cliquer sur l'onglet Importer,
- Cliquer alors sur le bouton Parcourir pour désigner le fichier d'importation,
- Dans le sous dossier bdd, double cliquer sur le fichier debut_id.sql,
- Conserver tous les autres choix par défaut et cliquer sur le bouton Exécuter en bas de page,
Un message de confirmation apparaît à l'issue du traitement.
- Dans le volet de gauche, cliquer sur la table liste_id de la base de données ids,
Nous accédons ainsi au contenu de la table et pouvons consulter les données importées. Cette dernière propose désormais 1046 enregistrements. Les départements sont listés dans le
champ liste_dep tandis que les villes sont archivées dans le
champ liste_ville.
Pour
charger dynamiquement les listes déroulantes sur la page Web, le
code Php doit accéder aux données de cette
base MySql. Et pour cela, le compte utilisateur que nous avions défini dans la formation pour accéder aux fichiers externes, doit être créé s'il n'existe pas :
- Nom d'utilisateur : codePHP,
- Mot de passe : php123bd,
- Nom d'hôte : Votre adresse locale attribuée par EasyPhp, ici : 127.0.0.1,
Vous devez définir les droits administrateurs en cochant la
case Tout cocher.
Connecter la base de données MySql
Pour reconstruire le
script Javascript de façon dynamique, donc par le
code Php, nous devons commencer par récupérer la liste de chaque département. Et pour chacun d'eux, nous devons extraire toutes les villes qu'ils comportent sans doublons. Nous devons donc exécuter une
requête SQL avec une
clause DISTINCT sur la
base de données ids. Pour exécuter une requête sur la base de données, nous devons commencer par établir la
connexion à cette dernière. Il s'agit simplement de reconstruire la
chaîne de connexion, avec les identifiants, en entête de code.
- Revenir dans le code de la page index.php,
- En entête, juste avant la déclarative Html, ajouter la section Php suivante :
<?php
$liaison = mysqli_connect("127.0.0.1", "codePHP", "php123bd");
mysqli_select_db($liaison, "ids");
?>
<html xmlns="https://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
...
Nous créons la
chaîne de connexion habituelle, mémorisée sous le
nom de variable $liaison, grâce à la
fonction Php mysqli_connect. Pour cela, nous lui passons les paramètres du nom d'hôte, du nom d'utilisateur et de son mot de passe associé. C'est alors la
fonction Php mysqli_select_db qui établit la liaison selon cette
chaîne de connexion en premier paramètre et le
nom de la base de données en second.
Souvenez-vous, toute connexion ouverte doit être fermée à l'issue des traitements.
- En toute fin de code, après la balise Html fermante, ajouter la section Php suivante :
...
</script>
</html>
<?php
mysqli_close($liaison);
?>
Comme nous en avons l'habitude désormais, nous exploitons la
fonction Php mysqli_close, avec la chaîne de connexion en paramètre, pour libérer les ressources.
Si vous rechargez la page d'accueil et qu'aucune erreur n'est générée, cela signifie que la
liaison est correctement établie.
Ecrire un code Javascript en PHP
Désormais, nous allons pouvoir attaquer la
base de données pour en extraire la substance.
- En entête de code, après l'établissement de la connexion, ajouter les instructions Php suivantes :
<?php
$liaison = mysqli_connect("127.0.0.1", "codePHP", "php123bd");
mysqli_select_db($liaison, "ids");
$requete = "SELECT DISTINCT liste_ville, liste_dep FROM liste_id ORDER BY liste_dep, liste_ville;";
$retours = mysqli_query($liaison, $requete);
?>
...
Dans la
variable $requete, nous mémorisons la
syntaxe Sql permettant de récupérer chaque ville sans redondance (DISTINCT liste_ville) avec le nom du département d'appartenance (liste_dep), à partir de la
table liste_id (FROM liste_id). Le tout est
trié croissant en priorité sur le département puis sur la ville grâce à la
clause ORDER BY. Nous exécutons cette
requête sur la
base de données grâce à la
fonction Php mysqli_query. Il en résulte un
tableau de variables représenté par la
variable $retours, déclarée et affectée à la volée. Chaque rangée de ce tableau correspond désormais à un enregistrement différent.
Nous devons parcourir l'ensemble de ces
enregistrements grâce à une
boucle while, comme nous l'avons appris. Il s'agit pour un même département, de récupérer la ville et de la concaténer dans une chaîne, afin de reconstruire le
script au fur et à mesure. Il s'agit donc aussi de détecter le changement de département, pour poursuivre l'
instruction switch du script dans une autre branche. Mais pour pouvoir écrire dans ce fichier de script, nous devons y accéder en écriture avant la boucle et le refermer à l'issue.
- A la suite du code précédent, ajouter les instructions suivantes :
<?php
$liaison = mysqli_connect("127.0.0.1", "codePHP", "php123bd");
mysqli_select_db($liaison, "ids");
$requete = "SELECT DISTINCT liste_ville, liste_dep FROM liste_id ORDER BY liste_dep, liste_ville;";
$retours = mysqli_query($liaison, $requete);
$fichier = fopen("js/villes_dep.js", "w");
fclose($fichier);
$fichier = fopen("js/villes_dep.js", "w+");
$chaine = ""; $le_dep=""; $chaine_dep="";
while($retour = mysqli_fetch_array($retours))
{
}
fclose($fichier);
?>
...
Nous exploitons donc la
fonction Php fopen qui permet de charger en mémoire le fichier dont le chemin lui est passé en paramètre. Comme nous y accédons en écriture brute (w en second paramètre), nous écrasons ce fichier. Et comme nous le fermons dans la foulée par la
fonction fclose, nous le vidons de son contenu. Puis, nous le rouvrons cette fois avec le
paramètre w+. Nous y accédons donc en écriture pour ajouter les données les unes à la suite des autres. Puis, nous initions la
boucle while qui permet de parcourir l'ensemble des enregistrements résultants de la
requête. C'est la
fonction Php mysqli_fetch_array qui permet de découper l'information de chaque enregistrement sur les champs qu'il contient. Ces valeurs de champs sont ainsi chargées dans un autre
tableau de variables ($retour au singulier) ainsi affecté à la volée. A l'issue de la boucle, nous n'oublions pas de décharger le fichier de la mémoire.
Désormais, il va donc s'agir de reconstruire ce
script en fonction des informations récupérées en
base de données. Mais avant cela, nous proposons de réaliser une petite vérification intermédiaire.
- Enregistrer les modifications et basculer sur le navigateur Web,
- Rafraîchir la page avec la touche F5 du clavier par exemple,
- Puis, éditer le fichier villes_dep.js,
Comme vous le constatez, grâce à la
fonction fopen accédant en écriture (w), ce
script externe est désormais vidé de son contenu.
Avant d'y ajouter son code construit dynamiquement, nous devons considérer que le début et la fin de ce
script sont statiques. Nous proposons donc de répliquer ces instructions constantes, avant et après la
boucle while.
- Au-dessus et en-dessous de la boucle while, ajouter les instructions Php suivantes :
...
$fichier = fopen("js/villes_dep.js", "w+");
$chaine = ""; $le_dep=""; $chaine_dep="";
fwrite($fichier, "function retour_villes(le_dep)\r\n");
fwrite($fichier, "{\r\n\tvar chaine_villes='';\r\n");
fwrite($fichier, "\r\n\tswitch(le_dep)\r\n\t{\r\n");
while($retour = mysqli_fetch_array($retours))
{
}
fwrite($fichier, "\t}\r\n\r\n\treturn chaine_villes;\r\n}");
fclose($fichier);
?>
C'est la
fonction Php fwrite qui permet d'écrire dans le fichier ouvert en mémoire par la
fonction fopen. Souvenez-vous, les séquences
\r\n permettent de simuler un saut de ligne. La séquence
\t quant à elle, permet de reproduire une tabulation pour l'indentation du code.
- Enregistrer les modifications et basculer sur le navigateur Web,
- Rafraîchir la page à l'aide de la touche F5,
- Puis, éditer le fichier de script externe,
Comme vous le constatez, nous avons parfaitement reconstruit le début et la fin du code de la fonction de ce script externe. Désormais, nous devons ajouter l'énumération des départements et pour chacun, la concaténation des villes leur appartenant. Ces instructions doivent être écrites dans les bornes de l'
instruction switch, Ã chaque passage dans la
boucle.
- Dans les bornes de la boucle while et juste après, ajouter les instructions Php mentionnées en gras :
...
$fichier = fopen("js/villes_dep.js","w+");
$chaine = ""; $le_dep=""; $chaine_dep="";
fwrite($fichier, "function retour_villes(le_dep)\r\n");
fwrite($fichier, "{\r\n\tvar chaine_villes='';\r\n");
fwrite($fichier, "\r\n\tswitch(le_dep)\r\n\t{\r\n");
while($retour = mysqli_fetch_array($retours))
{
if($retour["liste_dep"] != $le_dep)
{
if($le_dep!="")
{
$chaine = rtrim($chaine,"|");
$chaine .="';\r\n";
$chaine .= "\t\t\tbreak;\r\n";
}
$le_dep = $retour["liste_dep"];
$chaine_dep .= $retour["liste_dep"]."|";
$chaine .= "\t\tcase '".substr($le_dep,0,2)."':\r\n";
$chaine .= "\t\t\tchaine_villes ='";
}
else
{
$chaine .= trim(utf8_encode($retour["liste_ville"]))."|";
}
}
$chaine = rtrim($chaine,"|");
$chaine .="';\r\n";
$chaine .= "\t\t\tbreak;\r\n";
fwrite($fichier, $chaine);
fwrite($fichier, "\t}\r\n\r\n\treturn chaine_villes;\r\n}");
fclose($fichier);
?>
A chaque passage, nous commençons par vérifier si le département pour l'enregistrement précédent, est différent de l'actuel (if($retour["liste_dep"] != $le_dep)). Dans ce cas en effet, nous devons terminer la précédente chaîne tout en créant la nouvelle
branche case du switch Javascript. Mais il ne faut pas que le département mémorisé dans la variable soit vide ($le_dep!=""). Sinon nous comprenons qu'il s'agit du premier passage et donc qu'aucune chaîne de villes n'a encore été reconstruite. Donc s'il n'est pas vide, nous fermons la simple côte et ajoutons l'
instruction break signifiant que la branche est terminée. Le raisonnement semble inversé car nous n'avons pas encore écrit dans cette chaîne. Mais souvenez-vous, nous sommes dans une
boucle. Le traitement est récursif. Il faut considérer ce qui a pu se produire au passage précédent. Puis, nous créons la nouvelle
branche case avec le début de la chaîne pour l'affectation de la
variable chaine_villes. Notez que nous en profitons pour concaténer tous les départements dans la
variable $chaine_dep. Elle sera utile plus tard.
Dans le cas contraire, donc lorsqu'il ne s'agit pas d'un nouveau département, nous poursuivons l'énumération des villes dans la concaténation. La
fonction Php trim supprime les espaces potentiels en bouts de chaîne. La
fonction utf8_encode convertit l'information selon le système d'encodage en vigueur dans la page Web, pour la gestion des accents.
Au sortir de la boucle, nous n'oublions pas de réaliser le même traitement qu'au changement de département, pour fermer la dernière chaîne concaténée et ponctuer la syntaxe.
- Enregistrer les modifications et basculer sur le navigateur Web,
- Rafraichir la page et sélectionner un département dans la liste déroulante, par exemple : 26-Drome,
- Puis, déployer la seconde liste déroulante créée à la volée par le code Javascript :
Comme vous le constatez, les villes de ce département sont beaucoup plus nombreuses qu'à l'origine. Il s'agit bien des villes du département sélectionné et elles sont énumérées dans l'ordre alphabétique sans redondance. Si vous changez de département, par exemple Ardèche ou Isère, les villes de la seconde liste déroulante s'adaptent aussitôt. Nous avons donc réussi notre pari. Nous avons recréé la
fonction Javascript dynamiquement par le
code Php. Ainsi, à chaque nouveau chargement, les départements et villes doivent être réactualisés, en fonction des mises à jour survenues dans la
base de données MySql. Si vous éditez le script externe, vous constatez que la fonction a en effet parfaitement été reconstruite.
Comme ce script est chargé naturellement dans la
section head de la
page Web index.php :
<script language='javascript' id='cible' src='js/villes_dep.js'></script>
Il en résulte l'
actualisation dynamique des listes déroulantes reliées entre elles. Il est important de comprendre que toutes les actions des internautes au travers des listes ne sollicitent pas le serveur. Par reconstruction dynamique du
script externe, la main est passée au
code Javascript. C'est donc la machine du client qui gère ces opérations.
En revanche à ce stade, un problème persiste. La seconde liste réagit bien en fonction de la première. Mais la liste des départements est complètement statique. Elle est écrite dans le flux Html de la page Web. En conséquence, elle ne tient pas compte des informations issues de la base de données :
...
<select id="choix_dep" name="choix_dep" class="liste" onChange="charger_villes()">
<option value="00">Sélectionnez un département</option>
<option value="07-Ardèche">07-Ardèche</option>
<option value="26-Drome">26-Drome</option>
<option value="38-Isère">38-Isère</option>
<option value="69-Rhone">69-Rhone</option>
<option value="73-Savoie">73-Savoie</option>
</select>
...
Si vous choisissez le département de la Savoie, vous constatez que la
liste liée des villes est vide. Ceci est tout à fait logique. Ce département n'existe pas en
base de données. Donc la correspondance n'a pas été créée dans le
script externe. C'est la raison pour laquelle nous avons mémorisé la liste de tous les départements dans la
variable $chaine_dep. Nous devons l'exploiter pour reconstruire dynamiquement cette première
liste déroulante.
- Dans les bornes des balises Select de la liste déroulante des départements, remplacer le code Html statique par le code Php dynamique suivant :
...
<select id="choix_dep" name="choix_dep" class="liste" onChange="charger_villes()">
<?php
$tout_dep = explode("|",rtrim($chaine_dep,"|"));
echo "<option value='0'>Choisir un département</option>";
foreach($tout_dep as $un_dep)
{
echo "<option value='".utf8_encode($un_dep)."'>".utf8_encode($un_dep)."</option>";
}
?>
</select>
...
Grâce à la
fonction Php explode que nous connaissons, nous découpons la chaîne des départements sur le délimiteur (|). Il en résulte un
tableau de variables nommé
$tout_dep. Nous le parcourons grâce à une
boucle foreach que nous avons présentée lors d'une précédente formation. A chaque passage, nous recréons dynamiquement une ligne supplémentaire dans la liste déroulante, avec la valeur du département, grâce à la
balise Html option concaténée.
- Enregistrer les modifications et basculer sur le navigateur Web,
- Rafraîchir la page Html et déployer la première liste déroulante,
Comme vous le remarquez, l'offre est moins généreuse. Mais cette fois, elle est conforme aux données de la
base MySql.
Actualisation dynamique des listes déroulantes
Nous proposons de confirmer le dynamisme du système que nous avons bâti pour
relier ces listes déroulantes, gérées finalement par le
code client. C'est pourquoi il existe un second
fichier Sql dans le
sous dossier bdd.
- Dans l'interface d'administration PhpMyAdmin, sélectionner la base de données ids,
- Cliquer sur l'onglet Importer situé en haut de l'interface,
- Cliquer sur le bouton Parcourir,
- Puis, désigner le fichier Sql suite_id.sql situé dans le sous dossier bdd,
- En bas de l'interface, cliquer sur le bouton Exécuter pour procéder à l'importation,
Si vous affichez le contenu de la
table liste_id, elle compte désormais 1186 enregistrements.
- Revenir sur la page Web et la rafraîchir,
- Déployer la liste déroulante des départements,
Comme vous le constatez, deux nouveaux éléments sont venus se greffer à la suite : Le Rhône et la Savoie.
- Sélectionner par exemple le département de la Savoie,
- Puis, déployer l'affichage de la seconde liste déroulante des villes,
Comme vous le constatez, les villes de ce nouveau département, purgées de leurs doublons, sont chargées dynamiquement. Notre système de
listes déroulantes en cascade, gérées par le code client, est donc parfaitement fonctionnel. Si vous consultez le
code de la fonction du script externe, vous remarquez qu'il a effectivement évolué pour intégrer toutes les nouvelles valeurs issues de la
base de données MySql.