Validation
Validation
Niang\Core\Validation\Validator : 29 règles, vérifiées une à une contre
Validator::applyRule() — pas contre une liste retapée de mémoire.
Valider depuis un contrôleur
Controller::validate() encapsule Validator::make(...)->validate() :
public function store(Request $request): Response
{
$data = $this->validate($request, [
'name' => 'required|string|min:2',
'email' => 'required|email',
'message' => 'required|string|min:10',
]);
// $data ne contient que les champs déclarés dans les règles.
}
Les règles d'un champ s'écrivent en chaîne séparée par |, ou en tableau
(['required', 'string', 'min:2']) — les deux formes sont équivalentes.
FormRequest : valider par injection
Une classe qui étend Niang\Core\Validation\FormRequest et déclare
rules() se valide toute seule dès qu'elle est type-hintée dans un contrôleur — le
Container la construit à partir de la requête courante, vérifie authorize() puis
valide rules() avant même d'entrer dans la méthode (voir
injection par réflexion) :
namespace App\Requests;
use Niang\Core\Validation\FormRequest;
class ContactRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|min:2',
'email' => 'required|email',
'message' => 'required|string|min:10',
];
}
}
public function store(ContactRequest $request): Response
{
$data = $request->validated(); // déjà validé, garanti au moment où on arrive ici
}
authorize() retourne true par défaut ; la surcharger et retourner
false lève une AuthorizationException (403) avant même la validation —
utile pour une FormRequest qui doit vérifier une permission en plus de la forme des données.
Ce qui se passe quand ça échoue
Une règle qui échoue lève une ValidationException, interceptée une seule fois par
Handler::render() (voir cycle de vie d'une
requête) — jamais à gérer manuellement dans le contrôleur :
- Si la requête attend du JSON (
Accept: application/json) : réponse422avec{"message": "...", "errors": {...}}. - Sinon : redirection vers le
Referer, avec les erreurs et la saisie précédente flashées en session — récupérables avecerrors('champ')etold('champ')dans la vue.
<input type="email" name="email" value="<?= e(old('email')) ?>">
<?= component('components/field-errors', ['field' => 'email']) ?>
Une seule erreur est retenue par champ (la première règle qui échoue), pour rester lisible.
Toutes les règles
| Règle | Vérifie | Exemple |
|---|---|---|
required | Présent et non vide (chaîne non blanche, tableau non vide). | 'name' => 'required' |
required_if:champ,valeur | Requis seulement si champ vaut valeur. | 'phone' => 'required_if:contact_method,phone' |
required_with:champ | Requis seulement si champ est rempli. | 'shipping_city' => 'required_with:shipping_address' |
required_without:champ | Requis seulement si champ est vide. | 'email' => 'required_without:phone' |
string | is_string(). | 'name' => 'string' |
numeric | is_numeric(). | 'price' => 'numeric' |
integer | FILTER_VALIDATE_INT. | 'quantity' => 'integer' |
boolean | Un booléen, ou 0/1/'0'/'1'/'true'/'false'. | 'accepted' => 'boolean' |
array | is_array(). | 'tags' => 'array' |
email | FILTER_VALIDATE_EMAIL. | 'email' => 'required|email' |
url | FILTER_VALIDATE_URL. | 'website' => 'url' |
date | strtotime() réussit. | 'birthdate' => 'date' |
date_format:format | Respecte exactement un format DateTime::createFromFormat(). | 'day' => 'date_format:Y-m-d' |
min:n | ≥ n (longueur de chaîne, valeur si numérique, taille en Ko pour un fichier). | 'password' => 'min:8' |
max:n | ≤ n (mêmes unités que min). | 'bio' => 'max:500' |
between:min,max | Compris entre les deux. | 'age' => 'between:18,99' |
in:a,b,c | Une des valeurs listées. | 'role' => 'in:admin,editor,viewer' |
not_in:a,b,c | Aucune des valeurs listées. | 'username' => 'not_in:admin,root' |
same:champ | Identique à un autre champ. | 'password_confirmation' => 'same:password' |
different:champ | Différent d'un autre champ. | 'new_password' => 'different:current_password' |
regex:motif | Correspond au motif PCRE (délimiteurs inclus). | 'code' => 'regex:/^[A-Z]{3}-\d{4}$/' |
confirmed | Un champ x_confirmation existe et lui est identique. | 'password' => 'required|confirmed' |
unique:table,colonne[,id,idColonne] | Aucune ligne existante avec cette valeur (le 3ᵉ paramètre ignore la ligne courante lors d'une modification). | 'email' => "unique:users,email,{$id},id" |
exists:table,colonne | Une ligne existe avec cette valeur (colonne par défaut id). | 'category_id' => 'exists:categories,id' |
file | Un fichier envoyé, arrivé sans erreur (voir Upload de fichiers). | 'cv' => 'required|file' |
image | Le contenu réel est une image JPEG, PNG, GIF, WebP ou AVIF (SVG exclu : il peut contenir du JavaScript). | 'avatar' => 'image|max:2048' |
mimes:ext,... | L'extension déduite du contenu (jamais du nom envoyé) est dans la liste. | 'cv' => 'mimes:pdf,docx' |
mimetypes:type,... | Le type MIME réel est dans la liste ; accepte un joker (image/*). | 'media' => 'mimetypes:image/*,video/mp4' |
dimensions:... | Largeur/hauteur d'une image : min_width, max_width, min_height, max_height, width, height. | 'banniere' => 'dimensions:min_width=1200,max_height=600' |
nullable n'est pas dans ce tableau : ce n'est pas une règle mais un modificateur
(géré par runRules(), avant la boucle) — placé avant les autres, il fait sauter
toutes les règles suivantes si le champ est vide, plutôt que de les faire échouer.
Messages et attributs personnalisés
Validator::make($data, [
'email' => 'required|email',
], [
'email.required' => 'Une adresse email est nécessaire pour vous recontacter.',
], [
'email' => 'Adresse email',
])->validate();
Le 3ᵉ argument (messages) accepte une clé 'champ.règle' (prioritaire)
ou juste 'règle' (s'applique à tous les champs). Le 4ᵉ (attributes)
remplace le nom du champ dans les messages par défaut, ex. « Le champ Adresse email est requis. »
plutôt que « Le champ email est requis. ».
Les messages par défaut viennent de lang/<langue>/validation.php, livré en
français et en anglais (APP_LOCALE) : modifiez-y un message pour tout le projet, ou
donnez un libellé à un champ dans sa section attributes — voir
Langues.
Valider un tableau (règles items.*)
Une clé contenant .* applique ses règles à chaque élément d'un tableau :
Validator::make($data, [
'items' => 'required|array',
'items.*.name' => 'required|string',
'items.*.quantity' => 'required|integer|min:1',
])->validate();
Chaque erreur est indexée par position : items.0.name, items.1.quantity,
etc. — récupérables individuellement avec errors('items.0.name').