Module 15 – Validation avancée & Form Requests
Niveau 4 – Laravel avancé (PRO)
Objectifs
Au programme :
- Créer et utiliser des Form Request pour centraliser la validation
- Personnaliser les messages d’erreur (langue, champs, règles)
- Mettre en œuvre une validation conditionnelle (sometimes, required_if, etc.)
- Garder les contrôleurs légers en déléguant la validation aux Form Requests
Théorie
Form Request : principe
Une Form Request est une classe dédiée à la validation (et éventuellement à l’autorisation) d’une requête HTTP. Au lieu de mettre $request->validate([...]) dans le contrôleur, on type-hinte la Form Request : Laravel valide avant d’entrer dans la méthode du contrôleur.
Création :
php artisan make:request StoreArticleRequest
php artisan make:request UpdateArticleRequest
Utilisation dans le contrôleur :
public function store(StoreArticleRequest $request)
{
$validated = $request->validated();
Article::create($validated);
return redirect()->route('articles.index');
}
Si la validation échoue, Laravel redirige (web) ou renvoie du JSON (API) avec les erreurs ; le code du contrôleur n’est pas exécuté.
Structure d’une Form Request
Fichier : app/Http/Requests/StoreArticleRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreArticleRequest extends FormRequest
{
public function authorize(): bool
{
return true; // ou : return $this->user()?->can('create', Article::class);
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'body' => ['required', 'string'],
'published_at' => ['nullable', 'date'],
];
}
}
- authorize() : retourne
truepour autoriser la requête,falsepour 403. On peut y appeler des Gates ou Policies. - rules() : tableau des règles de validation (même syntaxe que
$request->validate()).
Récupérer les données validées : $request->validated() retourne uniquement les champs présents dans rules().
Règles courantes
| Règle | Exemple | Description |
|---|---|---|
| required | 'email' => 'required' | Champ obligatoire |
| string, integer, numeric, array | Type de la valeur | |
'email' => 'email' | Format email | |
| max:255, min:8 | Longueur ou valeur max/min | |
| unique:table,col | 'email' => 'unique:users,email' | Unique dans la table (ex. pour inscription) |
| exists:table,col | 'user_id' => 'exists:users,id' | Clé étrangère existante |
| confirmed | 'password' => 'confirmed' | Champ + champ_confirmation |
| nullable | Autorise null / absent | |
| sometimes | Valide seulement si le champ est présent | |
| required_if:autre,valeur | Obligatoire si un autre champ a une valeur donnée | |
| required_with:champ | Obligatoire si un autre champ est présent | |
| in:val1,val2 | 'role' => 'in:user,admin' | Valeur dans une liste |
| regex:pattern | Expression régulière |
Exemple complet :
public function rules(): array
{
return [
'email' => ['required', 'email', 'unique:users,email'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'role' => ['required', 'in:user,admin'],
'website' => ['nullable', 'url'],
];
}
Messages personnalisés
Méthode messages() dans la Form Request :
public function messages(): array
{
return [
'title.required' => 'The article title is required.',
'title.max' => 'The title may not exceed :max characters.',
'email.unique' => 'This email is already in use.',
];
}
Les placeholders :attribute, :max, :min, etc. sont remplacés par Laravel.
Personnaliser les noms d’attributs (pour les messages par défaut) :
public function attributes(): array
{
return [
'published_at' => 'date de publication',
];
}
Fichiers de langue : on peut aussi définir les messages dans lang/fr/validation.php (clés validation.attribute.nom, validation.custom.champ.regle) pour une app multilingue.
Validation conditionnelle
sometimes : la règle ne s’applique que si le champ est présent dans la requête.
'website' => ['sometimes', 'url'],
required_if : obligatoire si un autre champ a une valeur donnée.
'entreprise' => ['required_if:type,pro'],
required_with : obligatoire si un autre champ est présent.
'password_confirm' => ['required_with:password', 'same:password'],
Rule::when() (PHP 8+) pour des conditions plus complexes :
use Illuminate\Validation\Rule;
'tarif' => [
Rule::when($this->type === 'premium', ['required', 'numeric', 'min:10']),
],
Exemple complet
StoreUserRequest.php :
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'unique:users,email'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'role' => ['required', 'in:user,admin'],
];
}
public function messages(): array
{
return [
'email.unique' => 'Un compte existe déjà avec cet email.',
'password.min' => 'Le mot de passe doit contenir au moins :min caractères.',
];
}
UserController.php :
public function store(StoreUserRequest $request)
{
User::create($request->safe()->merge([
'password' => Hash::make($request->validated('password')),
])->all());
return redirect()->route('users.index')->with('success', 'User created.');
}
$request->safe() retourne uniquement les données validées (sans les champs non déclarés dans les rules).
Bonnes pratiques
- Une Form Request par action sensible (StoreXxxRequest, UpdateXxxRequest) pour garder des règles claires.
- authorize() : y mettre la logique d’autorisation (Policy, Gate) pour éviter du code dans le contrôleur.
- validated() ou safe() : n’utiliser que ces données pour créer/mettre à jour les modèles (ne pas utiliser
$request->all()sans filtre). - Messages personnalisés pour une meilleure UX ; fichiers de langue si l’app est multilingue.
Quiz – Module 15
Q1. À quoi sert une Form Request ?
Q2. Où déclare-t-on les règles de validation dans une Form Request ?
Q3. Que retourne $request->validated() ?
Q4. Quelle règle utiliser pour exiger un champ « mot de passe » + « confirmation » identique ?
Q5. Comment rendre une règle applicable seulement si le champ est présent ?
Réponses
R1. À centraliser la validation (et éventuellement l’autorisation) d’une requête dans une classe dédiée, exécutée avant la méthode du contrôleur.
R2. Dans la méthode rules() qui retourne un tableau de règles par champ.
R3. Un tableau contenant uniquement les champs validés (ceux présents dans les rules).
R4. confirmed : Laravel attend un champ password et un champ password_confirmation avec la même valeur.
R5. Avec la règle sometimes : la règle ne s’applique que si le champ est présent dans la requête.
Suite
Module 16 – API REST avec Laravel (API resources, Sanctum, versioning, pagination, projet API complète).