# Laravel 11 : Créer une application complète de A à Z > Guide complet pour créer une application Laravel 11 avec authentification, API REST, Eloquent ORM et déploiement. Tutorial pratique pour débutants et intermédiaires. - Published: 2026-01-14 - Updated: 2026-03-28 - Author: SharpSkill - Tags: laravel, php, api rest, eloquent, tutorial - Reading time: 15 min --- Laravel 11 redéfinit le développement PHP moderne avec une architecture simplifiée et des performances optimisées. Cette version majeure supprime de nombreux fichiers de configuration par défaut, introduit une structure allégée et améliore significativement l'expérience développeur. Ce guide accompagne la création d'une application complète de gestion de tâches, de l'installation au déploiement. > **Nouveautés Laravel 11** > > Laravel 11 adopte une structure minimaliste : plus de fichiers Kernel, configuration consolidée dans bootstrap/app.php, et un dossier app/ épuré. Le framework requiert PHP 8.2 minimum et intègre nativement SQLite pour un démarrage rapide. ## Installation et configuration du projet Laravel 11 s'installe via Composer ou l'installateur Laravel. La nouvelle structure du projet est plus légère, avec moins de fichiers de configuration à gérer dès le départ. ```bash # terminal # Installation de l'installateur Laravel (recommandé) composer global require laravel/installer # Création d'un nouveau projet Laravel 11 laravel new task-manager # Ou directement avec Composer composer create-project laravel/laravel task-manager # Navigation vers le projet cd task-manager ``` L'installateur propose plusieurs options interactives : choix du starter kit (Breeze, Jetstream), du système de test (Pest, PHPUnit) et de la base de données. ```bash # terminal # Lancement du serveur de développement php artisan serve # Le serveur démarre sur http://localhost:8000 ``` ### Configuration de la base de données Laravel 11 utilise SQLite par défaut, idéal pour le développement. Pour une application de production, la configuration vers MySQL ou PostgreSQL se fait dans le fichier `.env`. ```env # .env # Configuration pour MySQL DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=task_manager DB_USERNAME=root DB_PASSWORD=secret # Configuration pour PostgreSQL (alternative) # DB_CONNECTION=pgsql # DB_HOST=127.0.0.1 # DB_PORT=5432 # DB_DATABASE=task_manager # DB_USERNAME=postgres # DB_PASSWORD=secret ``` La connexion à la base de données se vérifie avec une commande Artisan. ```bash # terminal # Vérification de la connexion à la base de données php artisan db:show # Exécution des migrations par défaut php artisan migrate ``` ## Création du modèle et des migrations Eloquent ORM simplifie la manipulation des données avec des modèles expressifs. La commande `make:model` génère le modèle, la migration, le contrôleur et la factory en une seule fois. ```bash # terminal # Génération du modèle Task avec migration, factory, seeder et contrôleur php artisan make:model Task -mfsc # -m : migration # -f : factory # -s : seeder # -c : controller ``` Cette commande crée quatre fichiers essentiels pour une gestion complète des tâches. ```php id(); // Relation avec l'utilisateur propriétaire $table->foreignId('user_id')->constrained()->cascadeOnDelete(); // Titre de la tâche (obligatoire) $table->string('title'); // Description détaillée (optionnelle) $table->text('description')->nullable(); // Statut : pending, in_progress, completed $table->string('status')->default('pending'); // Priorité : low, medium, high $table->string('priority')->default('medium'); // Date d'échéance (optionnelle) $table->date('due_date')->nullable(); // Marqueur de complétion $table->timestamp('completed_at')->nullable(); // Timestamps automatiques (created_at, updated_at) $table->timestamps(); // Soft deletes pour la corbeille $table->softDeletes(); // Index pour optimiser les requêtes fréquentes $table->index(['user_id', 'status']); $table->index('due_date'); }); } public function down(): void { Schema::dropIfExists('tasks'); } }; ``` La migration définit la structure de la table avec des relations, des index et le soft delete pour ne jamais perdre de données accidentellement. ```php 'date', 'completed_at' => 'datetime', ]; } // Constantes pour les statuts valides public const STATUS_PENDING = 'pending'; public const STATUS_IN_PROGRESS = 'in_progress'; public const STATUS_COMPLETED = 'completed'; // Constantes pour les priorités public const PRIORITY_LOW = 'low'; public const PRIORITY_MEDIUM = 'medium'; public const PRIORITY_HIGH = 'high'; // Relation : une tâche appartient à un utilisateur public function user(): BelongsTo { return $this->belongsTo(User::class); } // Scope : tâches en attente public function scopePending(Builder $query): Builder { return $query->where('status', self::STATUS_PENDING); } // Scope : tâches en cours public function scopeInProgress(Builder $query): Builder { return $query->where('status', self::STATUS_IN_PROGRESS); } // Scope : tâches terminées public function scopeCompleted(Builder $query): Builder { return $query->where('status', self::STATUS_COMPLETED); } // Scope : tâches en retard public function scopeOverdue(Builder $query): Builder { return $query->where('due_date', '<', now()) ->whereNull('completed_at'); } // Scope : tâches d'un utilisateur public function scopeForUser(Builder $query, int $userId): Builder { return $query->where('user_id', $userId); } // Accesseur : vérifie si la tâche est en retard public function getIsOverdueAttribute(): bool { return $this->due_date && $this->due_date->isPast() && !$this->completed_at; } // Méthode : marquer comme terminée public function markAsCompleted(): void { $this->update([ 'status' => self::STATUS_COMPLETED, 'completed_at' => now(), ]); } } ``` Le modèle Task utilise les scopes Eloquent pour des requêtes lisibles et réutilisables. Les constantes centralisent les valeurs valides pour les statuts et priorités. > **Soft Deletes** > > Le trait SoftDeletes ajoute une colonne deleted_at. Les tâches supprimées ne disparaissent pas de la base de données mais sont marquées comme supprimées. Utilisez withTrashed() pour les inclure dans les requêtes. ## Configuration de l'authentification avec Breeze Laravel Breeze fournit une authentification complète avec des vues Blade ou une API. L'installation prend quelques minutes et génère tout le nécessaire : routes, contrôleurs, vues et tests. ```bash # terminal # Installation de Laravel Breeze composer require laravel/breeze --dev # Installation du stack Blade (traditionnel) php artisan breeze:install blade # Ou pour une API uniquement (SPA/mobile) php artisan breeze:install api # Compilation des assets npm install && npm run build # Exécution des migrations (tables users, sessions, etc.) php artisan migrate ``` Breeze génère les routes d'authentification, les contrôleurs et les vues pour inscription, connexion, réinitialisation de mot de passe et vérification d'email. ```php 'datetime', 'password' => 'hashed', ]; } // Relation : un utilisateur possède plusieurs tâches public function tasks(): HasMany { return $this->hasMany(Task::class); } // Raccourci : tâches en attente de l'utilisateur public function pendingTasks(): HasMany { return $this->tasks()->pending(); } // Raccourci : tâches en retard de l'utilisateur public function overdueTasks(): HasMany { return $this->tasks()->overdue(); } } ``` ## Création du contrôleur et des routes Le contrôleur orchestre la logique métier entre les requêtes HTTP et le modèle. Laravel 11 encourage les contrôleurs à action unique ou les ressources RESTful. ```php user() ->tasks() ->when($request->status, fn($q, $status) => $q->where('status', $status)) ->when($request->priority, fn($q, $priority) => $q->where('priority', $priority)) ->orderBy('due_date') ->orderBy('priority', 'desc') ->paginate(15); return view('tasks.index', compact('tasks')); } // Formulaire de création public function create(): View { return view('tasks.create'); } // Enregistrement d'une nouvelle tâche public function store(Request $request): RedirectResponse { // Validation des données entrantes $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:5000', 'priority' => 'required|in:low,medium,high', 'due_date' => 'nullable|date|after_or_equal:today', ]); // Création de la tâche liée à l'utilisateur $request->user()->tasks()->create($validated); return redirect() ->route('tasks.index') ->with('success', 'Tâche créée avec succès.'); } // Affichage d'une tâche public function show(Task $task): View { // Vérification que l'utilisateur est propriétaire Gate::authorize('view', $task); return view('tasks.show', compact('task')); } // Formulaire d'édition public function edit(Task $task): View { Gate::authorize('update', $task); return view('tasks.edit', compact('task')); } // Mise à jour d'une tâche public function update(Request $request, Task $task): RedirectResponse { Gate::authorize('update', $task); $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:5000', 'status' => 'required|in:pending,in_progress,completed', 'priority' => 'required|in:low,medium,high', 'due_date' => 'nullable|date', ]); // Mise à jour de completed_at si statut = completed if ($validated['status'] === Task::STATUS_COMPLETED && !$task->completed_at) { $validated['completed_at'] = now(); } $task->update($validated); return redirect() ->route('tasks.index') ->with('success', 'Tâche mise à jour.'); } // Suppression d'une tâche public function destroy(Task $task): RedirectResponse { Gate::authorize('delete', $task); $task->delete(); return redirect() ->route('tasks.index') ->with('success', 'Tâche supprimée.'); } // Marquer comme terminée (action rapide) public function complete(Task $task): RedirectResponse { Gate::authorize('update', $task); $task->markAsCompleted(); return back()->with('success', 'Tâche terminée !'); } } ``` Le contrôleur utilise les Gates pour l'autorisation, la validation intégrée et le route model binding pour un code concis et sécurisé. ### Définition des routes Les routes définissent les URLs et les associent aux actions du contrôleur. Laravel 11 centralise les routes dans `routes/web.php`. ```php group(function () { // Dashboard avec statistiques Route::get('/dashboard', function () { $user = auth()->user(); return view('dashboard', [ 'totalTasks' => $user->tasks()->count(), 'pendingTasks' => $user->tasks()->pending()->count(), 'completedTasks' => $user->tasks()->completed()->count(), 'overdueTasks' => $user->tasks()->overdue()->count(), ]); })->name('dashboard'); // Routes RESTful pour les tâches Route::resource('tasks', TaskController::class); // Action rapide pour compléter une tâche Route::patch('/tasks/{task}/complete', [TaskController::class, 'complete']) ->name('tasks.complete'); // Routes du profil (générées par Breeze) Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); }); // Routes d'authentification (générées par Breeze) require __DIR__.'/auth.php'; ``` La méthode `Route::resource()` génère automatiquement les sept routes RESTful standard : index, create, store, show, edit, update et destroy. ## Mise en place des policies d'autorisation Les policies centralisent la logique d'autorisation pour chaque modèle. Elles déterminent qui peut effectuer quelles actions sur les ressources. ```bash # terminal # Génération de la policy pour Task php artisan make:policy TaskPolicy --model=Task ``` ```php is_admin) { return true; } return null; // Continue vers les méthodes spécifiques } // Peut voir la liste des tâches public function viewAny(User $user): bool { return true; // Tout utilisateur authentifié } // Peut voir une tâche spécifique public function view(User $user, Task $task): bool { return $user->id === $task->user_id; } // Peut créer une tâche public function create(User $user): bool { return true; } // Peut modifier une tâche public function update(User $user, Task $task): bool { return $user->id === $task->user_id; } // Peut supprimer une tâche public function delete(User $user, Task $task): bool { return $user->id === $task->user_id; } // Peut restaurer une tâche supprimée (soft delete) public function restore(User $user, Task $task): bool { return $user->id === $task->user_id; } // Peut supprimer définitivement public function forceDelete(User $user, Task $task): bool { return $user->id === $task->user_id; } } ``` Laravel découvre automatiquement les policies grâce aux conventions de nommage. La policy `TaskPolicy` s'applique au modèle `Task`. > **Sécurité des policies** > > Les policies sont essentielles pour la sécurité. Sans elles, un utilisateur pourrait manipuler les URLs pour accéder aux tâches d'autres utilisateurs. Toujours vérifier la propriété des ressources. ## Création d'une API REST Laravel facilite la création d'APIs RESTful avec des routes dédiées, des ressources JSON et Sanctum pour l'authentification. ```bash # terminal # Installation de Sanctum (inclus par défaut depuis Laravel 11) php artisan install:api # Cette commande : # - Publie les migrations Sanctum # - Ajoute le trait HasApiTokens au modèle User # - Configure les routes API ``` ```php user() ->tasks() ->when($request->status, fn($q, $s) => $q->where('status', $s)) ->when($request->priority, fn($q, $p) => $q->where('priority', $p)) ->when($request->boolean('overdue'), fn($q) => $q->overdue()) ->latest() ->paginate($request->input('per_page', 15)); return TaskResource::collection($tasks); } // Création d'une tâche public function store(Request $request): JsonResponse { $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:5000', 'priority' => 'required|in:low,medium,high', 'due_date' => 'nullable|date|after_or_equal:today', ]); $task = $request->user()->tasks()->create($validated); return response()->json([ 'message' => 'Task created successfully.', 'data' => new TaskResource($task), ], 201); } // Affichage d'une tâche public function show(Task $task): TaskResource { $this->authorize('view', $task); return new TaskResource($task); } // Mise à jour d'une tâche public function update(Request $request, Task $task): TaskResource { $this->authorize('update', $task); $validated = $request->validate([ 'title' => 'sometimes|required|string|max:255', 'description' => 'nullable|string|max:5000', 'status' => 'sometimes|required|in:pending,in_progress,completed', 'priority' => 'sometimes|required|in:low,medium,high', 'due_date' => 'nullable|date', ]); if (isset($validated['status']) && $validated['status'] === Task::STATUS_COMPLETED && !$task->completed_at) { $validated['completed_at'] = now(); } $task->update($validated); return new TaskResource($task->fresh()); } // Suppression d'une tâche public function destroy(Task $task): JsonResponse { $this->authorize('delete', $task); $task->delete(); return response()->json([ 'message' => 'Task deleted successfully.', ]); } } ``` ### Ressources API pour la transformation des données Les ressources API transforment les modèles Eloquent en réponses JSON structurées, contrôlant précisément les données exposées. ```php $this->id, 'title' => $this->title, 'description' => $this->description, 'status' => $this->status, 'priority' => $this->priority, 'due_date' => $this->due_date?->format('Y-m-d'), 'is_overdue' => $this->is_overdue, 'completed_at' => $this->completed_at?->toISOString(), 'created_at' => $this->created_at->toISOString(), 'updated_at' => $this->updated_at->toISOString(), // Inclusion conditionnelle de l'utilisateur 'user' => $this->whenLoaded('user', fn() => [ 'id' => $this->user->id, 'name' => $this->user->name, ]), ]; } } ``` ### Routes API avec authentification Sanctum ```php user(); })->middleware('auth:sanctum'); // Routes API protégées par Sanctum Route::middleware('auth:sanctum')->group(function () { Route::apiResource('tasks', TaskController::class); // Statistiques du tableau de bord Route::get('/dashboard/stats', function (Request $request) { $user = $request->user(); return response()->json([ 'total' => $user->tasks()->count(), 'pending' => $user->tasks()->pending()->count(), 'in_progress' => $user->tasks()->inProgress()->count(), 'completed' => $user->tasks()->completed()->count(), 'overdue' => $user->tasks()->overdue()->count(), ]); }); }); ``` ## Tests automatisés avec Pest Laravel 11 intègre Pest PHP par défaut, un framework de test élégant et expressif. Les tests garantissent que l'application fonctionne correctement après chaque modification. ```php create(); $tasks = Task::factory()->count(5)->for($user)->create(); $response = $this->actingAs($user)->get('/tasks'); $response->assertOk(); $response->assertViewHas('tasks'); }); // Test : un utilisateur peut créer une tâche test('user can create a task', function () { $user = User::factory()->create(); $response = $this->actingAs($user)->post('/tasks', [ 'title' => 'Nouvelle tâche', 'description' => 'Description de la tâche', 'priority' => 'high', 'due_date' => now()->addDays(7)->format('Y-m-d'), ]); $response->assertRedirect('/tasks'); $this->assertDatabaseHas('tasks', [ 'user_id' => $user->id, 'title' => 'Nouvelle tâche', 'priority' => 'high', ]); }); // Test : validation requise pour le titre test('task title is required', function () { $user = User::factory()->create(); $response = $this->actingAs($user)->post('/tasks', [ 'title' => '', 'priority' => 'medium', ]); $response->assertSessionHasErrors('title'); }); // Test : un utilisateur ne peut pas voir les tâches d'un autre test('user cannot view another users task', function () { $user = User::factory()->create(); $otherUser = User::factory()->create(); $task = Task::factory()->for($otherUser)->create(); $response = $this->actingAs($user)->get("/tasks/{$task->id}"); $response->assertForbidden(); }); // Test : marquer une tâche comme terminée test('user can complete a task', function () { $user = User::factory()->create(); $task = Task::factory()->for($user)->create(['status' => 'pending']); $response = $this->actingAs($user)->patch("/tasks/{$task->id}/complete"); $response->assertRedirect(); $task->refresh(); expect($task->status)->toBe('completed'); expect($task->completed_at)->not->toBeNull(); }); // Test API : récupération des tâches test('api returns paginated tasks', function () { $user = User::factory()->create(); Task::factory()->count(20)->for($user)->create(); $response = $this->actingAs($user, 'sanctum') ->getJson('/api/tasks?per_page=10'); $response->assertOk() ->assertJsonCount(10, 'data') ->assertJsonStructure([ 'data' => [ '*' => ['id', 'title', 'status', 'priority', 'due_date'], ], 'links', 'meta', ]); }); ``` Exécution des tests avec Pest. ```bash # terminal # Exécution de tous les tests php artisan test # Tests avec couverture de code php artisan test --coverage # Tests d'un fichier spécifique php artisan test tests/Feature/TaskTest.php # Tests en parallèle (plus rapide) php artisan test --parallel ``` ## Optimisations pour la production Avant le déploiement, plusieurs optimisations améliorent les performances de l'application Laravel. ```bash # terminal # Cache de la configuration php artisan config:cache # Cache des routes php artisan route:cache # Cache des vues php artisan view:cache # Optimisation de l'autoloader Composer composer install --optimize-autoloader --no-dev # Génération du manifest des assets npm run build ``` ### Configuration du fichier .env pour la production ```env # .env.production APP_NAME="Task Manager" APP_ENV=production APP_DEBUG=false APP_URL=https://taskmanager.example.com # Cache et session via Redis (recommandé) CACHE_DRIVER=redis SESSION_DRIVER=redis QUEUE_CONNECTION=redis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 # Base de données DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_DATABASE=task_manager_prod DB_USERNAME=app_user DB_PASSWORD=strong_password_here # Mail MAIL_MAILER=smtp MAIL_HOST=smtp.mailgun.org MAIL_PORT=587 MAIL_USERNAME=postmaster@taskmanager.example.com MAIL_PASSWORD=secret MAIL_ENCRYPTION=tls ``` > **Variables sensibles** > > Ne jamais commiter le fichier .env dans le dépôt Git. Utilisez .env.example comme modèle et configurez les variables sensibles directement sur le serveur de production ou via des secrets managers. ## Conclusion Laravel 11 simplifie considérablement le développement PHP moderne avec sa structure allégée et ses conventions intelligentes. Ce guide a couvert les fondamentaux pour créer une application complète : modèles Eloquent, authentification, contrôleurs RESTful, policies d'autorisation, API avec Sanctum et tests automatisés. ### Checklist pour une application Laravel de qualité - ✅ Utiliser les migrations pour toutes les modifications de schéma - ✅ Implémenter des policies pour sécuriser l'accès aux ressources - ✅ Valider toutes les entrées utilisateur dans les contrôleurs - ✅ Utiliser les ressources API pour contrôler les données exposées - ✅ Écrire des tests pour les fonctionnalités critiques - ✅ Configurer le cache et les optimisations avant le déploiement - ✅ Sécuriser les variables d'environnement sensibles L'écosystème Laravel continue d'évoluer avec des packages comme Livewire pour les interfaces réactives, Horizon pour la gestion des queues, et Octane pour des performances exceptionnelles. La maîtrise de ces fondamentaux ouvre la porte à des applications PHP robustes et maintenables. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/fr/blog/laravel/laravel-11-creer-application-complete