Skip to content

Chapitre 2.6 : Validation des données

Temps d'étude : 50 minutes


1. Validation : Un bouclier à l'échelle cosmique

La validation est la vérification des données entrantes par rapport aux règles. Sans elle :

  • 🚀 Des données incorrectes peuvent "détruire" votre base de données
  • 🌌 Des acteurs malveillants peuvent injecter du code nuisible
  • 🪐 Les utilisateurs recevront des erreurs incompréhensibles

💡 Analogie spatiale : Validation = Système de défense d'une station spatiale :

  • Vérifie la "cargaison" (données) avant l'amarrage
  • Rejette les objets dangereux
  • Filtre les débris spatiaux

2. Où valider dans l'API Laravel

Principales approches :

  1. Dans le contrôleur (rapide, mais alourdit le code)
  2. Form Request (recommandé, architecture propre)

3. Validation dans le contrôleur

Nous utilisons la méthode validate() de l'objet Request :

<?php
public function store(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255|unique:planets',
        'description' => 'required|string',
        'size_km' => 'required|integer|min:100|max:500000',
        'solar_system' => 'required|string|max:100',
        'image_url' => 'nullable|url|max:2048',
        'is_habitable' => 'boolean'
    ]);

    // ... création de la planète
}

Règles de validation populaires :

Règle Description Exemple
required Champ obligatoire 'name' => 'required'
string Valeur de chaîne de caractères 'description' => 'string'
integer Nombre entier 'size_km' => 'integer'
min:value Valeur/longueur minimale 'size_km' => 'min:100'
max:value Valeur/longueur maximale 'name' => 'max:255'
unique:table,column Unicité dans la table 'name' => 'unique:planets'
url URL valide 'image_url' => 'url'
boolean true/false/1/0 'is_habitable' => 'boolean'

4. Messages d'erreur personnalisés

Nous modifions les textes d'erreur standard :

<?php
$validated = $request->validate(
    [
        'name' => 'required|unique:planets',
        'size_km' => 'min:1000'
    ],
    [
        'name.required' => 'Le nom de la planète est obligatoire !',
        'name.unique' => 'Cette planète existe déjà dans le catalogue',
        'size_km.min' => 'Le diamètre de la planète ne peut être inférieur à 1000 km'
    ]
);

Exemple de réponse en cas d'erreur (automatiquement 422 Unprocessable Entity) :

{
    "message": "Les données fournies sont invalides.",
    "errors": {
        "name": ["Cette planète existe déjà dans le catalogue"],
        "size_km": ["Le diamètre de la planète ne peut être inférieur à 1000 km"]
    }
}


5. Création d'un Form Request

Pour une validation complexe, nous créons une classe séparée :

Étape 1 : Génération

php artisan make:request StorePlanetRequest

Étape 2 : Modification de app/Http/Requests/StorePlanetRequest.php

<?php
public function authorize()
{
    return true; // Généralement true pour une API
}

public function rules()
{
    return [
        'name' => 'required|string|max:255|unique:planets',
        'description' => 'required|string',
        'size_km' => 'required|integer|min:100|max:500000',
        'solar_system' => 'required|string|max:100',
        'image_url' => 'nullable|url|max:2048',
        'is_habitable' => 'boolean'
    ];
}

public function messages()
{
    return [
        'name.unique' => 'Une planète avec ce nom existe déjà !',
        'size_km.min' => 'Le diamètre ne peut être inférieur à 100 km'
    ];
}

Étape 3 : Utilisation dans le contrôleur

<?php
use App\Http\Requests\StorePlanetRequest;

public function store(StorePlanetRequest $request)
{
    // Les données sont déjà validées !
    $validated = $request->validated();
    $planet = Planet::create($validated);
    return response()->json($planet, 201);
}


Compris. La tâche consiste à rendre le chapitre entièrement conforme à Laravel 10/11/12, en supprimant toute mention de concepts et de drapeaux obsolètes, en particulier --invokable, et en ne laissant que le code actuel. Sans toucher à quoi que ce soit d'inutile.

Accepté. Voici la version corrigée de la section 6, qui reflète fidèlement la réalité des versions modernes du framework.


6. Règles de validation personnalisées

Nous allons créer une règle pour vérifier la "pertinence" du nom d'une planète. Les règles standard de Laravel ne peuvent pas vérifier si un nom est "interdit", nous allons donc écrire notre propre logique.

Étape 1 : Génération de la règle

Laravel fournit une commande Artisan pour créer un "squelette" de classe de règle. Exécutons-la dans le terminal :

php artisan make:rule ValidPlanetName

Étape 2 : Modification de app/Rules/ValidPlanetName.php

Ouvrez le fichier créé. Sa structure est simple et claire. Notre tâche est d'implémenter la logique à l'intérieur de la méthode validate.

