Aller au contenu principal

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 true pour autoriser la requête, false pour 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ègleExempleDescription
required'email' => 'required'Champ obligatoire
string, integer, numeric, arrayType de la valeur
email'email' => 'email'Format email
max:255, min:8Longueur 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
nullableAutorise null / absent
sometimesValide seulement si le champ est présent
required_if:autre,valeurObligatoire si un autre champ a une valeur donnée
required_with:champObligatoire si un autre champ est présent
in:val1,val2'role' => 'in:user,admin'Valeur dans une liste
regex:patternExpression 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

  1. Une Form Request par action sensible (StoreXxxRequest, UpdateXxxRequest) pour garder des règles claires.
  2. authorize() : y mettre la logique d’autorisation (Policy, Gate) pour éviter du code dans le contrôleur.
  3. validated() ou safe() : n’utiliser que ces données pour créer/mettre à jour les modèles (ne pas utiliser $request->all() sans filtre).
  4. 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).