📘 COURS COMPLET CRUD Laravel 12 — Ultra détaillé & professionnel


🎯 Objectif du cours

Après ce cours, tu seras capable de :

✔ Comprendre l’architecture Laravel ✔ Créer un projet Laravel propre ✔ Configurer la BDD & les migrations ✔ Créer un modèle Eloquent pro ✔ Générer un contrôleur CRUD ✔ Faire les routes RESTful ✔ Construire les vues Blade pro ✔ Faire un CRUD complet (Create, Read, Update, Delete) ✔ Ajouter validation, pagination, sécurité ✔ Ajouter upload d’images ✔ Faire un CRUD API JSON


🧠 PRÉREQUIS

  • PHP 8.1+
  • Composer
  • MySQL / PostgreSQL
  • Notions basiques MVC

1️⃣ Créer un projet Laravel

composer create-project laravel/laravel crud-pro
cd crud-pro
php artisan serve

Le projet tourne sur :

http://127.0.0.1:8000

2️⃣ Configurer la base de données

Dans le fichier .env :

DB_DATABASE=crud_pro
DB_USERNAME=root
DB_PASSWORD=

Puis :

php artisan migrate

3️⃣ Créer une migration (table)

Exemple : table products

php artisan make:migration create_products_table

Ouvrir database/migrations/xxxx_create_products_table.php :

public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->text('description')->nullable();
        $table->decimal('price', 10, 2);
        $table->string('image')->nullable();
        $table->timestamps();
    });
}

Appliquer :

php artisan migrate

4️⃣ Créer le modèle Eloquent

php artisan make:model Product

Modifier app/Models/Product.php :

class Product extends Model
{
    protected $fillable = [
        'name',
        'description',
        'price',
        'image',
    ];
}

5️⃣ Créer le contrôleur CRUD

php artisan make:controller ProductController --resource

Ce controller contient :

  • index()
  • create()
  • store()
  • show()
  • edit()
  • update()
  • destroy()

6️⃣ Déclarer les routes CRUD

Dans routes/web.php :

Route::resource('products', ProductController::class);

Automatiquement Laravel crée :

Méthode URL Action But
GET /products index Liste
GET /products/create create Formulaire
POST /products store Enregistrer
GET /products/{id} show Détail
GET /products/{id}/edit edit Modifier
PUT /products/{id} update Mettre à jour
DELETE /products/{id} destroy Supprimer

7️⃣ Coder les méthodes CRUD (pro et propre)

📌 store() — Créer un produit

app/Http/Controllers/ProductController.php

public function store(Request $request)
{
    $validated = $request->validate([
        'name'        => 'required|min:3',
        'description' => 'nullable',
        'price'       => 'required|numeric',
        'image'       => 'nullable|image|max:2048'
    ]);

    if ($request->hasFile('image')) {
        $validated['image'] = $request->file('image')->store('products', 'public');
    }

    Product::create($validated);

    return redirect()->route('products.index')->with('success', 'Produit créé avec succès.');
}

📌 index() — Liste avec pagination

public function index()
{
    $products = Product::latest()->paginate(10);
    return view('products.index', compact('products'));
}

📌 edit() — charger le formulaire de modification

public function edit(Product $product)
{
    return view('products.edit', compact('product'));
}

📌 update() — modifier

public function update(Request $request, Product $product)
{
    $validated = $request->validate([
        'name'        => 'required|min:3',
        'description' => 'nullable',
        'price'       => 'required|numeric',
        'image'       => 'nullable|image|max:2048'
    ]);

    if ($request->hasFile('image')) {
        $validated['image'] = $request->file('image')->store('products', 'public');
    }

    $product->update($validated);

    return redirect()->route('products.index')->with('success', 'Produit mis à jour.');
}

📌 destroy() — supprimer

public function destroy(Product $product)
{
    $product->delete();
    return redirect()->back()->with('success', 'Produit supprimé.');
}

8️⃣ Créer les vues Blade professionnelles

Créer le dossier :

resources/views/products/

📌 Formulaire (create / edit)

resources/views/products/form.blade.php

<div class="mb-3">
    <label>Nom</label>
    <input type="text" name="name" class="form-control" value="{{ old('name', $product->name ?? '') }}">
</div>

<div class="mb-3">
    <label>Description</label>
    <textarea name="description" class="form-control">{{ old('description', $product->description ?? '') }}</textarea>
</div>

<div class="mb-3">
    <label>Prix</label>
    <input type="number" step="0.01" name="price" class="form-control" value="{{ old('price', $product->price ?? '') }}">
</div>

<div class="mb-3">
    <label>Image</label>
    <input type="file" name="image" class="form-control">
</div>

📌 Créer une nouvelle entrée

create.blade.php

@extends('layout')

@section('content')
<h1>Ajouter un produit</h1>

<form action="{{ route('products.store') }}" method="POST" enctype="multipart/form-data">
    @csrf

    @include('products.form')

    <button class="btn btn-primary">Enregistrer</button>
</form>
@endsection

📌 Liste

index.blade.php

@extends('layout')

@section('content')
<h1>Liste des produits</h1>

<a href="{{ route('products.create') }}" class="btn btn-success">Ajouter</a>

<table class="table mt-3">
    <thead>
        <tr>
            <th>ID</th>
            <th>Nom</th>
            <th>Prix</th>
            <th>Image</th>
            <th>Actions</th>
        </tr>
    </thead>

    <tbody>
        @foreach ($products as $p)
        <tr>
            <td>{{ $p->id }}</td>
            <td>{{ $p->name }}</td>
            <td>{{ $p->price }}€</td>
            <td>
                @if($p->image)
                    <img src="{{ asset('storage/'.$p->image) }}" width="60">
                @endif
            </td>
            <td>
                <a href="{{ route('products.edit', $p) }}" class="btn btn-warning">Modifier</a>

                <form action="{{ route('products.destroy', $p) }}" method="POST" class="d-inline">
                    @csrf @method('DELETE')
                    <button class="btn btn-danger">Supprimer</button>
                </form>
            </td>
        </tr>
        @endforeach
    </tbody>
</table>

{{ $products->links() }}

@endsection

9️⃣ BONUS : Ajouter un layout global

resources/views/layout.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>CRUD Laravel Pro</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-5">

<div class="container">
    @if(session('success'))
        <div class="alert alert-success">{{ session('success') }}</div>
    @endif

    @yield('content')
</div>

</body>
</html>

🔟 BONUS : CRUD API JSON PRO

Dans routes/api.php :

Route::apiResource('products', ProductController::class);

Dans le contrôleur :

return response()->json($products);

ou :

return response()->json(['message' => 'Produit créé', 'data' => $product]);

✔ BONUS : Notions professionnelles incluses

Cette formation couvre :

✔ Validation avancée ✔ Upload d’images ✔ Pagination ✔ Routing RESTful ✔ Architecture MVC ✔ Eloquent ORM ✔ Sécurité CSRF ✔ Messages flash ✔ Réutilisation de vues (partials) ✔ API JSON ✔ Resource Controllers ✔ Storage public/privé