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.

Tutorial Laravel 11 pour créer une application complète

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
<?php
// database/migrations/2026_01_14_000000_create_tasks_table.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

// Migration pour créer la table des tâches
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('tasks', function (Blueprint $table) {
            // Clé primaire auto-incrémentée
            $table->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
<?php
// app/Models/Task.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;

class Task extends Model
{
    // Traits pour les fonctionnalités avancées
    use HasFactory, SoftDeletes;

    // Attributs mass-assignables
    protected $fillable = [
        'user_id',
        'title',
        'description',
        'status',
        'priority',
        'due_date',
        'completed_at',
    ];

    // Casting automatique des attributs
    protected function casts(): array
    {
        return [
            'due_date' => '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
<?php
// app/Models/User.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected function casts(): array
    {
        return [
            'email_verified_at' => '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();
    }
}

Prêt à réussir tes entretiens Laravel ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

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
<?php
// app/Http/Controllers/TaskController.php

namespace App\Http\Controllers;

use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Support\Facades\Gate;

class TaskController extends Controller
{
    // Liste des tâches de l'utilisateur connecté
    public function index(Request $request): View
    {
        // Récupération des tâches avec filtrage optionnel
        $tasks = $request->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
<?php
// routes/web.php

use App\Http\Controllers\TaskController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

// Page d'accueil publique
Route::get('/', function () {
    return view('welcome');
});

// Routes protégées par authentification
Route::middleware(['auth', 'verified'])->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
<?php
// app/Policies/TaskPolicy.php

namespace App\Policies;

use App\Models\Task;
use App\Models\User;

class TaskPolicy
{
    // Vérification avant toutes les méthodes
    // Retourner true bypass toutes les vérifications (admin)
    public function before(User $user, string $ability): ?bool
    {
        if ($user->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
<?php
// app/Http/Controllers/Api/TaskController.php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\TaskResource;
use App\Http\Resources\TaskCollection;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

class TaskController extends Controller
{
    // Liste paginée des tâches
    public function index(Request $request): AnonymousResourceCollection
    {
        $tasks = $request->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
<?php
// app/Http/Resources/TaskResource.php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class TaskResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $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
<?php
// routes/api.php

use App\Http\Controllers\Api\TaskController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

// Route pour récupérer l'utilisateur authentifié
Route::get('/user', function (Request $request) {
    return $request->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
<?php
// tests/Feature/TaskTest.php

use App\Models\Task;
use App\Models\User;

// Test : un utilisateur peut voir ses tâches
test('user can view their tasks', function () {
    $user = User::factory()->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

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

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.

Tags

#laravel
#php
#api rest
#eloquent
#tutorial

Partager

Articles similaires