Le but de ce guide c'est de vous faire mettre en place, étape par étape le premier CRUD (Create, Read, Update, Delete) de votre projet, celui des utilisateurs.
Pourquoi commencer par les utilisateurs ? Comme votre projet doit avoir une interface d'administration, vous devrez tous et toutes mettre en place une gestion, même minimale des utilisateurs. Cela permet donc de faire un exercice qui vous est utile, indépendamment des spécificités de votre projet.
L'autre avantage de commencer par les utilisateurs, c'est qu'une fois qu'ils sont en place, vous pourrez enchaîner sur le guide suivant, qui vous permettra de mettre en place l'authentification, qui est un processus qui fait parfois peur, mais dont vous avez tous et toutes besoin dans vos projets.
Étape 1 : Créer la table dans la base de données
L'utilisateur que nous allons manipuler dans ce guide comprend donc 5 champs :
id
email
password
first_name (prénom em francais)
last_name (nom de famille en français)
Dans votre base de données, vous allez donc créer une table users qui contient 5 colonnes :
Nom du champ
Type du champ
id
INT auto-incrémenté
email
VARCHAR(255)
password
VARCHAR(255)
first_name
VARCHAR(255)
last_name
VARCHAR(255)
Utilisez PHPMyAdmin pour créer votre table. Une fois que c'est fait sa structure doit être semblable à l'image ci-dessous :
Étape 2 : créer le modèle User
Dans votre fichier models/User.php vous allez créer une classe User qui correspond à la table que vous venez de créer.
Votre classe aura donc des attributs qui correspondent aux colonnes de la table dams la base de données :
Nom de l'attribut
Type de l'attribut
id
int ou null
email
string
password
string
first_name
string
last_name
string
Votre classe doit également contenir un constructeur et des getters et setters pour chacun des attributs.
<?php
class User {
public function __construct(private string $email, private string $password, private string $firstName, private string $lastName, private ? int $id = null)
{
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): void
{
$this->email = $email;
}
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): void
{
$this->password = $password;
}
public function getFirstName(): string
{
return $this->firstName;
}
public function setFirstName(string $firstName): void
{
$this->firstName = $firstName;
}
public function getLastName(): string
{
return $this->lastName;
}
public function setLastName(string $lastName): void
{
$this->lastName = $lastName;
}
public function getId(): ?int
{
return $this->id;
}
public function setId(?int $id): void
{
$this->id = $id;
}
}
Étape 3 : mise en place du Routeur
Maintenant que nous avons notre base de données et notre model, nous allons un peu nous éloigner de ce qui touche aux données et nous concentrer sur le fait de pouvoir afficher des choses.
Nous allons commencer par mettre en place notre routeur. Pour pouvoir avoir un CRUD efficace nous avons besoin de pouvoir accomplir plusieurs actions :
consulter la liste des utilisateurs
consulter le détail d'un utilisateur
créer un utilisateur
modifier un utilisateur
supprimer un utilisateur
Pour faire ces actions, nous allons avoir besoin de routes (plus de routes que d'actions, car nous avons des routes de vérification). Voici la liste des routes que nous devrons mettre en place :
Nom de la route
Paramètres de la route
À quoi elle sert
list-users
Liste des utilisateurs
details-user
id de l'utilisateur
Détails d'un utilisateur
update-user
id de l'utilisateur
Affiche le formulaire de modification d'un utilisateur
check-update-user
id de l'utilisateur
Vérifie le formulaire et modifie l'utilisateur
create-user
Affiche le formulaire de création d'un utilisateur
check-create-user
Vérifie le formulaire et créée l'utilisateur
delete-user
id de l'utilisateur
Supprime un utilisateur
Notre classe Router devra donc nous permettre de mettre en place ces routes et par la suite de les rediriger vers les bonnes méthodes de Controllers.
Notre classe Router ne contient qu'une seule méthode, dont le prototype est le suivant :
public function handleRequest(array $get)
Cette méthode handleRequest va vérifier si le tableau $get qu'elle reçoit en paramètres contient bien une entrée "route".
Si oui, elle va ensuite devoir vérifier que la valeur de "route" correspond bien au nom d'une des routes du tableau un peu plus haut.
À quoi ça ressemble en code ?
class Router {
public function handleRequest(array $get)
{
if(!empty($get['route'])) { // route existe et n'est pas vide
if($get['route'] === "list-users") {
}
else if($get['route'] === "details-user") {
}
else if($get['route'] === "update-user") {
}
else if($get['route'] === "check-update-user") {
}
else if($get['route'] === "create-user") {
}
else if($get['route'] === "check-create-user") {
}
else if($get['route'] === "delete-user") {
}
else // n'importe quelle route pas prévue : page 404
{
}
}
else // pas de route je renvoie vers la home
{
}
}
}
Ensuite pour pouvoir tester notre router, nous allons mettre des affichages temporaires dans nos conditions :
class Router {
public function handleRequest(array $get)
{
if(!empty($get['route'])) { // route existe et n'est pas vide
if($get['route'] === "list-users") {
echo "La route demandée est list-users<br>";
}
else if($get['route'] === "details-user") {
}
else if($get['route'] === "update-user") {
}
else if($get['route'] === "check-update-user") {
}
else if($get['route'] === "create-user") {
}
else if($get['route'] === "check-create-user") {
}
else if($get['route'] === "delete-user") {
}
else // n'importe quelle route pas prévue : page 404
{
echo "La route demandée n'existe pas<br>";
}
}
else // pas de route je renvoie vers la home
{
echo "Aucune route n'est demandée<br>";
}
}
}
Je vous ai fait des exemples pour certaines conditions, à vous de créer les affichages de texte pour celles restantes.
class Router {
public function handleRequest(array $get)
{
if(!empty($get['route'])) { // route existe et n'est pas vide
if($get['route'] === "list-users") {
echo "La route demandée est list-users<br>";
}
else if($get['route'] === "details-user") {
echo "La route demandée est details-user<br>";
}
else if($get['route'] === "update-user") {
echo "La route demandée est update-user<br>";
}
else if($get['route'] === "check-update-user") {
echo "La route demandée est check-update-user<br>";
}
else if($get['route'] === "create-user") {
echo "La route demandée est create-user<br>";
}
else if($get['route'] === "check-create-user") {
echo "La route demandée est check-create-user<br>";
}
else if($get['route'] === "delete-user") {
echo "La route demandée est delete-user<br>";
}
else // n'importe quelle route pas prévue : page 404
{
echo "La route demandée n'existe pas<br>";
}
}
else // pas de route je renvoie vers la home
{
echo "Aucune route n'est demandée<br>";
}
}
}
Étape 4 : Mise en place du UserController
Nous avons maintenant un Router, nous allons créer le principal Controller qu'il va devoir appeler.
Reprenons la liste de nos routes :
Nom de la route
Paramètres de la route
À quoi elle sert
list-users
Liste des utilisateurs
details-user
id de l'utilisateur
Détails d'un utilisateur
update-user
id de l'utilisateur
Affiche le formulaire de modification d'un utilisateur
check-update-user
id de l'utilisateur
Vérifie le formulaire et modifie l'utilisateur
create-user
Affiche le formulaire de création d'un utilisateur
check-create-user
Vérifie le formulaire et créée l'utilisateur
delete-user
id de l'utilisateur
Supprime un utilisateur
Avec cette liste, nous pouvons déduire les méthodes qui existeront dans notre Controller :
Nom de la route
Méthode Correspondante
list-users
UserController::list()
details-user
UserController::details(int $id)
update-user
UserController::update(int $id)
check-update-user
UserController::checkUpdate(int $id)
create-user
UserController::create()
check-create-user
UserController::checkCreate()
delete-user
UserController::delete(int $id)
Mettons donc en place le squelette de notre UserController avec ces méthodes :
class UserController extends AbstractController {
public function __construct(){
parent::__construct();
}
public function list() : void
{
}
public function details(int $id) : void
{
}
public function update(int $id) : void
{
}
public function checkUpdate(int $id) : void
{
}
public function create() : void
{
}
public function checkCreate() : void
{
}
public function delete(int $id) : void
{
}
}
Ensuite, nous allons faire en sorte d'afficher dans chaque méthode le nom de celle ci, pour pouvoir tester le bon fonctionnement de notre solution.
public function list() : void
{
echo "UserController::list<br>";
}
Basez-vous sur l'exemple ci-dessus et faites des affichages dans chacune des méthodes.
class UserController extends AbstractController {
public function __construct(){
parent::__construct();
}
public function list() : void
{
echo "UserController::list<br>";
}
public function details(int $id) : void
{
echo "UserController::details<br>";
}
public function update(int $id) : void
{
echo "UserController::update<br>";
}
public function checkUpdate(int $id) : void
{
echo "UserController::checkUpdate<br>";
}
public function create() : void
{
echo "UserController::create<br>";
}
public function checkCreate() : void
{
echo "UserController::checkCreate<br>";
}
public function delete(int $id) : void
{
echo "UserController::delete<br>";
}
}
Étape 5 : appeler le UserController dans le Router
Nous avons maintenant un Router et un Controller. Dans cette étape, nous allons relier les deux, en nous basant sur notre tableau de correspondance entre route et méthode de controller :
Nom de la route
Méthode Correspondante
list-users
UserController::list()
details-user
UserController::details(int $id)
update-user
UserController::update(int $id)
check-update-user
UserController::checkUpdate(int $id)
create-user
UserController::create()
check-create-user
UserController::checkCreate()
delete-user
UserController::delete(int $id)
Nous allons commencer par modifier notre Router en lui ajoutant un UserController en attribut :
class Router {
private UserController $uc;
public function __construct() {
$this->uc = new UserController();
}
public function handleRequest(array $get)
{
if(!empty($get['route'])) { // route existe et n'est pas vide
if($get['route'] === "list-users") {
echo "La route demandée est list-users<br>";
}
else if($get['route'] === "details-user") {
echo "La route demandée est details-user<br>";
}
else if($get['route'] === "update-user") {
echo "La route demandée est update-user<br>";
}
else if($get['route'] === "check-update-user") {
echo "La route demandée est check-update-user<br>";
}
else if($get['route'] === "create-user") {
echo "La route demandée est create-user<br>";
}
else if($get['route'] === "check-create-user") {
echo "La route demandée est check-create-user<br>";
}
else if($get['route'] === "delete-user") {
echo "La route demandée est delete-user<br>";
}
else // n'importe quelle route pas prévue : page 404
{
echo "La route demandée n'existe pas<br>";
}
}
else // pas de route je renvoie vers la home
{
echo "Aucune route n'est demandée<br>";
}
}
}
Nous allons ensuite remplacer nos affichages temporaires par l'appel des méthodes du Controller. Pour les méthodes qui prennent en id en paramètre, emvoyez simplement le nombre 42.
Nous n'avons pas encore de Controller qui gère la home et la page 404 donc laissez ces deux conditions telles quelles.
class Router {
private UserController $uc;
public function __construct() {
$this->uc = new UserController();
}
public function handleRequest(array $get)
{
if(!empty($get['route'])) { // route existe et n'est pas vide
if($get['route'] === "list-users") {
$this->uc->list();
}
else if($get['route'] === "details-user") {
$this->uc->details(42);
}
else if($get['route'] === "update-user") {
$this->uc->update(42);
}
else if($get['route'] === "check-update-user") {
$this->uc->checkUpdate(42);
}
else if($get['route'] === "create-user") {
$this->uc->create();
}
else if($get['route'] === "check-create-user") {
$this->uc->checkCreate();
}
else if($get['route'] === "delete-user") {
$this->uc->delete(42);
}
else // n'importe quelle route pas prévue : page 404
{
echo "La route demandée n'existe pas<br>";
}
}
else // pas de route je renvoie vers la home
{
echo "Aucune route n'est demandée<br>";
}
}
}
Étape 6 : appel du Router dans l'index
Avant toute chose, nous allons commencer par faire charger nos classes à notre programme, vu que nous utilisons un composer.json nous allons utiliser une commande composer pour charger nos classes :
composer dump-autoload
Puis nous allons instancier un Router dans notre index.php et appeler sa méthode handleRequest:
$router = new Router();
$router->handleRequest($_GET);
Étape 7 : tester les routes
Pour tester vos routes, vous allez run votre fichier index.php et modifier à la main les URLs dans le navigateur. Dans mon navigateur à moi le projet est sur l'URL de base localhost adaptez les URLs suivantes au format sur votre poste :
Route testée
URL à saisir
Résultat attendu
Pas de route
index.php
Aucune route n'est demandée
list-users
index.php?route=list-users
UserController::list
details-user
index.php?route=details-user
UserController::details
create-user
index.php?route=create-user
UserController::create
check-create-user
index.php?route=check-create-user
UserController::checkCreate
update-user
index.php?route=update-user
UserController::update
check-update-user
index.php?route=check-update-user
UserController::checkUpdate
delete-user
index.php?route=delete-user
UserController::delete
toto
index.php?route=toto
La route demandée n'existe pas
Si tous ces tests fonctionnent : votre routeur et votre controller font bien leur travail de routing.
Étape 8 : les templates
Dans cette étape, nous allons mettre en place nos templates.
Commencez par remplir votre fichier templates/admin/layout.html.twig avec le contenu suivant :
Vous allez ensuite créer un dossier templates/admin/users dans lequel vous allez créer 4 fichiers :
list.html.twig
details.html.twig
create.html.twig
update.html.twig
Pour l'instant, nous n'allons nous occuper que de list.html.twig, vous pouvez y ajouter le code suivant :
{% extends 'admin/layout.html.twig' %}
{% block title %} Liste des Users | {{ parent() }} {% endblock %}
{% block main %}
<main class="container py-5">
<h1 class="mb-3">Liste des utilisateurs</h1>
<a href="index.php?route=create-user" class="my-3 btn btn-primary">Ajouter un utilisateur</a>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Email</th>
<th>Prénom</th>
<th>Nom</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</main>
{% endblock %}
Étape 9 : afficher le template depuis la méthode du Controller
Dans la méthode list de votre UserController, vous allez remplacer le echo d'affichage par un appel au moteur de rendu Twig en utilisant la méthode render que vous fournit l'AbstractController :
public function list() : void
{
$this->render('admin/users/list.html.twig', []);
}
À présent lorsque vous testez l'URL pour list-users dans votre navigateur, elle devrait afficher ceci :
Étape 10 : mettre en place le UserManager
Nous allons commencer par mettre en place le squelette de notre UserManager avec ses méthodes vides :
class UserManager extends AbstractManager {
public function __construct() {
parent::__construct();
}
public function findAll() : array {
return [];
}
public function findOne(int $id) : ? User {
return null;
}
public function findByEmail(string $email) : ?User {
return null;
}
public function create(User $user) : bool {
return true;
}
public function update(User $user) : bool {
return true;
}
public function delete(User $user) : bool {
return true;
}
}
Puis, nous allons l'ajouter à notre autoload en faisant la commande suivante dans le terminal :
composer dump-autoload
Ensuite, nous allons mettre en place le contenu de la méthode dont nous avons besoin pour notre page de liste des utilisateurs : la méthode findAll.
Le but de cette méthode, c'est de nous renvoyer un tableau de tous les utilisateurs présents dans la base de données. Et comme nous travaillons en MVC et POO de nous les renvoyer sous la forme d'instances de notre model User.
Comment allons-nous faire ça ?
Tout d'abord, nous allons préparer une requête SQL qui permet de récupérer tous les champs de tous les users inscrits en base de données :
SELECT * FROM users
Nous allons ensuite utiliser l'instance de PDO qui est chargée dans le constructeur de l'AbstractManager et donc héritée par le UserManager pour interroger la base de données.
Notre variable $results conteint à présent un tableau de tableaux associatifs, renvoyés par la base de données. Nous voulons donc transformer ça en tableau d'instances de la classe User que notre méthode pourra return.
public function findAll() : array {
$query = $this->db->prepare('SELECT * FROM users');
$parameters = [];
$query->execute($parameters);
$results = $query->fetchAll(PDO::FETCH_ASSOC);
$users = [];
foreach($results as $result)
{
$user = new User($result['email'], $result['password'], $result['first_name'], $result['last_name'], $result['id']);
$users[] = $user;
}
return $users;
}
Dans l'étape suivante, nous allons voir comment tester que tout cela fonctionne.
Étape 11 : tester la méthode findAll du UserManager
Notre méthode UserManager::findAll va devoir être appellée dans notre méthode UserController::list, ça toombe bien nous avons déjà mis en place cette méthode et nous savons qu'elle fonctionne. Nous allons simplement lui ajouter :
L'instanciation d'un UserManager
L'appel à la méthode findAll
Un dump du résultat de findAll
l'envoie du résultat de findAll au template
En code ça ressemble à ça :
public function list() : void
{
$um = new UserManager();
$users = $um->findAll();
dump($users);
die;
$this->render('admin/users/list.html.twig', [
'users' => $users
]);
}
Lorsque vous allez tester votre route pour l'URL index.php?route=list-users dans votre navigateur, vous allez obtenir ceci :
C'est normal, nous n'avons pas encore d'utilisateurs dans notre base de données.
Je vais donc utiliser PHPMyAdmin pour en ajouter un de test :
Quand vous retestez votre URL, vous obtenez ceci :
Une fois que cela fonctionne pour vous, retirez l'affichage de test dans votre méthode de Controller :
public function list() : void
{
$um = new UserManager();
$users = $um->findAll();
$this->render('admin/users/list.html.twig', [
'users' => $users
]);
}
Étape 12 : dynamiser le template de la liste des utilisateurs
Pour afficher la liste de nos utilisateurs dans notre template admin/users/list.html.twig nous allons devoir utiliser une boucle pour remplir la balise <tbody> de notre tableau.
Pour chacun des utilisateurs, nous allons créer une ligne dans le tableau (balise <tr>) et chacun des champs de l'utilisateur correspondra à une colonne de cette ligne (balise <td>). Dans la dernière colonne nous allons mettre nos 3 boutons d'actions qui permettront de :
Voir le détail de l'utilisateur
Modifier l'utilisateur
Supprimer l'utilisateur
Voilà ce que cette boucle donne en code en utilisant Twig :
Placez ce code au bon emplacement dans votre template pour pouvoir afficher les informations des utilisateurs. Une fois que cela fonctionne, vous devriez obtenir ceci :
Étape 13 : le template du formulaire de création d'un utilisateur
La prochaine partie du CRUD sur laquelle nous allons nous pencher c'est la création d'un utilisateur, et nous allons commencer par le template qui affiche le formulaire de création d'un utilisateur.
Apparté diagramme de séquence
Voici le diagramme de séquence du déroulement de la création d'un utilisateur :
Retour au template
Dans le template admin/users/create.html.twig, placez le code suivant :
Elle enverra directement le formulaire vers la route que nous avons mise en place pour traiter le formulaire de création.
C'est donc la partie "soumission du formulaire de création" de notre diagramme de séquence
Étape 14 : Afficher le template du formulaire depuis le UserController
Faites en sorte d'afficher le template admin/users/create.html.twig dans la méthode UserController::create.
public function create() : void
{
$this->render('admin/users/create.html.twig', [
]);
}
Si tout fonctionne bien lorsque vous testez l'URL de la page de création index.php?route=create-user vous devriez obtenir ceci :
Étape 15 : Traiter le formulaire de création
Nous allons maintenant nous occuper des étapes suivantes de notre diagramme de séquence :
Nous allons donc vérifier 2 conditions principales :
Tous les champs sont remplis
Il n'existe pas d'utilisateur avec cet email
Dans la méthode UserController::checkCreate vous allez d'abord vérifier que tous les champs du formulaire sont bien remplis :
if(!empty($_POST["email"]) && !empty($_POST["password"]) && !empty($_POST["first_name"]) && !empty($_POST["last_name"])){
// tous les champs sont remplis
}
else
{
// certains champs ne sont pas remplis
}
Ensuite si tous les champs sont remplis, nous allons utiliser la méthode findByEmail du UserManager pour vérifier si un utilisateur avec cet email existe déjà. Cette méthode n'est pas encore codé, mais en regardant son prototype, nous savons qu'elle peut renvoyer null ou un User.
C'est le cas où elle renvoie null qui nous intéresse, car cela voudrait dire que l'utilisateur n'existe pas déjà donc nous pouvons le créer.
public function checkCreate() : void
{
if(!empty($_POST["email"]) && !empty($_POST["password"]) && !empty($_POST["first_name"]) && !empty($_POST["last_name"]))
{
// tous les champs sont remplis
$um = new UserManager();
$user = $um->findByEmail($_POST["email"]);
if($user === null)
{
// il n'existe pas, on peut le créer
}
else
{
// un utilisateur avec cet email existe déjà
}
}
else
{
// certains champs ne sont pas remplis
}
}
Si nous pouvons créer l'utilisateur (il n'existe pas déjà et tous les champs sont saisis) nous allons passer au bloc "Le formulaire est valide" de notre diagramme de séquence :
La première chose que nous allons faire c'est donc d'instancier un modèle User avec les données du formulaire :
$user = new User($_POST["email"], $_POST["password"], $_POST["first_name"], $_POST["last_name"]);
Le UserManager a déjà été instancié pour vérifier la validité du formulaire nous allons donc le réutiliser pour appeler sa méthode create:
$ret = $um->create($user);
UserManager::create retourne un booleen donc nous pouvons savoir si notre création a fonctionné ou pas. Si elle a fonctionné nous redirigeons vers la page de liste des utilisateurs :
if($ret)
{
header("Location: index.php?route=list-users");
}
else
{
// la création a échoué.
}
class UserController extends AbstractController {
public function __construct(){
parent::__construct();
}
public function list() : void
{
$um = new UserManager();
$users = $um->findAll();
$this->render('admin/users/list.html.twig', [
'users' => $users
]);
}
public function details(int $id) : void
{
echo "UserController::details<br>";
}
public function update(int $id) : void
{
echo "UserController::update<br>";
}
public function checkUpdate(int $id) : void
{
echo "UserController::checkUpdate<br>";
}
public function create() : void
{
$this->render('admin/users/create.html.twig', [
]);
}
public function checkCreate() : void
{
if(!empty($_POST["email"]) && !empty($_POST["password"]) && !empty($_POST["first_name"]) && !empty($_POST["last_name"]))
{
// tous les champs sont remplis
$um = new UserManager();
$user = $um->findByEmail($_POST["email"]);
if($user === null)
{
// il n'existe pas, on peut le créer
$user = new User($_POST["email"], $_POST["password"], $_POST["first_name"], $_POST["last_name"]);
$ret = $um->create($user);
if($ret)
{
header("Location: index.php?route=list-users");
}
else
{
// la création a échoué.
}
}
else
{
// un utilisateur avec cet email existe déjà
}
}
else
{
// certains champs ne sont pas remplis
}
}
public function delete(int $id) : void
{
echo "UserController::delete<br>";
}
}
Étape 16 : gérer les erreurs du formulaire
Pour pouvoir gérer les erreurs de nos formulaires, nous allons devoir utiliser les sessions. Nous allons donc les activer dans notre index.php:
<?php
// charge l'autoload de composer
require "vendor/autoload.php";
session_start(); // démarrage de la session
// charge le contenu du .env dans $_ENV
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$router = new Router();
$router->handleRequest($_GET);
Ensuite dans nos templates, nous allons faire en sorte de pouvoir afficher des messages d'erreur.
D'abord dans le template de notre formulaire de création admin/users/create.html.twig:
{% if errors %}
{% for error in errors %}
<div class="alert alert-danger mb-3" role="alert">
{{ error }}
</div>
{% endfor %}
{% endif %}
Si notre template reçoit des erreurs à afficher, il fait une boucle sur la liste des erreurs et affiche une alerte pour chacune d'entre elle.
Mais comment envoyer ces erreurs au template ? Nous allons le faire via la session dans notre UserController:
Nous allons commencer par créer un tableau d'erreurs vide :
$_SESSION["errors"] = [];
Puis si nous rencontrons des erreurs, nous allons le remplir :
$_SESSION["errors"][] = "La création a échoué lors de l'écriture dans la base de données.";
$_SESSION["errors"][] = "Un utilisateur avec cet email existe déjà.";
$_SESSION["errors"][] = "Au moins un champ obligatoire est manquant.";
Si nous ne rencontrons aucune erreur, nous supprimons le tableau avant de rediriger vers la liste des utilisateurs :
unset($_SESSION["errors"]);
Si nous rencontrons une erreur, nous redirigeons vers la page du formulaire :
header("Location: index.php?route=create-user");
Le code complet :
public function checkCreate() : void
{
$_SESSION["errors"] = [];
if(!empty($_POST["email"]) && !empty($_POST["password"]) && !empty($_POST["first_name"]) && !empty($_POST["last_name"]))
{
// tous les champs sont remplis
$um = new UserManager();
$user = $um->findByEmail($_POST["email"]);
if($user === null)
{
// il n'existe pas, on peut le créer
$user = new User($_POST["email"], $_POST["password"], $_POST["first_name"], $_POST["last_name"]);
$ret = $um->create($user);
if($ret)
{
unset($_SESSION["errors"]);
header("Location: index.php?route=list-users");
}
else
{
$_SESSION["errors"][] = "La création a échoué lors de l'écriture dans la base de données.";
header("Location: index.php?route=create-user");
}
}
else
{
$_SESSION["errors"][] = "Un utilisateur avec cet email existe déjà.";
header("Location: index.php?route=create-user");
}
}
else
{
$_SESSION["errors"][] = "Au moins un champ obligatoire est manquant.";
header("Location: index.php?route=create-user");
}
}
Ensuite c'est notre méthode UserController::create qui va se charger d'envoyer les erreurs au template et de les effacer de la session pour qu'elles ne s'affichent pas en boucle :
public function create() : void
{
if (!empty($_SESSION["errors"])) {
$errors = $_SESSION["errors"];
unset($_SESSION["errors"]);
$this->render('admin/users/create.html.twig', [
"errors" => $errors
]);
} else {
$this->render('admin/users/create.html.twig', [
]);
}
}
Pour pouvoir tester, nous allons devoir faire une modification à la méthode UserManager::create pour le moment elle renvoie true, faites lui renvoyer false.
Ensuite si vous testez votre formulaire de création, vous devriez obtenir ceci :
Étape 17 : les méthodes du UserManager pour la création de l'utilisateur
Dans l'étape de validation par le controller, nous avons appellé deux méthodes de notre UserManager: la méthode findByEmail et la méthode create, nous allons donc les compléter.
UserManager::findByEmail
Voici le prototype de notre méthode UserManager::findByEmail:
public function findByEmail(string $email) : ? User
Elle prend donc un paramètre string $email et retourne null ou une instance de la classe User.
Elle va devoir effectuer une requête pour trouver si un utilisateur inscrit dans la base de données utilise l'email passé en paramètres :
$query = $this->db->prepare('SELECT * FROM users WHERE email = :email');
$parameters = [
':email' => $email
];
$query->execute($parameters);
Si un utilisateur existe, elle va instancier une classe User avec les infos de l'utilisateur et retourner cette instance de classe :
À présent si vous retestez votre formulaire de création d'utilisateur, vous ne devriez plus avoir d'erreur et votre nouvel utilisateur devrait apparaitre dans votre liste.
Étape 18 : supprimer un utilisateur
Pour supprimer un utilisateur, nous allons devoir modifier 2 méthodes : UserController::delete et UserManager::delete.
UserController::delete
public function delete(int $id) : void
{
$um = new UserManager();
$um->delete($id);
header("Location: index.php?route=list-users");
}
UserManager::delete
public function delete(int $id) : bool {
$query = $this->db->prepare("DELETE FROM users WHERE id = :id");
$parameters = [
'id' => $id
];
$query->execute($parameters);
return true;
}
Nous allons également devoir modifier notre Router pour qu'il envoie l'id de l'utilisateur à supprimer au Controller :