Ce chapitre est consacré à la gestion d'une table d'une base de données. Il n'est pas destiné aux débutants. Toutefois, ils auraient tort de ne pas essayer de comprendre, car cela leur facilitera considérablement leur travail de présentation de données.
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET AUTOCOMMIT = 0; START TRANSACTION; SET time_zone = "+00:00"; DROP TABLE IF EXISTS voitures; CREATE TABLE voitures ( `id_voiture` smallint(5) UNSIGNED NOT NULL, `marque` varchar(15) NOT NULL, `modele` varchar(15) NOT NULL, `pays` varchar(15) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; INSERT INTO voitures (`id_voiture`, `marque`, `modele`, `pays`) VALUES (1, 'Porsche', '911', 'Allemagne'), (2, 'BMW', 'M5', 'Allemagne'), (3, 'Ferrari', 'Testarossa', 'Italie'), (4, 'Ford', 'Fiesta', 'USA'), (5, 'Lamborghini', 'Aventador', 'Italie'), (6, 'Fiat', '500', 'Italie'); ALTER TABLE voitures ADD PRIMARY KEY (`id_voiture`); ALTER TABLE voitures MODIFY `id_voiture` smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; COMMIT;
voitures doit être préfixé par la valeur attribuée à la variable $prefixT du
fichier maConnexion.php
.
Pour réinitialiser la table "voitures", cliquez ici (TODO : modifier ce lien)
PHP Data Objects
PDO_MYSQL est un pilote qui implémente l'interface de PHP Data Objects (PDO) pour autoriser l'accès de PHP aux bases de données MySQL.
Ce pilote sera toujours utilisé (y compris avec les frameworks : w3.js et AngularJS)
Voir : Fichier PHP de connexion
PHP - MySQL
Les requêtes SQL relatives aux enregistrements peuvent se diviser en deux catégories.
- Requête de consultation (SELECT) -> query()
- Requête d'action (INSERT, UPDATE et DELETE) -> exec()
query()
$sql = "SELECT nom AS a, prenom AS b FROM table"; $rep=$bdd->query($sql); if ($rep===FALSE) die; /* code minimaliste */ $data=$rep->fetchAll(PDO::FETCH_ASSOC); echo "{\"lignes\":".json_encode($data)."}"; /* retourne au format JSON */
exec()
$sql = "UPDATE table SET pwd=MD5('".$newPwd."') WHERE id=".$id; $rep=$bdd->exec($sql); /* $rep = nombre de lignes affectées */ if($rep==1) {header("Location:index.php");} else {die("échec");} /* code minimaliste */
PHP - MySQL - w3.js
w3.js est un framework JS qui simplifie le code nécessaire à l'affichage des données (souvent, dans un tableau). PHP - MySQL - JSON - w3.js forment un quarté gagnant.
Voir le résumé de w3P.js
PHP - JSON
$file = 'tauxBe.json'; $data = file_get_contents($file); $obj = json_decode($data); echo $obj[0]->b;
PHP - MySQL - AngularJS
AngularJS est un framework JS qui simplifie le code nécessaire à l'affichage des données (souvent, dans un tableau). PHP - MySQL - JSON - AngularJS forment un quarté gagnant.
Bien que plus puissant que w3.js, AngularJS semble être en baisse de popularité
Afficher le contenu d'une table
mysql_01.htm (extrait)
<head> ... <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script> <script src="mysql_01.js"></script> ... </head> <body> ... <div data-ng-app="monApplication" data-ng-controller="monControleur"> <p> <button data-ng-click="afficherTable()">Afficher le contenu de la table 'voitures'</button> </p> <p> Affichage de contrôle de l'objet JSON voitures : </p> <p class="code"> {{voitures}}<br /> </p> <table border="1"> <tr> <th>Marque</th> <th>Modèle</th> <th>Pays</th> </tr><!-- Placement des enregistrements dans le tableau HTML --> <tr data-ng-repeat="voiture in voitures"> <td>{{voiture.marque}}</td> <td>{{voiture.modele}}</td> <td>{{voiture.pays}}</td> </tr> </table> </div>
Ce n'est plus le serveur qui crée le code HTML du tableau (via du code PHP),
mais le navigateur web (via du code JavaScript). D'ailleurs, le fichier ne
contient que du code HTML. Il possède l'extension .htm
, il est donc envoyé
tel quel au navigateur web par le serveur.
Après réception de ce fichier HTML, le navigateur appelle, dans l'ordre, deux JavaScript
: AngularJS et mysql_01.js
.
mysql_01.js
appelle le fichier mysql_01.php
qui répond par
l'envoi d'un objet JSON (qui contient les données à afficher dans le tableau HTML)
Cet objet JSON est ensuite envoyé au controller de l'application Angular qui s'occupe de la présentation selon les instructions données dans le fichier HTML.
La "magie" d'AngularJS ne s'exerce que dans la zone (<div>) :
<div data-ng-app="monApplication" data-ng-controller="monControleur"> ... </div>
Toutes les instructions AngularJS doivent être placées dans cette zone. HTML5 autorise l'ajout d'attributs globaux sans signification en HTML dans une balise, pourvu que le nom de cet attribut débute par data-.
<button data-ng-click="afficherTable()"> Afficher le contenu de la table 'voitures' </button>
On comprend aisément que le bouton appelle la fonction afficherTable()
,
située dans le JavaScript, lorsqu'il est cliqué.
<p>
Affichage de contrôle de l'objet JSON voitures :
</p>
<p class="code">
{{voitures}}<br />
</p>
Ce code HTML affiche le contenu de l'objet JSON. Il permet au développeur de comprendre. En production, ce code HTML ne signifiera rien au visiteur. Ce code devra donc être supprimé.
Le coeur de la "magie" se trouve donc ici :
<tr data-ng-repeat="voiture in voitures"> <td>{{voiture.marque}}</td> <td>{{voiture.modele}}</td> <td>{{voiture.pays}}</td> </tr>
L'objet JSON voitures
est un tableau d'objets.
L'objet voiture
est un élément du tableau (qui représente un enregistrement
de la table voitures). Ici, chaque élément dispose de trois propriétés dont les noms
correspondent aux noms des colonnes de la table voitures (et dont la valeur représente la
donnée contenue dans cette colonne pour cet enregistrement de la table voitures).
Le navigateur web exécute des instructions écrites dans différents langages (HTML, CSS, JS). Pour assurer l'affichage, il possède autant d'interprétateurs que de langages.
Cliquez ici pour voir la page permettant d'afficher la table dans un tableau.
mysql_01.js (code complet)
/* Ce JS retourne un objet JSON, nommé "voitures",
créé après l'appel d'un fichier PHP */
// Déclaration du module nommé monApplication
var app = angular.module("monApplication", []);
// Déclaration du contrôleur nommé monControleur
app.controller("monControleur", function($scope, $http) {
// Fonction d'affichage de la table
$scope.afficherTable = function() {
/* Via la fonction get()
=> URL sans paramètre ou passés dans l'URL)*/
$http.get("mysql_01.php")
.then(function(response) {
$scope.voitures = response.data;
});
};
});
Ce code n'est pas expliqué ! Il est donné tel quel. Bonne chance ...
Néanmoins, pour plus d'info, cliquez ici
En réalité, pour un débutant, il n'est pas nécessaire de le comprendre pour l'utiliser.
Pour conduire une voiture, il n'est pas nécessaire de comprendre le fonctionnement du
moteur.
.voitures
est l'objet JSON utilisé sur la page HTML
.data
sont les données envoyées par le fichier PHP
Ces données s'appellent toujours "data". Ici, elles sont au format JSON
mysql_01.php (code complet)
<?php // Informe l'appelant (mysql_01.js) que la réponse sera de type JSON header("Content-Type: application/json"); // Connexion à la DB require("maConnexion.php"); // Création de la requête SQL $voitures=$prefixT."voitures"; $sql = "SELECT * FROM $voitures ORDER BY pays"; // Soumission de la requête SQL $rep=$bdd->query($sql); // Réponse du présent fichier echo json_encode($rep->fetchAll(PDO::FETCH_ASSOC)); // Fermeture de la connexion MySQL $bdd=null; ?>
echo
va envoyer des données. Cependant, ici les données ne seront pas
intégrées dans un fichier PHP (page web), mais envoyées à l'appelant - le fichier
mysql_01.js - au format JSON, car Content-Type: application/json
.
Pour plus d'info sur json_encode()
, cliquez ici.
Pour plus d'info sur fetchAll()
, cliquez ici.
Pour plus d'info sur PDO::FETCH_ASSOC
, cliquez ici.
Afficher le contenu d'une table
Afficher une liste déroulante
mysql_02.htm (extrait)
<div data-ng-app="monApplication" data-ng-controller="monControleur"> <p> <select> <option data-ng-repeat="nom in pays" value="{{nom.pays}}"> {{nom.pays}} </option> </select> </p> </div>
Dans data-ng-repeat="nom in pays"
, pays
est le nom de l'objet
JSON (la réponse).
Dans {{nom.pays}}
, pays
est le nom de la propriété de l'objet
nom.
Le code {{ }}
permet d'afficher la valeur d'une variable de l'application
Angular ou, comme ici, la valeur d'une propriété d'un objet.
mysql_02.js (code complet)
var app = angular.module("monApplication", []); app.controller("monControleur", function($scope, $http) { $http.get("mysql_02.php") .then(function(response) { $scope.pays = response.data; }); });
mysql_02.php (code complet)
<?php header("Content-Type: application/json"); require("maConnexion.php"); $voitures=$prefixT."voitures"; $sql = "SELECT DISTINCT pays FROM $voitures"; $rep=$bdd->query($sql); echo json_encode($rep->fetchAll(PDO::FETCH_ASSOC)); $bdd=null; ?>
La clause DISTINCT impose de ne retenir que des valeurs différentes.
Il est préférable de limiter le choix de l'utilisateur aux choix possibles.
Sélectionner des enregistrements
mysql_03.htm (extrait)
<div data-ng-app="monApplication" data-ng-controller="monControleur"> <p> <select data-ng-model="nomPays"> <option data-ng-repeat="nom in pays" value="{{nom.pays}}"> {{nom.pays}} </option> </select> </p> <p> <button data-ng-click="selectionner()">Afficher les enregistrements correspondant</button> </p> <table border="1"> <tr> <th> Marque </th> <th> Modèle </th> </tr> <tr data-ng-repeat="voiture in voitures"> <td> {{voiture.marque}} </td> <td> {{voiture.modele}} </td> </tr> </table> </div>
nomPays
est le nom de la variable AngularJS dont la valeur représente le nom
du pays choisi. Lors du clic, la fonction selectionner()
(située dans le
fichier mysql_03.js) est appelée. Cette fonction transmet au fichier mysql_03.php la
valeur de la variable nomPays
et gère la réponse du fichier PHP.
mysql_03.js (code complet)
var app = angular.module("monApplication", []); app.controller("monControleur", function($scope, $http) { $http.get("mysql_02.php") .then(function(response) { $scope.pays = response.data; }); $scope.selectionner = function() { $http.get("mysql_03.php?pays="+$scope.nomPays) .then(function(response) { $scope.voitures = response.data; }); }; });
mysql_03.php (code complet)
<?php $pays=$_GET['pays']; header("Content-Type: application/json"); require("maConnexion.php"); $voitures=$prefixT."voitures"; $sql = "SELECT marque, modele FROM $voitures WHERE pays='$pays';"; $rep=$bdd->query($sql); echo json_encode($rep->fetchAll(PDO::FETCH_ASSOC)); $bdd=null; ?>
Sélectionner des enregistrements
Insérer un enregistrement
mysql_04.htm (extrait)
<div data-ng-app="monApplication" data-ng-controller="monControleur">
<table border="1" style="margin:auto;">
<tr>
<th>Pays</th>
<th>Marque</th>
<th>Modèle</th>
</tr>
<tr data-ng-repeat="voiture in voitures">
<td>{{voiture.pays}}</td>
<td>{{voiture.marque}}</td>
<td>{{voiture.modele}}</td>
</tr>
</table>
</div>
<form action="mysql_04.php" method="post">
<p>
Pays : <input name="pays" /><br />
Marque : <input name="marque" /><br />
Modèle : <input name="modele" />
</p>
<p>
<input type="submit">
</p>
</form>
</div>
Tout le code lié à l'affichage du tableau a été vu précédemment.
mysql_04.js (code complet)
var app = angular.module("monApplication", []); app.controller("monControleur", function($scope, $http) { $http.get("mysql_01.php") .then(function(response) { $scope.voitures = response.data; }); });
On réutilise le fichier "mysql_01.php" (car il renvoie un objet JSON qui représente toute
la table "voitures").
Ce fichier ressemble au fichier mysql_01.js. Ici, le tableau
s'affiche directement.
mysql_04.php (code complet)
<?php $pays=$_POST['pays']; $marque=$_POST['marque']; $modele=$_POST['modele']; require("maConnexion.php"); $voitures=$prefixT."voitures"; $sql="INSERT INTO $voitures (marque,modele,pays) VALUES ('$marque','$modele','$pays');"; $rep=$bdd->exec($sql); $bdd=null; header("Location: mysql_04.htm"); ?>
Grâce à la fonction header(), après la demande d'insertion, on retourne sur la page initiale (mysql_04.htm); ce qui permet de constater l'insertion.
Pour plus d'info sur la fonction header(), cliquez ici
Insérer via data-ng-click
mysql_04b.htm (extrait)
<div data-ng-app="monApplication" data-ng-controller="monControleur"> <p> Pays : <input data-ng-model="pays" /> {{pays}}<br /> Marque : <input data-ng-model="marque" /><br /> Modèle : <input data-ng-model="model" /> </p> <p> <button data-ng-click="insert(pays,marque,model)">Insérer les données</button> </p> </div>
La directive AngularJS data-ng-model
lie le champ d'un formulaire à
une variable de l'application AngularJS. pays est le nom d'une
variable. Tout ce qui tapé dans le champ "Pays" va directement dans la variable
pays.
À droite du champ "Pays", le code {{pays}}
permet d'afficher le contenu de
la variable pays. On constate ainsi que le contenu de la variable
pays est synchrone (correspond toujours au contenu du champ auquel elle est
liée)
Lors du clic, le contenu des trois variables - pays, marque, model - est passé à la
fonction insert()
qui est appelée.
mysql_04b.js (code complet)
var app = angular.module("monApplication", []); app.controller("monControleur", function($scope, $http) { $scope.insert = function(pays,marque,model) { $http({ url:"mysql_04b.php", method:"POST", data:{marque:marque,modele:model,pays:pays}, headers:{"Content-Type":"application/x-www-form-urlencoded"} }) }; });
Ce code n'est pas expliqué ! Mais, pour un débutant, il n'est pas nécessaire de le comprendre pour l'utiliser.
Notez qu'il n'est pas nécessaire de construire l'objet JSON - {marque:...,modele:...,pays:...} - en plaçant les variables dans l'ordre où ils sont passés dans la fonction : pays,marque,model.
Notez aussi que le nom des propriétés de l'objet JSON ne doit pas nécessairement correspondre aux nom des paramètres de la fonction. Ainsi, ici, modele est le nom d'une propriété de l'objet JSON et model est le nom de la variable liée au champ HTML "Modèle"
mysql_04b.php (code complet)
<?php $paramApp=file_get_contents("php://input"); $obj=json_decode($paramApp); $marque=$obj->marque; $modele=$obj->modele; $pays=$obj->pays; require("maConnexion.php"); $voitures=$prefixT."voitures"; $sql="INSERT INTO $voitures (marque,modele,pays) VALUES ('$marque','$modele','$pays');"; $rep=$bdd->exec($sql); $bdd=null; ?>
Ce code n'est pas expliqué ! Mais, pour un débutant, il n'est pas nécessaire de le comprendre pour l'utiliser.
Supprimer un enregistrement
Avant de supprimer un enregistrement, il faut le sélectionner. On affichera donc le tableau avec une colonne contenant un lien pour supprimer l'enregistrement choisi.
mysql_05.htm (extrait)
<tr data-ng-repeat="voiture in voitures">
<td>{{voiture.marque}}</td>
<td>{{voiture.modele}}</td>
<td>{{voiture.pays}}</td>
<td>
<a href="mysql_05.php?id={{voiture.id_voiture}}">❌</a>
</td>
</tr>
Le code lié à l'affichage du tableau varie peu par rapport ce qu'on a vu précédemment.
Le code HTML ❌
affiche : ❌
Voir aussi : Encodage des caractères spéciaux
Analysons : mysql_05.php?id={{voiture.id_voiture}}
C'est une URL.
{{voiture.id_voiture}}
représente la valeur de la propriété
id.voiture de l'objet voiture (un nombre entier attribué
automatiquement à un enregistrement dans la table "voitures"). En passant la souris sur
ce lien s'affichera (en bas de la fenêtre du navigateur) la valeur (un nombre entier
positif) qui sera envoyée au fichier "mysql_05.php". Par exemple, 1.
mysql_04.js (complet)
var app = angular.module("monApplication", []); app.controller("monControleur", function($scope, $http) { $http.get("mysql_01.php") .then(function(response) { $scope.voitures=response.data; }); });
Ce code vu précédemment ne sert qu'à l'affichage du tableau.
mysql_05.php (complet)
<?php $id=$_GET['id']; require("maConnexion.php"); $voitures=$prefixT."voitures"; $sql = "DELETE FROM $voitures WHERE id_voiture=$id;"; $rep=$bdd->exec($sql); $bdd=null; header("Location: mysql_05.htm"); ?>
La fonction header() a été vue précédemment. Après la demande de suppression, on retourne sur la page initiale (mysql_05.htm); ce qui permet de constater sa suppression.
Mettre à jour un enregistrement
mysql_06.htm (extrait)
<div data-ng-app="monApplication" data-ng-controller="monControleur"> <table border="1" style="margin:auto;"> <tr> <th>Pays</th> <th>Marque</th> <th>Modèle </th><th>Modifier</th> </tr> <tr data-ng-repeat="voiture in voitures"> <td>{{voiture.pays}}</td> <td>{{voiture.marque}}</td> <td>{{voiture.modele}}</td> <td> <button data-ng-click="selectionner(voiture.id_voiture)">Modifier</button> </td> </tr> </table> <form action="mysql_06.php" method="post"> <p> Pays : <input name="pays" data-ng-model="pays" /><br /> Marque : <input name="marque" data-ng-model="marque" /><br /> Modèle : <input name="modele" data-ng-model="modele" /> <input type="hidden" name="id_voiture" data-ng-value="id_voiture" /> </p><input type="submit" /> </form> </div>
Quasi tout le code lié à l'affichage du tableau a été vu précédemment.
La dernière colonne du tableau contient des boutons. Un clic sur un bouton entraîne le remplissage du formulaire, situé sous le tableau, avec les données en regard du bouton cliqué.
<button data-ng-click="selectionner(voiture.id_voiture)"> Modifier </button>
La directive AngularJS ng-click a été vu précédemment. La différence est qu'ici la fonction contient un paramètre (l'ID de la voiture).
Attention ! On écrit
selectionner(voiture.id_voiture)
et non selectionner({{voiture.id_voiture}})
...
La directive AngularJS ng-model permet de lier le contenu d'un champ d'un formulaire à un nom de variable AngularJS.
Pour plus d'info sur la directive AngularJS ng-model, cliquez ici.
Un exemple de l'utilisation de cette directive a été présenté lorsque l'insertion d'un
enregistrement a été abordé : Insérer via
data-ng-click.
Bien que ce type d'insertion d'un enregistrement ne doit pas être compris par un
débutant, le remplissage du champ "pays" montre le contenu de la variable AngularJS
pays synchronisé.
La directive AngularJS ng-value permet de lier la valeur d'un champ d'un formulaire à un nom de variable AngularJS.
Pour plus d'info sur la directive AngularJS ng-value, cliquez ici.
La valeur de la variable AngularJS id_voiture est donné par la fonction selectionner() contenu dans le JavaScript lié à ce fichier HTML.
mysql_06.js (code complet)
var app = angular.module("monApplication", []); app.controller("monControleur", function($scope, $http) { $http.get("mysql_01.php") .then(function(response) { $scope.voitures = response.data; }); $scope.selectionner = function(id) { for (i = 0, len = $scope.voitures.length; i < len; i++) { if ($scope.voitures[i].id_voiture==id){ $scope.pays=$scope.voitures[i].pays; $scope.marque=$scope.voitures[i].marque; $scope.modele=$scope.voitures[i].modele; $scope.id_voiture=$scope.voitures[i].id_voiture; break; } } }; });
On réutilise le fichier "mysql_01.php" (car il renvoie un objet JSON qui représente toute
la table "voitures").
Ce fichier ressemble au fichier mysql_01.js. Ici, le tableau
s'affiche directement.
La fonction selectionner() parcourt l'objet JSON voitures à la
recherche d'un ID voiture correspondant à celui fourni lors du clic sur le bouton
"Modifier". Une fois trouvé, il met à jour les champs du formulaire, y compris le champ
caché; puis quitte la boucle (break;
).
mysql_06.php (code complet)
<?php $id_voiture=$_POST['id_voiture']; $pays=$_POST['pays']; $marque=$_POST['marque']; $modele=$_POST['modele']; require("maConnexion.php"); $voitures=$prefixT."voitures"; $sql="UPDATE $voitures SET pays='$pays', marque='$marque', modele='$modele' WHERE id_voiture=$id_voiture;"; $rep=$bdd->exec($sql); $bdd=null; header("Location: mysql_06.htm"); ?>
La fonction header() a été vue précédemment. Après la demande de mise à jour, on retourne sur la page initiale (mysql_06.htm); ce qui permet de constater sa modification.
Mettre à jour un enregistrement
Afin de se centrer sur l'essentiel, les codes "complets" présentés ci-dessus sont "minimalistes". Aucune validation des données est faite avant leur envoi au serveur. Aucune vérification de l'identité de celui qui demande une modification de la base de données n'est faite. Aucune réponse du serveur MySQL n'affichée en cas d'une insertion, suppression ou modification d'un enregistrement. De plus, ces codes ne gèrent pas le cas des enregistrement identiques (doublons) ni les cas triviaux : Absence de table, de colonnes, table vide, ...
Voir aussi : Trier les colonnes