Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🐘 Laravel – Framework PHP (Artisan, Eloquent & Blade)

Guide complet IDEO‑Lab sur le framework PHP (MVC, ORM, DI, Routage).

1.1 Facile

Vue d'ensemble

Framework PHP, MVC, "Batteries incluses".

PHP MVC Framework
1.2 Moyen

Architecture

Request Lifecycle, Service Container (DI), Facades.

Service Container Facades
1.3 Facile

Installation (Composer)

composer create-project, laravel new.

Composer php artisan
1.4 Facile

Installation (Sail)

Docker Desktop, sail up, sail artisan.

Sail Docker
1.5 Facile

Structure des dossiers

app/, routes/, resources/, public/, .env.

app/ routes/
2.1 Facile

Routage (routes/web.php)

Route::get, Route::post, Route::view.

Route::get Route::post
2.2 Moyen

ParamĂštres & Noms de Route

{id}, ->name(), Route Model Binding.

{id} name()
2.3 Facile

Controllers

make:controller, Resource Controllers.

Controller Route::resource
2.4 Moyen

Blade (Syntaxe)

{{{}}, {if, {foreach, {csrf.

Blade {{ $var }}
2.5 Moyen

Blade (Layouts)

{extends, {section, {yield, {include.

@extends @section
3.1 Moyen

Migrations & Seeders

make:migration, Schema::create, migrate.

migrate Schema
3.2 Moyen

Eloquent (ModĂšles)

make:model, $fillable, $hidden.

Eloquent Model
3.3 Moyen

Eloquent (Querying)

find, where, get, first, create, update.

ORM Query Builder
3.4 Avancé

Eloquent (Relations)

hasOne, hasMany, belongsTo, belongsToMany.

hasMany belongsTo
4.1 Moyen

Middleware

make:middleware, handle(), auth, guest.

Middleware Request
4.2 Moyen

Validation

$request->validate(), @error, Form Requests.

validate() Form Request
4.3 Avancé

Service Container (DI)

bind, singleton, Type-hinting (DI Auto).

DI bind
4.4 Avancé

Queues & Jobs (Files d'attente)

make:job, dispatch(), queue:work, Redis.

Queues Jobs
4.5 Moyen

Testing (PHPUnit / PEST)

make:test, Feature vs Unit, $this->get().

PHPUnit PEST
5.1 Moyen

Déploiement (Nginx)

Nginx (public/), PHP-FPM, artisan optimize.

Nginx PHP-FPM
6.1 Facile

Cheat-sheet artisan

make:, migrate, queue, tinker.

cheat artisan
1.1 Vue d'ensemble : Le Framework PHP "Batteries Incluses"
Le Framework Web pour les Artisans du Web

Laravel est un framework d'application web PHP open-source, basé sur l'architecture **MVC** (Model-View-Controller). Il est réputé pour sa **syntaxe élégante**, sa **simplicité d'utilisation** et son écosystÚme "batteries incluses" qui vise à rendre le développement agréable ("Developer Experience").

Il fournit des solutions robustes pour les tĂąches courantes :

  • Routage (simple et puissant)
  • Eloquent (ORM) : Un ORM (Object-Relational Mapper) magnifique et simple.
  • Blade (Moteur de template) : Simple mais puissant.
  • Authentification (Starter Kits : Breeze, Jetstream)
  • Files d'attente (Queues), TĂąches planifiĂ©es (Scheduler), WebSockets...
Laravel vs. Symfony vs. Django
CritĂšreLaravel (PHP)Symfony (PHP)Django (Python)
Philosophie"Batteries incluses", Opinionated."BoĂźte Ă  outils", Non-opinionated."Batteries incluses", Opinionated.
Courbe d'apprentissageFacile Ă  Moyenne.Difficile.Moyenne.
ComposantsUtilise beaucoup de composants Symfony.Base de nombreux frameworks (dont Laravel).Écosystùme Python (pip).
ORMEloquent (Active Record)Doctrine (Data Mapper)Django ORM (Active Record)
AdminExterne (ex: Nova, Filament)Externe (EasyAdmin)Intégré (auto-généré)
UsageStartups, PME, APIs, applications rapides.Grandes entreprises, projets trĂšs custom.Back-offices, APIs, projets data-centric.
1.2 Architecture : Service Container & Facades
Cycle de Vie d'une RequĂȘte (SimplifiĂ©)
[Image d'un cycle de vie Laravel]
1. RequĂȘte HTTP -> [Serveur Web (Nginx)]
   |
   ▌
2. [public/index.php] (Point d'entrée unique)
   |
   ▌
3. [Kernel HTTP] (Charge le Service Container)
   |
   ▌
4. [Middleware] (Session, Auth, CORS...)
   |
   ▌
5. [Router] (Lit 'routes/web.php')
   |
   ▌
6. [Controller] (Logique métier)
   |
   â–Œ (Demande des donnĂ©es)
7. [Model (Eloquent)] <-> [Base de Données]
   |
   â–Œ (Renvoie les donnĂ©es)
8. [View (Blade)] (GénÚre le HTML)
   |
   ▌
9. Réponse HTTP -> [Client]
Le Service Container (Le CƓur)

Le "Service Container" (ou "Conteneur d'Injection de DĂ©pendances") est le cƓur de Laravel. C'est une "boĂźte magique" qui gĂšre la crĂ©ation et l'injection des objets (Services, Classes...).

Principe (DI) : Au lieu de créer un objet ($obj = new MaClasse()), vous le "demandez" à Laravel (via type-hinting dans un constructeur) et le Container vous le fournit automatiquement.

class MonController {
  // 1. Demander le service (Type-hint)
  public function __construct(private PaymentService $payment) {
  }
  
  public function store(Request $request) {
    // 2. $this->payment est auto-injecté
    $this->payment->charge($request->amount);
  }
}
Facades (Les Raccourcis)

Les "Facades" sont une particularité de Laravel. Ce sont des "raccourcis" statiques pour appeler des services qui se trouvent dans le Service Container.

Syntaxe Facade (Statique)Syntaxe DI (Injectée)Ce que ça fait
Route::get(...)$router->get(...)Service de Routage
Cache::get('key')$cache->get('key')Service de Cache
DB::select(...)$db->select(...)Service de BDD

Pour les débutants : Les Facades sont simples et pratiques (Route::, Auth::, Cache::).
Pour les avancés : L'injection de dépendances (DI) est plus testable et plus propre (voir 4.3).

1.3 Installation (via Composer)
Prérequis (Stack AMP)

Vous avez besoin d'une stack PHP complĂšte (ex: WAMP, XAMPP, MAMP) ou d'une installation manuelle (Nginx/Apache + PHP + MariaDB) et de Composer (le "npm" de PHP).

# (Vérifier les prérequis)
php -v       # (PHP 8.1+ requis)
composer -v  # (Gestionnaire de paquets PHP)
1. composer create-project
# Crée un dossier 'mon_projet' avec Laravel
composer create-project laravel/laravel mon_projet
2. (Alternative) Installeur Laravel
# 1. Installer l'installeur (1 fois)
composer global require laravel/installer

# 2. Créer un projet (plus rapide)
laravel new mon_projet
3. Lancer le serveur de dev (artisan)
cd mon_projet
# Lancer le serveur (similaire Ă  'runserver' Django)
php artisan serve
# Serveur démarré sur http://127.0.0.1:8000
1.4 Installation (via Sail - Docker) (Recommandé)
Laravel Sail (Docker)

Sail est l'environnement de développement Docker officiel de Laravel. C'est la méthode la plus simple pour démarrer, car elle gÚre PHP, Nginx, MariaDB, Redis... pour vous.

Prérequis : Docker Desktop (Windows/macOS) ou Docker (Linux).

1. Installation (Linux/macOS)
# 1. Télécharge l'installeur (script bash)
curl -s "https://laravel.build/mon-projet-sail" | bash

# 2. Entrer dans le dossier
cd mon-projet-sail

# 3. Lancer les conteneurs (Nginx, PHP, MariaDB, Redis...)
./vendor/bin/sail up -d
2. Utiliser sail

sail est un alias pour docker compose exec ....

# Créer un alias (optionnel)
alias sail='./vendor/bin/sail'

# Exécuter 'php artisan migrate' (DANS le conteneur)
sail artisan migrate

# Lancer npm
sail npm install
sail npm run dev

# Lancer composer
sail composer require livewire/livewire

# ArrĂȘter les conteneurs
sail down

AccĂšs : http://localhost (Port 80).

1.5 Structure des dossiers (Laravel 11+)
Arborescence (Simplifiée)
mon_projet/
├── app/                  (Le CƓur)
│   ├── Http/
│   │   ├── Controllers/  (Contrîleurs)
│   │   └── Middleware/   (Middleware)
│   ├── Models/           (Eloquent ORM)
│   └── Providers/        (Service Providers)
│
├── bootstrap/            (Cache, DĂ©marrage)
├── config/               (Fichiers de config, ex: database.php)
├── database/
│   ├── migrations/       (Structure BDD)
│   └── seeders/          (DonnĂ©es de test)
│
├── public/               (Racine Web : index.php, assets)
│
├── resources/
│   ├── css/
│   ├── js/
│   └── views/            (Templates Blade)
│       └── welcome.blade.php
│
├── routes/
│   ├── web.php           (Routes Web)
│   └── api.php           (Routes API)
│
├── tests/                (Tests PHPUnit/PEST)
├── vendor/               (DĂ©pendances Composer)
├── .env                  (Variables d'environnement)
└── composer.json         (DĂ©pendances)
Le Fichier .env (Environnement)

C'est le fichier **le plus important** pour la configuration locale. Il surcharge les valeurs de config/.

# .env
APP_NAME="IDEO-Lab"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ideo_lab_db
DB_USERNAME=root
DB_PASSWORD=secret

# (Pour Sail, DB_HOST=mysql, DB_USERNAME=sail)

CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file

⚠ Ne jamais commiter (git) le fichier .env. Utiliser .env.example comme template.

2.1 CLI : php artisan (Le couteau suisse)
php artisan

artisan est l'équivalent de manage.py (Django) ou bin/console (Symfony). C'est votre outil pour tout faire.

Commandes de base
# Lister toutes les commandes
php artisan list

# Lancer le serveur de dev
php artisan serve

# Lancer le REPL (console)
php artisan tinker
Générateurs (make)
# Créer un Controller
php artisan make:controller ArticleController

# Créer un ModÚle
php artisan make:model Article

# Créer une Migration
php artisan make:migration create_articles_table

# Créer ModÚle + Migration + Factory + Seeder + Controller
php artisan make:model Article -mfs -c
Base de données (Migrations)
# Exécuter les migrations
php artisan migrate

# Annuler la derniĂšre migration
php artisan migrate:rollback

# Tout annuler et tout refaire (DEV)
php artisan migrate:fresh

# Lancer les Seeders (données de test)
php artisan db:seed
Cache & Optimisation (Prod)
# Mettre en cache la config (accélÚre)
php artisan config:cache

# Mettre en cache les routes (accélÚre)
php artisan route:cache

# Mettre tout en cache
php artisan optimize
2.2 Routage (routes/web.php)
routes/web.php (Pour le web)

Ce fichier gĂšre les routes "web" (avec sessions, cookies, CSRF).

Route::get (Closure)

Pour les routes simples, on peut utiliser une "Closure" (fonction anonyme).

use Illuminate\Http\Request;

// GET
Route::get('/', function () {
    return view('welcome'); // (Charge 'resources/views/welcome.blade.php')
});

// POST
Route::post('/contact', function (Request $request) {
    // $request->input('email') ...
    return redirect('/');
});
Route::get (Controller)

(Recommandé) Pour la logique complexe, on pointe vers une méthode de Controller.

use App\Http\Controllers\ArticleController;

// GET -> Méthode 'index'
Route::get('/articles', [ArticleController::class, 'index']);

// GET (ID) -> Méthode 'show'
Route::get('/articles/{id}', [ArticleController::class, 'show']);

// POST -> Méthode 'store'
Route::post('/articles', [ArticleController::class, 'store']);

// Route::put, Route::patch, Route::delete ...

// Groupe de routes
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', ...);
});
2.3 ParamĂštres & Noms de Route
ParamĂštres (Path & Query)
// Route: /users/{id}?search=test
Route::get('/users/{id}', [UserController::class, 'show']);

// Controller:
use Illuminate\Http\Request;

class UserController extends Controller {
    public function show(Request $request, string $id) {
        // 1. ParamĂštre de Path
        $userId = $id; // (ou $request->route('id'))
        
        // 2. ParamĂštre de Query
        $searchTerm = $request->input('search'); // "test"
        
        // 3. Contrainte (regex)
        // Route::get('/users/{id}', ...)->where('id', '[0-9]+');
    }
}
Noms de Route (->name())

Comme Django (name="home"), nommer les routes est une bonne pratique. Cela permet de les utiliser dans Blade sans hardcoder l'URL.

// routes/web.php
Route::get('/articles/{id}', [ArticleController::class, 'show'])
    ->name('articles.show');
Utilisation (Blade)
{-- (GénÚre l'URL: /articles/15) --}
<a href="{{ route('articles.show', ['id' => 15]) }}">
  Voir l'article
</a>
Route Model Binding (Implicite)

Une fonctionnalité "magique" de Laravel. Si le type-hint (Article $article) correspond au paramÚtre ({article}), Laravel va automatiquement chercher l'objet en BDD (Article::findOrFail($id)).

// routes/web.php
// (Le nom du paramĂštre '{article}' doit correspondre)
Route::get('/articles/{article}', [ArticleController::class, 'show']);

// ArticleController.php
use App\Models\Article;

class ArticleController extends Controller {
    // 1. Demander 'Article $article' (Type-hint)
    public function show(Article $article) {
        
        // 2. Pas besoin de 'find()'. Laravel l'a fait.
        //    Si non trouvé, renvoie 404 auto.
        
        return view('articles.show', ['article' => $article]);
    }
}
2.4 Blade (Syntaxe)
Moteur de template (.blade.php)

Blade est le moteur de template de Laravel. Il compile les fichiers .blade.php en PHP pur (trĂšs rapide).

Affichage (ÉchappĂ©)

(Équivalent de htmlspecialchars())

Bonjour, {{ $user->nom }}.
Affichage (Non-échappé)

⚠ (DANGEREUX - Risque XSS)

{!! $article->contenu_html !!}
Directives ({...)
{-- Conditionnel --}
{if ($user->isAdmin())
  <p>AccĂšs Admin</p>
{elseif ($user->isEditor())
  <p>AccĂšs Editeur</p>
{else
  <p>AccĂšs Visiteur</p>
{endif

{-- Boucles --}
{foreach ($articles as $article)
  <li>{{ $article->titre }}</li>
{endforeach

{-- Sécurité CSRF (Formulaires) --}
<form method="POST">
  {csrf
  ...
</form>
2.5 Blade (Layouts & Composants)
Héritage (resources/views/layout/app.blade.php)
<html>
<head>
  <title>IDEO-Lab - {yield('titre', 'Accueil')</title>
</head>
<body>
  {include('partials.nav')
  
  <div class="container">
    {yield('content')
  </div>
</body>
</html>
Page Enfant (resources/views/home.blade.php)
{-- 1. Étend le layout --}
{extends('layout.app')

{-- 2. Définit la section 'titre' --}
{section('titre', 'Ma Page d'Accueil')

{-- 3. Définit la section 'content' --}
{section('content')
  <h1>Bienvenue</h1>
  <p>Contenu de la page...</p>
{endsection
Composants Blade (Moderne)

Permet de créer des composants (similaires à React/Vue) sous forme de balises <x-...>.

Définition (resources/views/components/alert.blade.php)
{-- RécupÚre les 'props' --}
{props(['type' => 'info', 'message'])

<div class="alert alert-{{ $type }}">
  {{ $message }}
</div>
Utilisation
<!-- Syntaxe 'tag' -->
<x-alert type="error" message="Oups, une erreur !" />

<!-- Rendu HTML -->
<div class="alert alert-error">
  Oups, une erreur !
</div>
3.1 Migrations & Seeders
Migrations (Versionning BDD)

Une migration est un fichier PHP qui décrit une modification de la structure de votre BDD (créer/modifier une table, ajouter une colonne...).

# Crée un fichier dans 'database/migrations/'
php artisan make:migration create_articles_table
// ..._create_articles_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateArticlesTable extends Migration {
    public function up(): void {
        Schema::create('articles', function (Blueprint $table) {
            $table->id(); // (BigInt Unsigned Auto-Increment)
            $table->string('titre');
            $table->string('slug')->unique();
            $table->text('contenu')->nullable();
            $table->boolean('publie')->default(false);
            $table->foreignId('user_id')->constrained('users');
            $table->timestamps(); // (Ajoute created_at et updated_at)
        });
    }
    public function down(): void {
        Schema::dropIfExists('articles');
    }
}
Exécuter les Migrations
# (Configurer .env d'abord)
php artisan migrate
Seeders (Données de test)
php artisan make:seeder ArticleSeeder

// database/seeders/ArticleSeeder.php
use App\Models\Article;
use App\Models\User;

class ArticleSeeder extends Seeder {
    public function run(): void {
        Article::create([
            'user_id' => User::first()->id,
            'titre'   => 'Mon Premier Article',
            'slug'    => 'mon-premier-article',
            'contenu' => '...'
        ]);
    }
}

// (Appeler le Seeder depuis DatabaseSeeder.php)
// $this->call(ArticleSeeder::class);

// Lancer le seeding
php artisan db:seed
3.2 Eloquent ORM (ModĂšles)
Active Record

Eloquent est un ORM "Active Record". Chaque ModĂšle (classe) correspond Ă  une table. Chaque instance du modĂšle correspond Ă  une ligne.

php artisan make:model Article
// app/Models/Article.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model {
    
    // (Par défaut, table = 'articles')
    // protected $table = 'ma_table_custom';
    
    // (Par défaut, Clé primaire = 'id')
    // protected $primaryKey = 'article_id';
    
    // (Par défaut, 'created_at'/'updated_at' sont gérés)
    // public $timestamps = false;
    
    /**
     * (Mass Assignment) Champs autorisés
     * à l'écriture (ex: Article::create([...]))
     */
    protected $fillable = [
        'titre',
        'slug',
        'contenu',
        'user_id'
    ];

    /**
     * Champs à cacher lors de la sérialisation
     * (ex: en JSON pour une API)
     */
    protected $hidden = [
        'user_id'
    ];
}
Conventions (La "magie" de Laravel)

Eloquent repose sur des conventions fortes :

ObjetConvention
ModĂšleArticle (Singulier, PascalCase)
Table BDDarticles (Pluriel, snake_case)
Clé Primaireid
ClĂ© ÉtrangĂšrearticle_id (nom_modele_id)
3.3 Eloquent ORM (RequĂȘtes)
Lecture (SELECT)
use App\Models\Article;

// Récupérer tous
$articles = Article::all();

// Récupérer par ID
$article = Article::find(1);
$article = Article::findOrFail(1); // (Renvoie 404 si non trouvé)

// Query Builder (constructeur)
$articles_publies = Article::where('publie', true)
    ->where('titre', 'like', 'Mon%')
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->get(); // ExĂ©cute la requĂȘte

// Obtenir le premier
$premier = Article::where('publie', true)->first();
Écriture (INSERT, UPDATE, DELETE)
create (INSERT)
// (Utilise $fillable, cf 3.2)
$article = Article::create([
    'titre' => 'Nouveau Titre',
    'slug' => 'nouveau-titre',
    'user_id' => 1
]);
update (UPDATE)
$article = Article::findOrFail(1);
$article->titre = "Titre modifié";
$article->save(); // (Sauve les changements)

// (Mass Update)
Article::where('publie', false)->update(['publie' => true]);
delete (DELETE)
$article = Article::findOrFail(1);
$article->delete();

Article::destroy([1, 2, 3]);
Query Builder (AccĂšs direct)

Si vous ne voulez pas utiliser Eloquent (pas d'objet ModĂšle), vous pouvez utiliser le Query Builder (via la Facade DB).

use Illuminate\Support\Facades\DB;

// SELECT
$users = DB::table('users')
    ->where('votes', '>', 100)
    ->get();

// INSERT
DB::table('users')->insert([
    'email' => 'test@test.com',
    'votes' => 0
]);

// SQL Brut (Raw)
$users = DB::select('SELECT * FROM users WHERE id = ?', [1]);
3.4 Eloquent ORM (Relations)
belongsTo (Un Article appartient Ă  un User)
// app/Models/Article.php
use App\Models\User;

class Article extends Model {
    // Définit la relation 'user'
    public function user() {
        return $this->belongsTo(User::class);
    }
}

// --- Utilisation ---
$article = Article::findOrFail(1);
// ($article->user est l'objet User complet)
echo $article->user->name;
hasMany (Un User a plusieurs Articles)
// app/Models/User.php
use App\Models\Article;

class User extends Model {
    // Définit la relation 'articles'
    public function articles() {
        return $this->hasMany(Article::class);
    }
}

// --- Utilisation ---
$user = User::findOrFail(1);
// ($user->articles est une Collection d'Articles)
foreach ($user->articles as $article) {
    echo $article->titre;
}
belongsToMany (Plusieurs-Ă -Plusieurs)

Ex: Un Article a plusieurs Tags. Un Tag a plusieurs Articles.
Nécessite une table pivot (ex: article_tag) contenant article_id et tag_id.

// app/Models/Article.php
class Article extends Model {
    public function tags() {
        return $this->belongsToMany(Tag::class);
    }
}

// app/Models/Tag.php
class Tag extends Model {
    public function articles() {
        return $this->belongsToMany(Article::class);
    }
}

// --- Utilisation ---
$article = Article::findOrFail(1);
// Attacher un tag (ajoute dans la table pivot)
$article->tags()->attach(5);
// Lister les tags
foreach ($article->tags as $tag) { ... }
5.1 Déploiement (Nginx + PHP-FPM)
Architecture de Prod : Nginx + PHP-FPM

Contrairement à Django/Gunicorn, PHP a un gestionnaire de processus (FastCGI) appelé PHP-FPM. C'est l'équivalent de Gunicorn.

[Internet] (Port 80/443)
    |
    ▌
[Nginx (Reverse Proxy)]
 (Sert /index.html, /app.css)
    |
    | (RequĂȘte .php ? -> FastCGI)
    ▌
[PHP-FPM (Socket)]
 (GĂšre un pool de workers PHP)
    |
    ▌
[index.php] -> (Framework Laravel)
Configuration Nginx (Laravel)

La clé est que le root doit pointer vers le dossier public/ de Laravel, et try_files doit renvoyer vers index.php.

# /etc/nginx/sites-available/laravel
server {
    listen 80;
    server_name ideolab.com;
    
    # 1. Racine = dossier /public
    root /var/www/mon_projet/public;
    index index.php;

    location / {
        # 2. Front Controller
        try_files $uri $uri/ /index.php?$query_string;
    }

    # 3. Passer les .php Ă  FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        
        # Socket (RHEL: /run/php-fpm/www.sock)
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }
    
    # 4. Sécurité
    location ~ /\.ht {
        deny all;
    }
}
6.1 Cheat-sheet (Artisan)
Projet & Dev
composer create-project laravel/laravel .
php artisan serve
php artisan tinker
Générateurs (make)
php artisan make:controller MonController
php artisan make:controller ApiController --api
php artisan make:controller PostController --resource

php artisan make:model Article
php artisan make:model Article -m # (avec migration)
php artisan make:model Article -mfs # (mig, factory, seeder)

php artisan make:migration create_users_table
php artisan make:seeder UserSeeder
php artisan make:factory ArticleFactory
php artisan make:middleware CheckRole
php artisan make:request StoreArticleRequest
Base de Données
php artisan migrate
php artisan migrate:fresh
php artisan migrate:rollback
php artisan db:seed
Production & Cache
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan optimize # (Fait les 3)

php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear
php artisan optimize:clear
Queues (Files d'attente)
php artisan queue:work
php artisan queue:listen
php artisan queue:retry [id]
4.2 Validation (Request & Blade)
$request->validate()

La méthode la plus simple pour valider des données entrantes (POST). Si la validation échoue, Laravel redirige automatiquement l'utilisateur vers la page précédente (back()) avec les erreurs.

// ArticleController.php
use Illuminate\Http\Request;
public function store(Request $request) {
    // 1. Valider
    $validatedData = $request->validate([
        'titre' => 'required|unique:articles|max:255',
        'contenu' => 'required|min:10',
        'image' => 'nullable|image|mimes:jpeg,png|max:2048',
    ]);
    
    // 2. Si OK, 'validatedData' est un array sûr
    Article::create($validatedData);
    
    return redirect()->route('articles.index');
}
Affichage des Erreurs (Blade)

Les erreurs sont flashées en session dans une variable $errors.

{-- create.blade.php --}

<form ...>
  {csrf
  <div>
    <label>Titre</label>
    <input type="text" name="titre" value="{{ old('titre') }}">
    
    {-- Affiche l'erreur pour 'titre' --}
    {error('titre')
      <div class="error-message">{{ $message }}</div>
    {enderror
  </div>
  
  {-- Affiche TOUTES les erreurs --}
  {if ($errors->any())
    <div class="error-summary">
      <ul>
        {foreach ($errors->all() as $error)
          <li>{{ $error }}</li>
        {endforeach
      </ul>
    </div>
  {endif
</form>
Form Requests (La "Bonne Pratique")

Déplacer la logique de validation du Controller vers une classe dédiée (Form Request).

php artisan make:request StoreArticleRequest
// app/Http/Requests/StoreArticleRequest.php
public function authorize(): bool {
    // 1. Mettre la logique d'autorisation (ex: Auth::check())
    return true;
}
public function rules(): array {
    // 2. Mettre les rĂšgles
    return [
        'titre' => 'required|unique:articles|max:255',
        'contenu' => 'required|min:10',
    ];
}

// ArticleController.php
// 3. Type-hinter la Request (DI)
public function store(StoreArticleRequest $request) {
    // 4. Si on arrive ici, c'est validé.
    //    $request->validated() contient les données sûres.
    Article::create($request->validated());
    return redirect()->route('articles.index');
}
4.1 Middleware (Filtres HTTP)
Concept (L'Oignon)

Un Middleware est une "couche" (comme un oignon) que la requĂȘte HTTP traverse *avant* d'atteindre votre Controller (et *aprĂšs* avoir quittĂ© le Controller).

Usage : Authentification (auth), vérification CSRF, CORS, ajout de Headers...

RequĂȘte -> [Middleware Log] -> [Middleware Auth] -> [Controller] -> RĂ©ponse
Créer un Middleware
php artisan make:middleware CheckRole
// app/Http/Middleware/CheckRole.php
use Closure;
class CheckRole {
    public function handle(Request $request, Closure $next, string $role) {
        if (! $request->user()->hasRole($role)) {
            // Stoppe la requĂȘte
            return redirect('home');
        }
        
        // 2. Passe Ă  la couche suivante
        return $next($request);
    }
}
Enregistrer & Utiliser
// app/Http/Kernel.php
// (Donner un "alias" au middleware)
protected $middlewareAliases = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'role' => \App\Http\Middleware\CheckRole::class,
    ...
];

// routes/web.php
// Utiliser l'alias
Route::get('/admin', ...)
    ->middleware('auth', 'role:admin');

// (Ou en groupe)
Route::middleware(['auth', 'role:admin'])->group(function () {
    // ...
});
4.3 Service Container (Injection de Dépendances)
Injection de Dépendances (DI) Automatique

Le Service Container est la "boßte magique" de Laravel (cf 1.2). Sa fonction principale est l'injection de dépendances (DI).

Principe (DI) : Si vous "type-hintez" une classe dans un constructeur (ou une méthode de Controller), Laravel essaiera de la "résoudre" (créer new) automatiquement pour vous.

// Un service simple
class PaymentService {
    public function charge(float $amount) { ... }
}

// Controller
class PaymentController extends Controller {
    // 1. Laravel voit 'PaymentService',
    //    le crée (new PaymentService),
    //    et l'injecte dans $this->payment.
    public function __construct(private PaymentService $payment) {
    }
    
    public function store(Request $request) {
        $this->payment->charge($request->amount);
    }
}
Binding (Liaison) Manuel

Que faire si une classe a besoin d'une config (ex: une clé API) ? Ou si vous voulez "binder" une Interface à une Implémentation ? On utilise les Service Providers (ex: app/Providers/AppServiceProvider.php).

// app/Providers/AppServiceProvider.php
class AppServiceProvider extends ServiceProvider {
    public function register(): void {
        
        // 1. Binding (Simple)
        $this->app->bind(PaymentService::class, function ($app) {
            // (Crée un nouvel objet à chaque fois)
            return new PaymentService(config('services.stripe.key'));
        });

        // 2. Singleton (Une seule instance)
        $this->app->singleton(Analytics::class, function ($app) {
            // (Crée 1 fois, puis réutilise)
            return new Analytics(config('services.ga.key'));
        });
        
        // 3. Interface (Binding Interface -> Implémentation)
        $this->app->bind(
            \App\Contracts\BillingInterface::class,
            \App\Services\StripeBilling::class
        );
    }
}
4.4 Queues (Files d'attente) & Jobs
TĂąches en arriĂšre-plan

ProblĂšme : Un utilisateur upload une vidĂ©o. Le traitement (encodage) prend 2 minutes. La requĂȘte HTTP va "timeout" (expirer).

Solution : Les Queues (Files d'attente). Le Controller ne fait que "dispatcher" un "Job" (tùche) dans la file d'attente (ex: Redis, BDD) et renvoie une réponse 200 (OK) immédiate à l'utilisateur.

Un "Worker" (processus séparé) écoute cette file et exécute le Job en arriÚre-plan.

// .env (Changer 'sync' en 'redis' ou 'database')
QUEUE_CONNECTION=redis
1. Créer le Job
php artisan make:job ProcessVideo
// app/Jobs/ProcessVideo.php
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
// ...
class ProcessVideo implements ShouldQueue {
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
    // Le constructeur (reçoit les données)
    public function __construct(protected Video $video) {}

    // La méthode 'handle' (le travail)
    public function handle(): void {
        // (Logique d'encodage de 2 minutes...)
        $this->video->encode();
    }
}
2. Dispatcher le Job (Controller)
// VideoController.php
use App\Jobs\ProcessVideo;
public function store(Request $request) {
    $video = Video::create(...);
    
    // 3. Envoyer Ă  la Queue (rapide)
    ProcessVideo::dispatch($video);
    
    return back()->with('message', 'Vidéo en cours...');
}
3. Lancer le Worker

C'est le processus (systemd, supervisor) qui écoute la file d'attente en production.

# Lancer le worker (en dev)
php artisan queue:work

# Lancer en prod (avec Supervisor)
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=8
4.5 Testing (PHPUnit & PEST)
PHPUnit (Classique)
php artisan make:test UserTest
// tests/Feature/UserTest.php
use Tests\TestCase;
class UserTest extends TestCase {
    public function test_home_page_is_ok(): void {
        // 1. Action
        $response = $this->get('/');
        
        // 2. Assertion
        $response->assertStatus(200);
        $response->assertSee('Bienvenue');
    }
}
PEST (Moderne, élégant)
php artisan make:test HomeTest --pest
// tests/Feature/HomeTest.php
// (Syntaxe plus légÚre, type Jest)
test('home page is ok', function () {
    // 1. Action & Assertion
    $this->get('/')
        ->assertStatus(200)
        ->assertSee('Bienvenue');
});
Lancer les tests
php artisan test
# (ou ./vendor/bin/phpunit)