Branche 4 — Modèles PHP 8.4 : Model, Article, User et Comment
Objectif : Encapsuler les données et la logique d’accès à la base de données dans des classes PHP 8.3+/8.4.
Nous introduisons un seul héritage : une classe de baseModelqui fournit la connexion PDO, dont héritentArticle,UseretComment.
Pourquoi passer aux Classes ?
Dans la Branche 3, nous avons centralisé les requêtes SQL dans des fonctions dans app/functions/. C’était une grande amélioration.
Mais on peut encore mieux faire :
| Branche 3 — Fonctions | Branche 4 — Classes |
|---|---|
findArticle(5) → retourne un tableau ['id'=>5, ...] |
Article::find(5) → retourne un objet Article |
$article['title'] pour lire un champ |
$article->title pour lire une propriété typée |
| Pas de validation au niveau de la donnée | Le constructeur garantit les types corrects |
| Fonctions éparpillées dans plusieurs fichiers | Tout le comportement d’un Article est dans Article.php |
$pdo = getPdo() répété partout |
$this->pdo disponible dans toutes les classes via Model |
La Classe de Base : Model
Avant de créer Article et User, nous créons une classe parent dont elles vont toutes les deux hériter.
<?php
require_once "database/database.php";
class Model
{
protected PDO $pdo;
public function __construct()
{
$this->pdo = getPdo();
}
}
Pourquoi Model est utile ?
- Elle centralise la connexion
getPdo()en un seul endroit. - Toute classe qui
extends Modelhérite automatiquement de$this->pdo. - Plus besoin d’écrire
$pdo = getPdo();dans chaque méthode.
Nouvelles fonctionnalités PHP 8.3+/8.4 utilisées
1. Constructor Property Promotion (PHP 8.0+, affiné en 8.4)
Au lieu d’écrire :
class Article extends Model {
public int $id;
public string $title;
public string $slug;
public function __construct(int $id, string $title, string $slug) {
parent::__construct(); // appel du constructeur de Model
$this->id = $id;
$this->title = $title;
$this->slug = $slug;
}
}
On écrit maintenant directement avec la promotion :
class Article extends Model {
public function __construct(
public readonly int $id,
public string $title,
public string $slug,
// ...
) {
parent::__construct(); // toujours appeler le parent pour avoir $this->pdo
}
}
2. readonly Properties (PHP 8.1+)
Les propriétés readonly ne peuvent être assignées qu’une seule fois (dans le constructeur). Parfait pour l’id qui ne doit jamais changer après la création de l’objet.
3. Typed Properties (PHP 8.0+)
Chaque propriété a un type strict (int, string, ?string). PHP lance une TypeError si on tente d’assigner un type incorrect.
4. Nullable types (?string)
On utilise ?string pour les propriétés optionnelles comme image (un article peut ne pas avoir d’image).
Architecture cible
app/
├── Models/
│ ├── Model.php ← Classe de base (connexion PDO partagée)
│ ├── Article.php ← extends Model — CRUD articles
│ ├── User.php ← extends Model — auth + profil
│ └── Comment.php ← extends Model — réactions des lecteurs
├── functions/ ← Conservé pour compatibilité Branche 3
│ ├── article.php
│ ├── user.php
│ └── comment.php
└── helpers.php
Diagramme de l’héritage
┌──────────────┐
│ Model │
│ $this->pdo │
└──────┬───────┘
│ extends
┌───────────┼───────────┐
│ │ │
┌─────▼─────┐ ┌───▼────┐ ┌───▼───────┐
│ Article │ │ User │ │ Comment │
│ + CRUD │ │ + auth │ │ + réact. │
└───────────┘ └────────┘ └───────────┘
Contenu des Classes
Model.php
Propriétés :
- protected $pdo ← instance PDO disponible dans toutes les sous-classes
Constructeur :
- __construct() ← appelle getPdo() et stocke la connexion
Article.php — extends Model
Propriétés (typées, readonly pour id) :
- readonly int $id
- string $title
- string $slug
- string $introduction
- string $content
- ?string $image
- string $created_at
- string $updated_at
- int $comment_count (calculé via sous-requête)
Méthodes statiques (factory methods) :
- Article::count() → int
- Article::find(int $id) → ?Article
- Article::findAll(?limit, ?offset, $search) → array<Article>
- Article::slugExists(string $slug) → bool
Méthodes d'instance (actions) :
- $article->save() → bool (INSERT si id=0, UPDATE sinon)
- $article->delete() → bool
- $article->isNew() → bool
User.php — extends Model
Propriétés (typées, readonly pour id) :
- readonly int $id
- string $username
- string $email
- string $password ← toujours stocké haché
- string $role
- string $created_at
Méthodes statiques :
- User::count() → int
- User::find(int $id) → ?User
- User::findByEmail(string) → ?User
- User::findByUsername(string) → ?User
- User::findByEmailOrUsername(string) → ?User
- User::allWithCommentCount() → array
Méthodes d'instance :
- $user->save() → bool
- $user->verifyPassword(string) → bool
- $user->hashPassword(string) → void (met à jour $this->password)
- $user->isAdmin() → bool
- $user->toSession() → void (écrit dans $_SESSION['auth'])
Comment.php — extends Model
Propriétés (typées, readonly pour id) :
- readonly int $id
- string $content
- int $article_id ← clé étrangère vers articles
- int $user_id ← clé étrangère vers users
- string $created_at
- string $username ← dénormalisé depuis la jointure users (lecture seule)
Méthodes statiques :
- Comment::count() → int
- Comment::find(int $id) → ?Comment
- Comment::findByArticle(int $article_id) → array<Comment> (avec username)
- Comment::findByUser(int $user_id) → array<Comment> (avec titre article)
Méthodes d'instance :
- $comment->save() → bool (INSERT uniquement, pas d'UPDATE)
- $comment->delete() → bool
- $comment->belongsTo(int $userId, bool $isAdmin) → bool (contrôle des droits)
Plan des fichiers de documentation
| Fichier | Contenu |
|---|---|
00_plan.md |
Ce plan — Vue d’ensemble de la Branche 4 |
01_introduction_classes.md |
POO vs Fonctions, héritage simple, vocabulaire |
02_class_model.md |
Code complet de Model.php expliqué pas à pas |
03_class_article.md |
Code complet de Article.php avec promotion PHP 8.4 |
04_class_user.md |
Code complet de User.php avec méthodes d’auth |
05_class_comment.md |
Code complet de Comment.php avec contrôle des droits |
06_usage_controleurs.md |
Migration des contrôleurs vers les nouvelles classes |
Étapes d’implémentation
- Créer
app/Models/Model.php— la base - Créer
app/Models/Article.php extends Model - Créer
app/Models/User.php extends Model - Créer
app/Models/Comment.php extends Model - Inclure les modèles dans
app/helpers.php - Migrer
index.php→Article::findAll() - Migrer les contrôleurs admin →
Article::find(),$article->save() - Migrer
login.php→User::findByEmailOrUsername(),$user->verifyPassword() - Migrer
register.php→Userinstancié +$user->save() - Migrer
user-comment-save.php+user-comment-delete.php→$comment->save(),$comment->delete()
Prêt à passer à la suite ?
Vous avez terminé cette leçon sur Branche 4 — Modèles PHP 8.4 : `Model`, `Article`, `User` et `Comment`. Continuez votre apprentissage avec la prochaine leçon ou explorez d'autres formations.