Étape 5: Développement du site
Introduction
Maintenant que le fonctionnement et les interactions entre les technologies HTML, PHP et SQL sont assimilés, nous pouvons commencer à développer plus en profondeur notre site Web dynamique de gestion des emplois du temps.
Objectifs de cette étape:
- avoir une page d’accueil en 2 parties: en haut les filtres de recherche (un formulaire HTML); en bas l’affichage de l’emploi du temps (résultat du
select
SQL) - quand on valide les critères de filtrage (soumission du formulaire), “seule la partie basse de la page est mise à jour” (enfin, on fait comme si…)
- générer des hyperliens sur les valeurs des cellules de l’emploi du temps
Intégration en une seule page
Je vais d’abord commencer par intégrer le formulaire HTML permettant de sélectionner un enseignant (et plus tard les autres critères de filtrage) à la page affichant le planning.
Il suffit pour cela de “fusionner” les 2 scripts PHP vus aux étapes précédentes: celui qui permettait de créer le formulaire en remplissant le select
avec les informations de la table prof
, et celui affichant le planning d’un enseignant donné à partir de la table planning
.
Vous pouvez tester vous-mêmes en cliquant sur ce lien.
Fichier PHP complet pour cette 1ère version (fichier <code>index05.php</code>)
<html>
<head>
<meta charset="utf-8"/>
<title>Gestion des emplois du temps</title>
</head>
<body>
<?php
// Ouverture du connecteur à la BdD une fois pour toute au début du script
$dbh = new PDO('sqlite:planning.db') or die("impossible d'ouvrir la base sqlite");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
?>
<h1>Gestion des emplois du temps</h1>
<form action="index05.php" method="GET">
Nom du prof
<select name="prof">
<?php
$sql = "select * from prof;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numprof'].'">'.$row['nomprof'].'</option>';
}
?>
</select>
<br>
<input type="submit" name="go" value="Rafraîchir">
</form>
<hr>
<?php
$prof = $_GET['prof'];
// Dans la requête SQL, on met un '?' à chaque endroit où l'on voudra insérer un paramètre
$sql = "select * from planning where (numprof=?) order by debut;";
// Préparation du statement avec la requête SQL
$stmt = $dbh->prepare($sql);
// Exécution du statement avec les paramètres indiqués dans le tableau
$stmt->execute([$prof]);
// Récupération du résultat de la requête
$res = $stmt->fetchAll();
echo '<table border="1">';
echo '<tr><th>num</th><th>début</th><th>fin</th><th>cours</th><th>salle</th><th>prof</th></tr>';
// Parcours du résultat
foreach ($res as $row) {
echo '<tr>';
echo '<td>'.$row['numcreneau'].'</td>';
echo '<td>'.$row['debut'].'</td>';
echo '<td>'.$row['fin'].'</td>';
echo '<td>'.$row['numcours'].'</td>';
echo '<td>'.$row['numsalle'].'</td>';
echo '<td>'.$row['numprof'].'</td>';
echo '</tr>';
}
echo '</table>';
?>
<hr>
Copyright © 2022 Manuel Munier
<br>
<a href="https://munier.perso.univ-pau.fr/">https://munier.perso.univ-pau.fr/</a>
</body>
</html>
Cette 1ère version de notre page Web fonctionne… mais d’un point de vue ergonomique elle souffre de 2 lacunes plutôt gênantes pour l’utilisateur:
- quand aucun enseignant n’est sélectionné, elle n’affiche rien dans le tableau; ce comportement est normal au regard de la requête SQL qui est exécuté, vu que la variable
$prof
est vide; leselect
retourne un résultat vide (aucun tuple ne matche la clausewhere
); dans ce cas, il serait plus judicieux d’afficher par défaut tous les créneaux du planning (aucun filtre donc) - une fois que l’on a choisi un enseignant et que l’on soumet le formulaire (le script s’appelle lui-même), le tableau est correctement rempli; MAIS le formulaire est réinitialisé aux valeurs par défaut; il serait plus ergonomique pour l’utilisateur de lui pré-remplir le formulaire avec les choix qu’il a déjà effectués
PHP: tester si une variable existe
La résolution des 2 problèmes mentionnés repose sur la même technique: il nous faut savoir si la variable $prof
de notre script PHP a bien été initialisée avec le contenu d’un paramètre CGI nommé prof
.
- si la variable
$prof
n’existe pas, on n’ajoute pas la clausewhere
dans notreselect
- si la variable
$prof
existe (avec l’id d’un enseignant), alors l’élément<option>
correspondant à cet id aura l’optionselected
quand le script générera la formulaire
Ceci peut se faire très simplement en PHP avec la fonction isset()
. Voici un exemple de code:
$prof = $_GET['prof'];
if (isset($prof)) {
echo 'idprof = '.$prof;
} else {
echo 'idprof non défini';
}
Notons néanmoins que cette solution génère une erreur en PHP si le tableau $_GET
ne contient pas de clé 'prof'
. Cette erreur n’est pas bloquante en soi (c’est juste un warning), mais selon la configuration du serveur Web et du module PHP il arrive parfois que le serveur Web affiche ce warning dans le code HTML retourné au client. Voici donc une version plus propre du code:
if (array_key_exists('prof',$_GET)) {
$prof = $_GET['prof'];
}
if (isset($prof)) {
echo 'idprof = '.$prof;
} else {
echo 'idprof non défini';
}
Nous pouvons alors modifier notre code pour adapter le code HTML généré en fonction de la présence (ou non) du paramètre CGI prof
et de sa valeur. Le résultat est tout de suite plus confortable pour l’utilisateur !
Vous pouvez tester vous-mêmes en cliquant sur ce lien.
Fichier PHP complet pour cette 2nde version (fichier <code>index06.php</code>)
<html>
<head>
<meta charset="utf-8"/>
<title>Gestion des emplois du temps</title>
</head>
<body>
<?php
// Ouverture du connecteur à la BdD une fois pour toute au début du script
$dbh = new PDO('sqlite:planning.db') or die("impossible d'ouvrir la base sqlite");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Récupération des paramètres CGI
if (array_key_exists('prof',$_GET)) {
$prof = $_GET['prof'];
}
?>
<h1>Gestion des emplois du temps</h1>
<form action="index06.php" method="GET">
Nom du prof
<select name="prof">
<option value="none" selected disabled hidden>Enseignant</option>
<?php
$sql = "select * from prof;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numprof'].'"';
// S'il s'agit de l'enseignant dont l'id est dans le paramètre CGI prof, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($prof)) {
if ($prof == $row['numprof']) {
echo ' selected';
}
}
echo '>'.$row['nomprof'].'</option>';
}
?>
</select>
<br>
<input type="submit" name="go" value="Rafraîchir">
</form>
<hr>
<?php
// Dans la requête SQL, on met un '?' à chaque endroit où l'on voudra insérer un paramètre
$sql = "select * from planning";
// Si la variable $prof existe, alors on prévoit une clause "where" dans la requête SQL
if (isset($prof)) {
$sql .= " where (numprof=?)";
}
$sql .= " order by debut;";
// Préparation du statement avec la requête SQL
$stmt = $dbh->prepare($sql);
// Exécution du statement avec les paramètres indiqués dans le tableau
$params = array();
if (isset($prof)) {
array_push($params, $prof);
}
$stmt->execute($params);
// Récupération du résultat de la requête
$res = $stmt->fetchAll();
echo '<table border="1">';
echo '<tr><th>num</th><th>début</th><th>fin</th><th>cours</th><th>salle</th><th>prof</th></tr>';
// Parcours du résultat
foreach ($res as $row) {
echo '<tr>';
echo '<td>'.$row['numcreneau'].'</td>';
echo '<td>'.$row['debut'].'</td>';
echo '<td>'.$row['fin'].'</td>';
echo '<td>'.$row['numcours'].'</td>';
echo '<td>'.$row['numsalle'].'</td>';
echo '<td>'.$row['numprof'].'</td>';
echo '</tr>';
}
echo '</table>';
?>
<hr>
Copyright © 2022 Manuel Munier
<br>
<a href="https://munier.perso.univ-pau.fr/">https://munier.perso.univ-pau.fr/</a>
</body>
</html>
Finalisation du formulaire
Nous pouvons maintenant procéder de la même façon pour ajouter les autres widgets du formulaire et prendre en compte leurs valeurs dans les requêtes SQLexécutées.
Vous pouvez tester vous-mêmes en cliquant sur ce lien.
Notons que dans la base de données, dans la table
planning
nous avons utilisé des attributs de typeDATE
qui, en SQLite, représente à la fois la date et l’heure (ex:2022-04-04 08:00:00
).Dans le formulaire HTML nous avons cependant 2 champs distincts: 1 de type
date
et 1 de typetime
.→ Traitement nécessaire en PHP pour construire correctement la requête SQL.
Fichier PHP complet pour cette version avec tous les champs du formulaire (fichier <code>index07.php</code>)
<html>
<head>
<meta charset="utf-8"/>
<title>Gestion des emplois du temps</title>
</head>
<body>
<?php
// Ouverture du connecteur à la BdD une fois pour toute au début du script
$dbh = new PDO('sqlite:planning.db') or die("impossible d'ouvrir la base sqlite");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Récupération des paramètres CGI éventuels
// NB: si la valeur est 'none' alors le paramètre est ignoré
if (array_key_exists('cours',$_GET)) {
if ($_GET['cours'] != 'none') {
$cours = $_GET['cours'];
}
}
if (array_key_exists('salle',$_GET)) {
if ($_GET['salle'] != 'none') {
$salle = $_GET['salle'];
}
}
if (array_key_exists('prof',$_GET)) {
if ($_GET['prof'] != 'none') {
$prof = $_GET['prof'];
}
}
if (array_key_exists('datemin',$_GET)) {
if ($_GET['datemin'] != '') {
$datemin = $_GET['datemin'];
}
}
if (array_key_exists('datemax',$_GET)) {
if ($_GET['datemax'] != '') {
$datemax = $_GET['datemax'];
}
}
if (array_key_exists('heuremin',$_GET)) {
if ($_GET['heuremin'] != '') {
$heuremin = $_GET['heuremin'];
}
}
if (array_key_exists('heuremax',$_GET)) {
if ($_GET['heuremax'] != '') {
$heuremax = $_GET['heuremax'];
}
}
?>
<h1>Gestion des emplois du temps</h1>
<form action="index07.php" method="GET">
<!-- Choix date et heure minimum -->
Date min
<input type="date" name="datemin" <?php if (isset($datemin)) { echo 'value="'.$datemin.'"'; }?> >
Heure min
<input type="time" name="heuremin" <?php if (isset($heuremin)) { echo 'value="'.$heuremin.'"'; }?> >
<br>
<!-- Choix date et heure maximum -->
Date max
<input type="date" name="datemax" <?php if (isset($datemax)) { echo 'value="'.$datemax.'"'; }?> >
Heure max
<input type="time" name="heuremax" <?php if (isset($heuremax)) { echo 'value="'.$heuremax.'"'; }?> >
<br>
<!-- Choix du cours -->
Nom du cours
<select name="cours">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from cours;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numcours'].'"';
// S'il s'agit du cours dont l'id est dans le paramètre CGI cours, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($cours)) {
if ($cours == $row['numcours']) {
echo ' selected';
}
}
echo '>'.$row['idcours'].' ('.$row['libcours'].')</option>';
}
?>
</select>
<br>
<!-- Choix de la salle -->
Nom de la salle
<select name="salle">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from salle;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numsalle'].'"';
// S'il s'agit de la salle dont l'id est dans le paramètre CGI salle, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($salle)) {
if ($salle == $row['numsalle']) {
echo ' selected';
}
}
echo '>'.$row['descsalle'].'</option>';
}
?>
</select>
<br>
<!-- Choix du prof -->
Nom du prof
<select name="prof">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from prof;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numprof'].'"';
// S'il s'agit de l'enseignant dont l'id est dans le paramètre CGI prof, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($prof)) {
if ($prof == $row['numprof']) {
echo ' selected';
}
}
echo '>'.$row['nomprof'].'</option>';
}
?>
</select>
<br>
<!-- Bouton de soumission du formulaire -->
<input type="submit" name="go" value="Rafraîchir">
</form>
<hr>
<?php
// Dans la requête SQL, on mettra un '?' à chaque endroit où l'on voudra insérer un paramètre
$sql = "select * from planning where ( (1=1)";
$params = array();
// Si un critère de filtre (ex: variable $prof) existe, alors on ajoute une conjonction à la clause "where"
// dans la requête SQL et on ajoute la valeur à la liste des paramètres pour l'exécution du statement
if (isset($cours)) {
$sql .= " and (numcours=?)";
array_push($params, $cours);
}
if (isset($salle)) {
$sql .= " and (numsalle=?)";
array_push($params, $salle);
}
if (isset($prof)) {
$sql .= " and (numprof=?)";
array_push($params, $prof);
}
if (isset($datemin) && isset($heuremin)) {
$dhmin = $datemin.' '.$heuremin;
$sql .= " and (?<=datetime(debut))";
array_push($params, $dhmin);
} else {
if (isset($datemin)) {
$sql .= " and (?<=date(debut))";
array_push($params, $datemin);
}
if (isset($heuremin)) {
$sql .= " and (?<=time(debut))";
array_push($params, $heuremin);
}
}
if (isset($datemax) && isset($heuremax)) {
$dhmax = $datemax.' '.$heuremax;
$sql .= " and (datetime(fin)<=?)";
array_push($params, $dhmax);
} else {
if (isset($datemax)) {
$sql .= " and (date(fin)<=?)";
array_push($params, $datemax);
}
if (isset($heuremax)) {
$sql .= " and (time(fin)<=?)";
array_push($params, $heuremax);
}
}
//echo '$sql = "'.$sql.'"<br>';
// On termine proprement notre requête SQL
$sql .= ") order by debut;";
// Préparation du statement avec la requête SQL
$stmt = $dbh->prepare($sql);
// Exécution du statement avec les paramètres indiqués dans le tableau
$stmt->execute($params);
// Récupération du résultat de la requête
$res = $stmt->fetchAll();
echo '<table border="1">';
echo '<tr><th>num</th><th>début</th><th>fin</th><th>cours</th><th>salle</th><th>prof</th></tr>';
// Parcours du résultat
foreach ($res as $row) {
echo '<tr>';
echo '<td>'.$row['numcreneau'].'</td>';
echo '<td>'.$row['debut'].'</td>';
echo '<td>'.$row['fin'].'</td>';
echo '<td>'.$row['numcours'].'</td>';
echo '<td>'.$row['numsalle'].'</td>';
echo '<td>'.$row['numprof'].'</td>';
echo '</tr>';
}
echo '</table>';
?>
<hr>
Copyright © 2022 Manuel Munier
<br>
<a href="https://munier.perso.univ-pau.fr/">https://munier.perso.univ-pau.fr/</a>
</body>
</html>
Au passage nous pouvons également voir comment sont encodés les paramètres CGI dans l’URL. En effet, bien que les valeurs transmises ne soient que des chaînes de caractères, certains caractères ne sont pas autorisés dans les URL (ex: espaces, :
, caratères accentués). D’où la nécessité de les encoder (plus d’infos ici).
https://munier.perso.univ-pau.fr/temp/R209/tuto_php/step05/index07.php?datemin=2022-04-05&heuremin=11%3A00&datemax=2022-04-06&heuremax=17%3A00&cours=3&salle=none&prof=none&go=Rafra%C3%AEchir
name | value | string |
---|---|---|
datemin | 2022-04-05 |
2022-04-05 |
heuremin | 11%3A00 |
11:30 |
datemax | 2022-04-06 |
2022-04-06 |
heuremax | 17%3A00 |
17:00 |
cours | 3 |
3 |
salle | none |
none |
prof | none |
none |
go | Rafra%C3%AEchir |
Rafraîchir |
Gardons en mémoire cette remarque sur l’encodage des paramètres CGI dans les URLs. En effet, si dans le cas présent c’est le formulaire HTML qui encode automatiquement les valeurs, quand nous générerons manuellement les URLs dans nos scripts PHP, ce sera à nous d’encoder les valeurs à transmettre via les CGI.
Amélioration du tableau
Pour l’instant, le tableau affiché dans la 2ème partie de la page avec les créneaux du planning est pour le moins “brut de décoffrage”. Les valeurs des tuples sélectionnés dans la table planning
par notre requête SQL sont affichés telles quelles. L’objectif était de vérifier la bonne exécution de notre script PHP.
Sans pour autant s’occuper de la mise en forme, nous pouvons néanmoins améliorer le contenu affiché par ce tableau:
- il n’est pas utile d’afficher l’attribut
numcreneau
- pour le cours, la salle et le prof il serait plus confortable d’afficher le nom ou le libellé plutôt que le numéro → adaptation de la requête SQL
- le nom des enseignants sera cliquable et affichera dans un onglet séparé du navigateur la liste des journées où cet enseignant a des cours → génération d’un hyperlien vers un autre script PHP avec encodage de paramètres CGI
Modification de la requête SQL
La requête SQL actuellement exécutée pour interroger la table planning
est à peu près celle-ci:
select * from planning where ( (1=1) [...] ) order by debut;
Exécutée sur la base de données utilisée dans ce tutoriel, cette requête donne ceci:
sqlite> select * from planning order by debut;
numcreneau debut fin numcours numsalle numprof
---------- ------------------- ------------------- ---------- ---------- ----------
1 2022-04-04 08:00:00 2022-04-04 09:30:00 1 1 1
2 2022-04-04 09:30:00 2022-04-04 11:00:00 2 2 2
3 2022-04-04 11:00:00 2022-04-04 12:30:00 3 3 3
4 2022-04-04 13:30:00 2022-04-04 15:00:00 2 4 2
5 2022-04-04 15:00:00 2022-04-04 18:00:00 1 5 1
6 2022-04-04 18:00:00 2022-04-04 19:30:00 501 2 4
7 2022-04-05 08:00:00 2022-04-05 11:00:00 5 6 5
8 2022-04-05 11:00:00 2022-04-05 12:30:00 2 7 2
9 2022-04-05 13:30:00 2022-04-05 15:00:00 3 8 0
10 2022-04-05 15:00:00 2022-04-05 18:00:00 5 9 6
11 2022-04-06 08:00:00 2022-04-06 09:30:00 3 10 0
12 2022-04-06 09:00:00 2022-04-06 11:00:00 3 11 0
13 2022-04-06 11:00:00 2022-04-06 12:30:00 6 12 5
14 2022-04-06 13:30:00 2022-04-06 15:00:00 7 3 7
15 2022-04-06 15:00:00 2022-04-06 18:00:00 2 13 2
16 2022-04-07 08:00:00 2022-04-07 09:30:00 6 2 5
17 2022-04-07 09:30:00 2022-04-07 11:00:00 5 12 6
18 2022-04-07 11:00:00 2022-04-07 12:30:00 4 12 5
Pour associer l’attribut numcours
de la table planning
aux attributs idcours
et libcours
correspondants dans la table cours
nous allons utiliser une clause inner join
dans notre requête SQL (cf. document SQLite Inner Join). Dans notre cas, nous ajoutons la clause
inner join cours on cours.numcours = planning.numcours
L’exécution de notre requête SQL nous retourne maintenant le résultat suivant où les colonnes idcours
et libcours
ont bien été “ajoutées”:
sqlite> select * from planning inner join cours on cours.numcours = planning.numcours order by debut;
numcreneau debut fin numcours numsalle numprof numcours idcours libcours
---------- ------------------- ------------------- ---------- ---------- ---------- ---------- ---------- -------------------------
1 2022-04-04 08:00:00 2022-04-04 09:30:00 1 1 1 1 R201 Technologie de l'Internet
2 2022-04-04 09:30:00 2022-04-04 11:00:00 2 2 2 2 R204 Initiation à la téléphoni
3 2022-04-04 11:00:00 2022-04-04 12:30:00 3 3 3 3 SAE 21 SAE 21
4 2022-04-04 13:30:00 2022-04-04 15:00:00 2 4 2 2 R204 Initiation à la téléphoni
5 2022-04-04 15:00:00 2022-04-04 18:00:00 1 5 1 1 R201 Technologie de l'Internet
6 2022-04-04 18:00:00 2022-04-04 19:30:00 501 2 4 501 réunion Présentation parcours BUT
7 2022-04-05 08:00:00 2022-04-05 11:00:00 5 6 5 5 R209 Initiation au développeme
8 2022-04-05 11:00:00 2022-04-05 12:30:00 2 7 2 2 R204 Initiation à la téléphoni
9 2022-04-05 13:30:00 2022-04-05 15:00:00 3 8 0 3 SAE 21 SAE 21
10 2022-04-05 15:00:00 2022-04-05 18:00:00 5 9 6 5 R209 Initiation au développeme
11 2022-04-06 08:00:00 2022-04-06 09:30:00 3 10 0 3 SAE 21 SAE 21
12 2022-04-06 09:00:00 2022-04-06 11:00:00 3 11 0 3 SAE 21 SAE 21
13 2022-04-06 11:00:00 2022-04-06 12:30:00 6 12 5 6 R214 Analyse mathématiques des
14 2022-04-06 13:30:00 2022-04-06 15:00:00 7 3 7 7 R211 Expression, Culture, Comm
15 2022-04-06 15:00:00 2022-04-06 18:00:00 2 13 2 2 R204 Initiation à la téléphoni
16 2022-04-07 08:00:00 2022-04-07 09:30:00 6 2 5 6 R214 Analyse mathématiques des
17 2022-04-07 09:30:00 2022-04-07 11:00:00 5 12 6 5 R209 Initiation au développeme
18 2022-04-07 11:00:00 2022-04-07 12:30:00 4 12 5 4 R213 Mathématiques des système
Il suffit de faire pareil pour intégrer au résultat les attributs des tables salle
et prof
:
inner join salle on salle.numsalle = planning.numsalle
inner join prof on prof.numprof = planning.numprof
D’où le résultat complet:
sqlite> select * from planning
...> inner join cours on cours.numcours = planning.numcours
...> inner join salle on salle.numsalle = planning.numsalle
...> inner join prof on prof.numprof = planning.numprof
...> order by debut;
numcreneau debut fin numcours numsalle numprof numcours idcours libcours numsalle descsalle numprof nomprof
---------- ------------------- ------------------- ---------- ---------- ---------- ---------- ---------- ------------------------- ---------- ---------- ---------- ----------
1 2022-04-04 08:00:00 2022-04-04 09:30:00 1 1 1 1 R201 Technologie de l'Internet 1 Amphi BIO 1 JJB
2 2022-04-04 09:30:00 2022-04-04 11:00:00 2 2 2 2 R204 Initiation à la téléphoni 2 Salle de c 2 AA
3 2022-04-04 11:00:00 2022-04-04 12:30:00 3 3 3 3 SAE 21 SAE 21 3 Téléformat 3 PA
4 2022-04-04 13:30:00 2022-04-04 15:00:00 2 4 2 2 R204 Initiation à la téléphoni 4 TD6 2 AA
5 2022-04-04 15:00:00 2022-04-04 18:00:00 1 5 1 1 R201 Technologie de l'Internet 5 Réseaux 1 JJB
6 2022-04-04 18:00:00 2022-04-04 19:30:00 501 2 4 501 réunion Présentation parcours BUT 2 Salle de c 4 SS
7 2022-04-05 08:00:00 2022-04-05 11:00:00 5 6 5 5 R209 Initiation au développeme 6 Salle PC 5 SM
8 2022-04-05 11:00:00 2022-04-05 12:30:00 2 7 2 2 R204 Initiation à la téléphoni 7 TD4 2 AA
9 2022-04-05 13:30:00 2022-04-05 15:00:00 3 8 0 3 SAE 21 SAE 21 8 Très Haut 0 accès libr
10 2022-04-05 15:00:00 2022-04-05 18:00:00 5 9 6 5 R209 Initiation au développeme 9 Station 6 MM
11 2022-04-06 08:00:00 2022-04-06 09:30:00 3 10 0 3 SAE 21 SAE 21 10 Projets 0 accès libr
12 2022-04-06 09:00:00 2022-04-06 11:00:00 3 11 0 3 SAE 21 SAE 21 11 Réseaux op 0 accès libr
13 2022-04-06 11:00:00 2022-04-06 12:30:00 6 12 5 6 R214 Analyse mathématiques des 12 TD Info 5 SM
14 2022-04-06 13:30:00 2022-04-06 15:00:00 7 3 7 7 R211 Expression, Culture, Comm 3 Téléformat 7 FK
15 2022-04-06 15:00:00 2022-04-06 18:00:00 2 13 2 2 R204 Initiation à la téléphoni 13 Téléphonie 2 AA
16 2022-04-07 08:00:00 2022-04-07 09:30:00 6 2 5 6 R214 Analyse mathématiques des 2 Salle de c 5 SM
17 2022-04-07 09:30:00 2022-04-07 11:00:00 5 12 6 5 R209 Initiation au développeme 12 TD Info 6 MM
18 2022-04-07 11:00:00 2022-04-07 12:30:00 4 12 5 4 R213 Mathématiques des système 12 TD Info 5 SM
Dans notre script PHP il ne reste plus qu’à utiliser les valeurs de ces colonnes supplémentaires dans la boucle foreach
qui traite le résultat de la requête SQL.
Et voilà le résultat que vous pouvez tester vous-mêmes en cliquant sur ce lien.
Code source complet de ce fichier PHP (fichier <code>index08.php</code>)
<html>
<head>
<meta charset="utf-8"/>
<title>Gestion des emplois du temps</title>
</head>
<body>
<?php
// Ouverture du connecteur à la BdD une fois pour toute au début du script
$dbh = new PDO('sqlite:planning.db') or die("impossible d'ouvrir la base sqlite");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Récupération des paramètres CGI éventuels
// NB: si la valeur est 'none' alors le paramètre est ignoré
if (array_key_exists('cours',$_GET)) {
if ($_GET['cours'] != 'none') {
$cours = $_GET['cours'];
}
}
if (array_key_exists('salle',$_GET)) {
if ($_GET['salle'] != 'none') {
$salle = $_GET['salle'];
}
}
if (array_key_exists('prof',$_GET)) {
if ($_GET['prof'] != 'none') {
$prof = $_GET['prof'];
}
}
if (array_key_exists('datemin',$_GET)) {
if ($_GET['datemin'] != '') {
$datemin = $_GET['datemin'];
}
}
if (array_key_exists('datemax',$_GET)) {
if ($_GET['datemax'] != '') {
$datemax = $_GET['datemax'];
}
}
if (array_key_exists('heuremin',$_GET)) {
if ($_GET['heuremin'] != '') {
$heuremin = $_GET['heuremin'];
}
}
if (array_key_exists('heuremax',$_GET)) {
if ($_GET['heuremax'] != '') {
$heuremax = $_GET['heuremax'];
}
}
?>
<h1>Gestion des emplois du temps</h1>
<form action="index08.php" method="GET">
<!-- Choix date et heure minimum -->
Date min
<input type="date" name="datemin" <?php if (isset($datemin)) { echo 'value="'.$datemin.'"'; }?> >
Heure min
<input type="time" name="heuremin" <?php if (isset($heuremin)) { echo 'value="'.$heuremin.'"'; }?> >
<br>
<!-- Choix date et heure maximum -->
Date max
<input type="date" name="datemax" <?php if (isset($datemax)) { echo 'value="'.$datemax.'"'; }?> >
Heure max
<input type="time" name="heuremax" <?php if (isset($heuremax)) { echo 'value="'.$heuremax.'"'; }?> >
<br>
<!-- Choix du cours -->
Nom du cours
<select name="cours">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from cours;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numcours'].'"';
// S'il s'agit du cours dont l'id est dans le paramètre CGI cours, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($cours)) {
if ($cours == $row['numcours']) {
echo ' selected';
}
}
echo '>'.$row['idcours'].' ('.$row['libcours'].')</option>';
}
?>
</select>
<br>
<!-- Choix de la salle -->
Nom de la salle
<select name="salle">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from salle;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numsalle'].'"';
// S'il s'agit de la salle dont l'id est dans le paramètre CGI salle, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($salle)) {
if ($salle == $row['numsalle']) {
echo ' selected';
}
}
echo '>'.$row['descsalle'].'</option>';
}
?>
</select>
<br>
<!-- Choix du prof -->
Nom du prof
<select name="prof">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from prof;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numprof'].'"';
// S'il s'agit de l'enseignant dont l'id est dans le paramètre CGI prof, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($prof)) {
if ($prof == $row['numprof']) {
echo ' selected';
}
}
echo '>'.$row['nomprof'].'</option>';
}
?>
</select>
<br>
<!-- Bouton de soumission du formulaire -->
<input type="submit" name="go" value="Rafraîchir">
</form>
<hr>
<?php
// Dans la requête SQL, on mettra un '?' à chaque endroit où l'on voudra insérer un paramètre
$sql = "select * from planning ".
"inner join cours on cours.numcours = planning.numcours ".
"inner join salle on salle.numsalle = planning.numsalle ".
"inner join prof on prof.numprof = planning.numprof ".
"where ( (1=1)";
$params = array();
// Si un critère de filtre (ex: variable $prof) existe, alors on ajoute une conjonction à la clause "where"
// dans la requête SQL et on ajoute la valeur à la liste des paramètres pour l'exécution du statement
if (isset($cours)) {
$sql .= " and (planning.numcours=?)";
array_push($params, $cours);
}
if (isset($salle)) {
$sql .= " and (planning.numsalle=?)";
array_push($params, $salle);
}
if (isset($prof)) {
$sql .= " and (planning.numprof=?)";
array_push($params, $prof);
}
if (isset($datemin) && isset($heuremin)) {
$dhmin = $datemin.' '.$heuremin;
$sql .= " and (?<=datetime(debut))";
array_push($params, $dhmin);
} else {
if (isset($datemin)) {
$sql .= " and (?<=date(debut))";
array_push($params, $datemin);
}
if (isset($heuremin)) {
$sql .= " and (?<=time(debut))";
array_push($params, $heuremin);
}
}
if (isset($datemax) && isset($heuremax)) {
$dhmax = $datemax.' '.$heuremax;
$sql .= " and (datetime(fin)<=?)";
array_push($params, $dhmax);
} else {
if (isset($datemax)) {
$sql .= " and (date(fin)<=?)";
array_push($params, $datemax);
}
if (isset($heuremax)) {
$sql .= " and (time(fin)<=?)";
array_push($params, $heuremax);
}
}
//echo '$sql = "'.$sql.'"<br>';
// On termine proprement notre requête SQL
$sql .= ") order by debut;";
// Préparation du statement avec la requête SQL
$stmt = $dbh->prepare($sql);
// Exécution du statement avec les paramètres indiqués dans le tableau
$stmt->execute($params);
// Récupération du résultat de la requête
$res = $stmt->fetchAll();
echo '<table border="1">';
echo '<tr><th>num</th><th>début</th><th>fin</th><th>cours</th><th>salle</th><th>prof</th></tr>';
// Parcours du résultat
foreach ($res as $row) {
echo '<tr>';
echo '<td>'.$row['numcreneau'].'</td>';
echo '<td>'.$row['debut'].'</td>';
echo '<td>'.$row['fin'].'</td>';
echo '<td>'.'<a href="" title="'.$row['libcours'].'">'.$row['idcours'].'</a>'.'</td>';
echo '<td>'.$row['descsalle'].'</td>';
echo '<td>'.$row['nomprof'].'</td>';
echo '</tr>';
}
echo '</table>';
?>
<hr>
Copyright © 2022 Manuel Munier
<br>
<a href="https://munier.perso.univ-pau.fr/">https://munier.perso.univ-pau.fr/</a>
</body>
</html>
À noter que les valeurs de la colonne
cours
apparaissent comme des liens. Dans le code PHP nous avons effectivement ajouté un lien “vide” (donc reste sur la même page) dans le seul but de pouvoir insérer une infobulle sur le code du module pour afficher le libellé complet.Nous avons pour cela remplacé la ligne
echo '<td>'.$row['idcours'].'</td>';
par la ligne
echo '<td>'.'<a href="" title="'.$row['libcours'].'">'.$row['idcours'].'</a>'.'</td>';
Ajout d’hyperliens
De la même manière que nous avons ajouté une balise <a href[...]>
sur le code d’un module pour afficher (via une infobulle ou tooltip) le libellé complet de ce module, nous allons maintenant ajouter un hyperlien sur le nom d’un enseignant pour renvoyer cette fois sur un script PHP qui va générer (dynamiquement ☺) une page HTML contenant diverses informations sur cet enseignant, et notamment la liste des journées où il a au moins un cours.
1. Script PHP
Commençons par écrire le script PHP qui réalise le traitement. Ce script prendra un paramètre CGI nommé prof
dans lequel sera indiqué l’identifiant de l’enseignant. La requête SQL est la suivante:
select distinct(date(debut)) as date from planning where (numprof=?) order by debut;
Nous pouvons déjà la tester dans l’interpréteur SQLite:
sqlite> select distinct(date(debut)) as date from planning where (numprof=6) order by debut;
date
----------
2022-04-05
2022-04-07
Le script PHP s’écrit de la même façon que les scripts précédents. Lui aussi n’introduira pas la clause where
dans le select
si la paramètre prof
n’existe pas. Dans ce cas, la requête retournera tous les jours où il y a au moins un cours, peu importe l’enseignant.
Nous pouvons tester l’exécution de ce script manuellement en saisissant nous même l’URL dans le navigateur Web (ex: lien ici):
https://munier.perso.univ-pau.fr/temp/R209/tuto_php/step05/infos_prof01.php?prof=6
Code source complet de ce script PHP (fichier <code>infos_prof01.php</code>)
<html>
<head>
<meta charset="utf-8"/>
<title>Infos prof</title>
</head>
<body>
<?php
// Ouverture du connecteur à la BdD une fois pour toute au début du script
$dbh = new PDO('sqlite:planning.db') or die("impossible d'ouvrir la base sqlite");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Récupération des paramètres CGI éventuels
// NB: si la valeur est 'none' alors le paramètre est ignoré
if (array_key_exists('prof',$_GET)) {
if ($_GET['prof'] != 'none') {
$prof = $_GET['prof'];
}
}
?>
<h1>Enseignant #<?php if (isset($prof)) { echo $prof; } else { echo '?'; } ?></h1>
<?php
// Dans la requête SQL, on mettra un '?' à chaque endroit où l'on voudra insérer un paramètre
$sql = "select distinct(date(debut)) as date from planning where ( (1=1)";
$params = array();
// Si un critère de filtre (ex: variable $prof) existe, alors on ajoute une conjonction à la clause "where"
// dans la requête SQL et on ajoute la valeur à la liste des paramètres pour l'exécution du statement
if (isset($prof)) {
$sql .= " and (numprof=?)";
array_push($params, $prof);
}
//echo '$sql = "'.$sql.'"<br>';
// On termine proprement notre requête SQL
$sql .= ") order by debut;";
// Préparation du statement avec la requête SQL
$stmt = $dbh->prepare($sql);
// Exécution du statement avec les paramètres indiqués dans le tableau
$stmt->execute($params);
// Récupération du résultat de la requête
$res = $stmt->fetchAll();
echo '<ul>';
// Parcours du résultat
foreach ($res as $row) {
$d = $row['date'];
echo '<li>'.$d.' → '.date_format(date_create($d),"l d F Y").'</li>';
}
echo '</ul>';
?>
<hr>
Copyright © 2022 Manuel Munier
<br>
<a href="https://munier.perso.univ-pau.fr/">https://munier.perso.univ-pau.fr/</a>
</body>
</html>
NB: J’en ai profité pour utiliser la fonction PHP
date_format()
pour remettre en forme la date stockée dans la base de données.
2. Génération des hyperliens
Dans le script principal (celui contenant le formulaire avec les critères de recherche et le tableau des créneaux sélectionnés), il nous suffit de remplacer la ligne suivante:
echo '<td>'.$row['nomprof'].'</td>';
par celle-ci pour générer l’hyperlien vers notre script infos_prof01.php
avec l’id de l’enseignant encodé comme paramètre CGI dans l’URL:
echo '<td>'.'<a href="infos_prof01.php?prof='.urlencode($row['numprof']).'" title="infos prof #'.$row['numprof'].'">'.$row['nomprof'].'</a>'.'</td>';
Notez bien l’utilisation de la fonction PHP urlencode()
pour encoder la valeur du paramètre CGI (une chaîne de caractères), afin d’être certain que tous les caractères soietn acceptables dans l’URL.
Il est vrai que donc le cas présent il ne s’agit que d’un numérique (ex:
6
), mais autant prendre tout de suite les bonnes habitudes ☺
Voici enfin le résultat (presque) final que vous pouvez tester vous-mêmes en cliquant sur ce lien.
Code source complet de ce script PHP avec la génération des liens (fichier <code>index09.php</code>)
<html>
<head>
<meta charset="utf-8"/>
<title>Gestion des emplois du temps</title>
</head>
<body>
<?php
// Ouverture du connecteur à la BdD une fois pour toute au début du script
$dbh = new PDO('sqlite:planning.db') or die("impossible d'ouvrir la base sqlite");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Récupération des paramètres CGI éventuels
// NB: si la valeur est 'none' alors le paramètre est ignoré
if (array_key_exists('cours',$_GET)) {
if ($_GET['cours'] != 'none') {
$cours = $_GET['cours'];
}
}
if (array_key_exists('salle',$_GET)) {
if ($_GET['salle'] != 'none') {
$salle = $_GET['salle'];
}
}
if (array_key_exists('prof',$_GET)) {
if ($_GET['prof'] != 'none') {
$prof = $_GET['prof'];
}
}
if (array_key_exists('datemin',$_GET)) {
if ($_GET['datemin'] != '') {
$datemin = $_GET['datemin'];
}
}
if (array_key_exists('datemax',$_GET)) {
if ($_GET['datemax'] != '') {
$datemax = $_GET['datemax'];
}
}
if (array_key_exists('heuremin',$_GET)) {
if ($_GET['heuremin'] != '') {
$heuremin = $_GET['heuremin'];
}
}
if (array_key_exists('heuremax',$_GET)) {
if ($_GET['heuremax'] != '') {
$heuremax = $_GET['heuremax'];
}
}
?>
<h1>Gestion des emplois du temps</h1>
<form action="index09.php" method="GET">
<!-- Choix date et heure minimum -->
Date min
<input type="date" name="datemin" <?php if (isset($datemin)) { echo 'value="'.$datemin.'"'; }?> >
Heure min
<input type="time" name="heuremin" <?php if (isset($heuremin)) { echo 'value="'.$heuremin.'"'; }?> >
<br>
<!-- Choix date et heure maximum -->
Date max
<input type="date" name="datemax" <?php if (isset($datemax)) { echo 'value="'.$datemax.'"'; }?> >
Heure max
<input type="time" name="heuremax" <?php if (isset($heuremax)) { echo 'value="'.$heuremax.'"'; }?> >
<br>
<!-- Choix du cours -->
Nom du cours
<select name="cours">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from cours;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numcours'].'"';
// S'il s'agit du cours dont l'id est dans le paramètre CGI cours, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($cours)) {
if ($cours == $row['numcours']) {
echo ' selected';
}
}
echo '>'.$row['idcours'].' ('.$row['libcours'].')</option>';
}
?>
</select>
<br>
<!-- Choix de la salle -->
Nom de la salle
<select name="salle">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from salle;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numsalle'].'"';
// S'il s'agit de la salle dont l'id est dans le paramètre CGI salle, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($salle)) {
if ($salle == $row['numsalle']) {
echo ' selected';
}
}
echo '>'.$row['descsalle'].'</option>';
}
?>
</select>
<br>
<!-- Choix du prof -->
Nom du prof
<select name="prof">
<option value="none" selected>〈aucun〉</option>
<?php
$sql = "select * from prof;";
foreach ($dbh->query($sql) as $row) {
echo '<option value="'.$row['numprof'].'"';
// S'il s'agit de l'enseignant dont l'id est dans le paramètre CGI prof, alors
// on ajoute l'option "selected" à cet élément de la liste
if (isset($prof)) {
if ($prof == $row['numprof']) {
echo ' selected';
}
}
echo '>'.$row['nomprof'].'</option>';
}
?>
</select>
<br>
<!-- Bouton de soumission du formulaire -->
<input type="submit" name="go" value="Rafraîchir">
</form>
<hr>
<?php
// Dans la requête SQL, on mettra un '?' à chaque endroit où l'on voudra insérer un paramètre
$sql = "select * from planning ".
"inner join cours on cours.numcours = planning.numcours ".
"inner join salle on salle.numsalle = planning.numsalle ".
"inner join prof on prof.numprof = planning.numprof ".
"where ( (1=1)";
$params = array();
// Si un critère de filtre (ex: variable $prof) existe, alors on ajoute une conjonction à la clause "where"
// dans la requête SQL et on ajoute la valeur à la liste des paramètres pour l'exécution du statement
if (isset($cours)) {
$sql .= " and (planning.numcours=?)";
array_push($params, $cours);
}
if (isset($salle)) {
$sql .= " and (planning.numsalle=?)";
array_push($params, $salle);
}
if (isset($prof)) {
$sql .= " and (planning.numprof=?)";
array_push($params, $prof);
}
if (isset($datemin) && isset($heuremin)) {
$dhmin = $datemin.' '.$heuremin;
$sql .= " and (?<=datetime(debut))";
array_push($params, $dhmin);
} else {
if (isset($datemin)) {
$sql .= " and (?<=date(debut))";
array_push($params, $datemin);
}
if (isset($heuremin)) {
$sql .= " and (?<=time(debut))";
array_push($params, $heuremin);
}
}
if (isset($datemax) && isset($heuremax)) {
$dhmax = $datemax.' '.$heuremax;
$sql .= " and (datetime(fin)<=?)";
array_push($params, $dhmax);
} else {
if (isset($datemax)) {
$sql .= " and (date(fin)<=?)";
array_push($params, $datemax);
}
if (isset($heuremax)) {
$sql .= " and (time(fin)<=?)";
array_push($params, $heuremax);
}
}
//echo '$sql = "'.$sql.'"<br>';
// On termine proprement notre requête SQL
$sql .= ") order by debut;";
// Préparation du statement avec la requête SQL
$stmt = $dbh->prepare($sql);
// Exécution du statement avec les paramètres indiqués dans le tableau
$stmt->execute($params);
// Récupération du résultat de la requête
$res = $stmt->fetchAll();
echo '<table border="1">';
echo '<tr><th>num</th><th>début</th><th>fin</th><th>cours</th><th>salle</th><th>prof</th></tr>';
// Parcours du résultat
foreach ($res as $row) {
echo '<tr>';
echo '<td>'.$row['numcreneau'].'</td>';
echo '<td>'.$row['debut'].'</td>';
echo '<td>'.$row['fin'].'</td>';
echo '<td>'.'<a href="" title="'.$row['libcours'].'">'.$row['idcours'].'</a>'.'</td>';
echo '<td>'.$row['descsalle'].'</td>';
echo '<td>'.'<a href="infos_prof01.php?prof='.urlencode($row['numprof']).'" title="infos prof #'.$row['numprof'].'">'.$row['nomprof'].'</a>'.'</td>';
echo '</tr>';
}
echo '</table>';
?>
<hr>
Copyright © 2022 Manuel Munier
<br>
<a href="https://munier.perso.univ-pau.fr/">https://munier.perso.univ-pau.fr/</a>
</body>
</html>
Conclusion
Nous voici arrivés à un point important de ce tutoriel. Vous savez maintenant:
- créer votre base de données SQLite (et n’oubliez pas de tester vos requêtes directement sous l’interpréteur)
- écrire des scripts PHP qui interrogent votre base de données et générent du code HTML renvoyé au client pour affichage dans son navigateur Web
- écrire des formulaires HTML (avec des listes peuplées dynamiquement) qui envoient leurs données sous forme de paramètres CGI (encodés dans l’URL) à un script PHP (et récupérer ces paramètres en PHP…)
- dans vos scripts PHP, générer vos propres URL vers d’autres scripts en encodant proprement les valeurs des paramètres CGI
Vous savez donc créer un site Web dynamique, c’est-à-dire un site avec des pages Web générées “à la volée” en fonction du contenu à l’instant t de votre base de données et liées les unes aux autres via des hyperliens !
And now ?
Dans les étapes suivantes nous allons aller un peu plus loin en:
- ajoutant un peu plus d’interactivité côté client → envoie de scripts JavaScript qui seront exécutés dans le navigateur Web (donc côté client)
- rendant nos pages visuellement plus agréables → utilisation de CSS & co.