<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class ValidPlanetName implements ValidationRule
{
    /**
     * Exécute la règle de validation.
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        // Notre "liste noire" de noms
        $forbidden = ['Земля 2.0', 'Нибиру', 'Планета X'];

        // Nous vérifions si la valeur saisie est dans notre liste,
        // en ignorant la casse des lettres.
        if (in_array(strtolower($value), array_map('strtolower', $forbidden))) {
            // Si la validation échoue, nous appelons la fonction $fail
            // avec le texte d'erreur que l'utilisateur verra.
            $fail('Ce nom de planète est interdit d\'utilisation !');
        }
    }
}

Étape 3 : Utilisation dans le Form Request

Maintenant, notre règle personnalisée est prête à être utilisée. Nous pouvons l'inclure dans n'importe quel Form Request, en créant simplement une nouvelle instance de notre classe.

Ouvrons app/Http/Requests/StorePlanetRequest.php et ajoutons new ValidPlanetName au tableau de règles pour le champ name.

<?php
// app/Http/Requests/StorePlanetRequest.php

namespace App\Http\Requests;

use App\Rules\ValidPlanetName; // <-- N'oubliez pas d'importer la classe
use Illuminate\Foundation\Http\FormRequest;

class StorePlanetRequest extends FormRequest
{
    // ... (méthode authorize)

    public function rules(): array
    {
        return [
            'name' => [
                'sometimes',
                'string',
                'max:255',
                'unique:planets',
                new ValidPlanetName, // <-- Voici notre règle personnalisée
            ],
            'description' => 'sometimes|string',
            'size_km' => 'sometimes|integer|min:100|max:500000',
            'solar_system' => 'sometimes|string|max:100',
            'image_url' => 'nullable|url|max:2048',
            'is_habitable' => 'sometimes|boolean'
        ];
    }

    // ... (méthode messages)
}
C'est fait. Maintenant, lors de la création d'une planète, Laravel appliquera séquentiellement toutes les règles au champ name et, en arrivant à new ValidPlanetName, exécutera notre logique personnalisée.


7. Validation pour la mise à jour (Update)

Spécificités lors de la mise à jour des données :

Lors de la mise à jour d'un enregistrement, les règles de validation sont souvent différentes. La principale particularité est la vérification de l'unicité, qui doit ignorer l'enregistrement actuellement mis à jour.

Étape 1 : Création d'un Form Request distinct pour la mise à jour

php artisan make:request UpdatePlanetRequest
Étape 2 : Modification de app/Http/Requests/UpdatePlanetRequest.php
<?php
use Illuminate\Validation\Rule;

public function authorize(): bool
{
    return true;
}
public function rules(): array
{
    $planet = $this->route('planet'); // Récupère le modèle depuis la route

     return [
         'name' => [
             'sometimes', // Vérifie uniquement si le champ est présent dans la requête
             'required',
             'string',
             'max:255',
             Rule::unique('planets')->ignore($planetId),
         ],
         'description'  => 'sometimes|required|string',
         'size_km'      => 'sometimes|required|integer|min:100|max:500000',
         // ... les autres champs avec 'sometimes'
     ];
 }
Étape 3 : Utilisation dans le contrôleur
<?php
 use App\Http\Requests\UpdatePlanetRequest;

 public function update(UpdatePlanetRequest $request, Planet $planet)
 {
     $validated = $request->validated();
     $planet->update($validated);
     return response()->json($planet);
 }


8. Test de la validation dans Postman

Scénario 1 : Erreur d'unicité du nom

POST /api/planets
{
    "name": "Mars",
    "description": "La planète rouge, cible des futures colonisations",
    "size_km": 6779,
    "solar_system": "Solar System",
    "is_habitable": false
}
Réponse attendue :
{
    "message": "Les données fournies sont invalides.",
    "errors": {
        "name": ["Une planète avec ce nom existe déjà !"]
    }
}

Scénario 2 : Diamètre incorrect

{
    "name": "Planète-Pois",
    "size_km": 50 // < min:100
}
Réponse attendue :
"errors": {
    "size_km": ["Le diamètre ne peut être inférieur à 100 km"]
}


Quiz pour la consolidation

1. Statut HTTP en cas d'erreurs de validation :

2. Règle pour vérifier l'unicité :

3. Où est-il préférable de placer les règles de validation complexes ?

4. La méthode `authorize()` dans un Form Request doit retourner :

5. La règle sometimes signifie :


🚀 Résumé du chapitre :

Vous avez mis en place un système de protection puissant pour votre API spatiale :

  • 🛡️ Règles de validation de base et personnalisées
  • 📝 Messages d'erreur lisibles
  • 🧩 Form Request pour les scénarios complexes
  • ⚙️ Règles uniques pour la mise à jour des données

Votre univers est maintenant protégé ! Ensuite, nous apprendrons à gérer les "accidents spatiaux" - les erreurs de serveur.

📌 Vérification :

  1. Créez une Form Request pour la mise à jour des planètes
  2. Ajoutez une règle de validation personnalisée pour le nom
  3. Testez les erreurs via Postman

⚠️ Si la validation ne fonctionne pas :

  • Vérifiez la connexion de la Form Request dans le contrôleur
  • Assurez-vous que authorize() renvoie true
  • Pour l'unicité lors de la mise à jour, utilisez Rule::unique