backend / php-laravel
Routing Laravel
Explication
Ce que vous allez apprendre
- Déclarer des routes pour chaque verbe HTTP et leur donner un nom explicite
- Contraindre et rendre optionnels des paramètres de route
- Comprendre le route model binding, qui injecte directement un modèle Eloquent depuis l'URL
- Regrouper des routes par préfixe, middleware et nom pour éviter la répétition
- Générer des routes CRUD complètes en une seule ligne avec
Route::resource
Dans quel contexte ?
Un développeur construit une boutique en ligne avec un espace d'administration protégé. Il doit exposer des URLs publiques (/produits/{id}) et des URLs réservées aux admins (/admin/commandes), sans dupliquer dix fois le même middleware d'authentification sur chaque route. Le système de routing de Laravel, avec ses groupes et ses conventions, rend cette organisation naturelle plutôt que fastidieuse.
D'abord, une route, c'est quoi concrètement ?
Une route associe une URL et un verbe HTTP (GET, POST...) à un morceau de code à exécuter — soit une closure directe, soit une méthode de contrôleur. Route::get('/produits', [ProduitController::class, 'index']) dit : "quand quelqu'un visite /produits en GET, exécute la méthode index du contrôleur ProduitController".
Nommer systématiquement chaque route avec ->name('produits.index') est une habitude à prendre dès le début : elle permet de générer des URLs par leur nom plutôt qu'en dur, ce qui évite de tout casser si le chemin change plus tard.
Ensuite, comment récupérer des informations depuis l'URL elle-même
Un segment comme {id} capture une partie dynamique de l'URL. On peut le contraindre avec ->where('id', '[0-9]+') pour n'accepter que des chiffres, ou le rendre optionnel avec {slug?}.
Prérequis
Cette leçon suppose que le projet Laravel de base (leçon précédente) est en place, avec au moins un contrôleur généré via artisan make:controller.
Il reste une astuce puissante : le route model binding
Plutôt que de récupérer un id brut puis d'aller chercher le modèle correspondant en base manuellement, Laravel peut le faire automatiquement. Si la route est /produits/{produit} et que le contrôleur attend show(Produit $produit), Laravel résout lui-même l'instance Eloquent correspondante — et renvoie une erreur 404 automatique si l'identifiant n'existe pas.
Astuce
Le route model binding fonctionne aussi avec des colonnes autres que l'id, comme un slug, en le configurant sur le modèle (getRouteKeyName()). Très utile pour des URLs lisibles comme /produits/clavier-mecanique plutôt que /produits/42.
Maintenant, éviter la répétition sur des groupes de routes
Regrouper des routes partageant un middleware, un préfixe d'URL et un préfixe de nom (Route::middleware(...)->prefix('admin')->name('admin.')->group(...)) évite d'écrire trois fois la même configuration sur chaque route individuelle. C'est indispensable dès qu'un espace d'administration comporte plus de deux ou trois pages protégées.
| Élément du groupe | Effet |
|---|---|
middleware([...]) | Applique un ou plusieurs middlewares à toutes les routes du groupe |
prefix('admin') | Ajoute /admin devant chaque URL du groupe |
name('admin.') | Préfixe le nom de chaque route (ex: admin.dashboard) |
Enfin, le raccourci qui génère un CRUD entier
Route::resource('commandes', CommandeController::class) génère automatiquement les 7 routes RESTful standard (index, create, store, show, edit, update, destroy) en une seule ligne. Route::apiResource, en variante, retire create et edit, deux routes inutiles pour une API sans formulaires HTML.
Piège fréquent
Écrire des chemins en dur dans les vues ou contrôleurs (href="/produits/42") plutôt que d'utiliser route('produits.show', 42) rend le code fragile : le moindre changement de structure d'URL oblige à chercher toutes les occurrences codées en dur dans le projet.
Maintenant que tu sais router une requête vers le bon code, la prochaine leçon détaille précisément ce qui se passe dans ce code : comment un contrôleur lit et valide une requête HTTP entrante.
Commandes & code
Routing Laravel
<?php
// routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProduitController;
use App\Http\Controllers\CommandeController;
// Routes de base par verbe HTTP
Route::get('/', fn () => view('accueil'));
Route::get('/produits', [ProduitController::class, 'index'])->name('produits.index');
Route::post('/produits', [ProduitController::class, 'store'])->name('produits.store');
// Paramètres de route, avec contrainte regex
Route::get('/produits/{id}', [ProduitController::class, 'show'])
->where('id', '[0-9]+')
->name('produits.show');
// Paramètre optionnel avec valeur par défaut
Route::get('/produits/categorie/{slug?}', [ProduitController::class, 'parCategorie']);
// Route model binding : {produit} résout automatiquement le modèle Eloquent via son id
Route::get('/produits/{produit}/avis', [ProduitController::class, 'avis']);
// -> nécessite public function avis(Produit $produit) dans le contrôleur
// Groupes de routes : préfixe, middleware et namespace communs
Route::middleware(['auth', 'verified'])
->prefix('admin')
->name('admin.')
->group(function () {
Route::get('/tableau-de-bord', fn () => view('admin.dashboard'))->name('dashboard');
Route::resource('commandes', CommandeController::class); // CRUD complet en une ligne
});
// Route::resource génère automatiquement 7 routes RESTful :
// GET /commandes -> index
// GET /commandes/create -> create
// POST /commandes -> store
// GET /commandes/{id} -> show
// GET /commandes/{id}/edit -> edit
// PUT/PATCH /commandes/{id} -> update
// DELETE /commandes/{id} -> destroy
// Routes API (routes/api.php) : préfixées /api, stateless, throttle par défaut
Route::middleware('throttle:api')->group(function () {
Route::apiResource('produits', ProduitController::class); // sans create/edit (pas de vues)
});
// Génération d'URL nommées (à préférer aux chemins en dur dans les vues/contrôleurs)
$url = route('produits.show', ['produit' => 42]); // /produits/42php artisan route:list --path=produits # inspecter les routes enregistrées, filtréesRésumé
Route::resourcegénère les 7 routes CRUD standard ;apiResourceen retire 2 (create/edit).- Le route model binding injecte directement l'instance Eloquent au lieu de l'id brut.
route('nom', [...])génère des URLs à partir du nom de route, jamais en dur.- Les groupes (
middleware,prefix,name) évitent la répétition sur des ensembles de routes.
Exercices pratiques
Mission : securiser et nommer les routes d'un espace admin
Objectif : Reorganiser des routes dupliquees et non protegees en un groupe coherent avec middleware, prefixe et route model binding.
Contexte
Le fichier routes/web.php d'une boutique en ligne contient dix routes commencant toutes par /admin/, chacune avec son propre ->middleware(['auth', 'verified']) repete individuellement. L'une d'elles, Route::get('/admin/commandes/{id}', ...), recupere manuellement l'id puis fait Commande::find($id) dans le controleur, avec un if (!$commande) abort(404); recopie a la main a chaque methode du controleur.