Guide très facile Laravel — OFPPT Notes دليل Laravel سهل جدا — ملاحظات OFPPT

Guide facile étape par étape. Copie. Colle. Ça marche. On va créer une petite application Laravel avec login, modules et calcul de note.

دليل سهل خطوة بخطوة. انسخ. الصق. وسيعمل. سنبني تطبيقا صغيرا بـ Laravel فيه دخول، وحدات، وحساب النقطة.

Loginتسجيل الدخول Ajouter / modifier / supprimerإضافة / تعديل / حذف Calcul de la note finaleحساب النقطة النهائية admin@ofppt.ma / password

▶ Voir le projet en live

▶ شاهد المشروع مباشرة

1. Avant de commencer 1. قبل أن نبدأ

▼

Avant d’écrire du code, installe ces outils. Ils vont aider Laravel à marcher sur ton PC.

قبل كتابة الكود، ثبت هذه الأدوات. هي تساعد Laravel أن يعمل في حاسوبك.

Outilالأداة Ce qu’il fautما نحتاجه
PHP (XAMPP)8.2+
Composer2.x
VS Codestableمستقر
✅ Tu peux choisir SQLite ou MySQL. SQLite est le plus simple. MySQL utilise XAMPP et phpMyAdmin. On choisira à l’étape 4. ✅ يمكنك اختيار SQLite أو MySQL. SQLite هو الأسهل. MySQL يحتاج XAMPP و phpMyAdmin. سنختار في الخطوة 4.
📍 Où écrire ? → Dans CMD. Appuie sur Windows + R, écris cmd, puis Entrée. أين نكتب؟ → في CMD. اضغط Windows + R، اكتب cmd، ثم Entrée.
php -v
composer -v
Exemple php -v et composer -v

Si tu vois des numéros, c’est bon. PHP et Composer sont prêts. إذا رأيت أرقاما، فهذا جيد. PHP و Composer جاهزان.

⚠ Si Windows ne connaît pas php ou composer, ce n’est pas grave. Ajoute le dossier PHP de XAMPP au PATH Windows. Ferme CMD. Ouvre CMD encore une fois. ⚠ إذا لم يعرف Windows الأمر php أو composer، لا مشكلة. أضف مجلد PHP الخاص بـ XAMPP إلى PATH. أغلق CMD. افتحه من جديد.
NEXT → Étape 2 : On crée le projet التالي → الخطوة 2: سننشئ المشروع

2. Créer ton projet 2. أنشئ مشروعك

▼

Pas besoin de cd ni de mkdir. Tu crées le dossier avec Windows. Puis tu ouvres CMD déjà dedans.

لا تحتاج cd ولا mkdir. أنشئ المجلد بويندوز. ثم افتح CMD وهو داخل المجلد.

  1. Clic droit sur le Bureau (ou Documents) → Nouveau → Dossier. Donne-lui un nom (exemple : laravel projet).
  2. زر يمين على سطح المكتب (أو المستندات) → جديد → مجلد. سمّه (مثال: laravel projet).
  3. Ouvre ce dossier (double-clic). Il peut être vide. C’est normal.
  4. افتح هذا المجلد (نقرتان). يمكن أن يكون فارغا. هذا عادي.
  5. Clique en haut dans la barre d’adresse (le chemin). Efface. Tape cmd. Appuie sur Entrée.
  6. انقر أعلى في شريط العنوان (المسار). امسح. اكتب cmd. ثم Entrée.
Taper cmd dans la barre d'adresse de l'Explorateur

Tape cmd ici, puis Entrée. CMD s’ouvre dans ton dossier. اكتب cmd هنا ثم Entrée. يفتح CMD داخل مجلدك.

📍 Où écrire ? → Dans ce CMD (déjà dans ton dossier). Copie seulement ces commandes. أين نكتب؟ → في هذا CMD (هو أصلا داخل مجلدك). انسخ هذه الأوامر فقط.
composer create-project laravel/laravel first-app
cd first-app
code .
php artisan serve
  1. composer create-project télécharge Laravel et crée first-app.
  2. composer create-project يحمل Laravel وينشئ first-app.
  3. code . ouvre le projet dans VS Code.
  4. code . يفتح المشروع في VS Code.
  5. php artisan serve lance le site ici : http://127.0.0.1:8000.
  6. php artisan serve يشغل الموقع هنا: http://127.0.0.1:8000.
💡 Tu n’as pas besoin de key:generate. Laravel le fait tout seul. Pour la base, on verra à l’étape 4. 💡 لا تحتاج key:generate. Laravel يفعلها وحده. القاعدة في الخطوة 4.
Page d'accueil Laravel

Tu dois voir la page de bienvenue Laravel. Si tu la vois, le projet marche. يجب أن ترى صفحة الترحيب Laravel. إذا رأيتها، فالمشروع يعمل.

✅ Au début, Laravel utilise SQLite. Si ton prof demande MySQL, attends l’étape 4. On changera .env avant migrate. ✅ في البداية، Laravel يستعمل SQLite. إذا طلب الأستاذ MySQL، انتظر الخطوة 4. سنغير .env قبل migrate.
⚠ Ne ferme pas CMD pendant que le site marche. Pour écrire une autre commande, ouvre un 2e CMD. Puis va dans first-app. ⚠ لا تغلق CMD عندما يكون الموقع يعمل. لكتابة أمر آخر، افتح CMD ثاني. ثم ادخل إلى first-app.
NEXT → Étape 3 : Où sont les fichiers ? التالي → الخطوة 3: أين توجد الملفات؟

3. Trouver les bons dossiers 3. نجد المجلدات الصحيحة

▼

Dans VS Code, ouvre le projet first-app. Voici les endroits importants. Ne t’inquiète pas. On va les utiliser un par un.

في VS Code، افتح مشروع first-app. هذه هي الأماكن المهمة. لا تقلق. سنستعملها واحدا واحدا.

VS Code avec projet Laravel ouvert

Exemple : VS Code montre les dossiers du projet. مثال: VS Code يعرض مجلدات المشروع.

app/Models/ Ici on met les models. Un model parle avec une table.هنا نضع Models. الـ Model يتكلم مع جدول.
app/Http/Controllers/ Ici on met les controllers. Un controller reçoit la demande et répond.هنا نضع Controllers. الـ Controller يستقبل الطلب ويرد.
database/migrations/ Ici on décrit les tables de la base.هنا نصف جداول قاعدة البيانات.
database/seeders/ Ici on met des données pour tester.هنا نضع بيانات للتجربة.
resources/views/ Ici on met les pages HTML. Laravel les appelle Blade.هنا نضع صفحات HTML. Laravel يسميها Blade.
routes/web.php Ici on met les adresses du site.هنا نضع عناوين الموقع.
users / modules / calculs / notes_modules Formule : (Note1A × 1 + Note2A × 3 + EFF) ÷ 9 Réussi : note_finale >= 10
NEXT → Étape 4 : Préparer la base التالي → الخطوة 4: نجهز قاعدة البيانات

4. Préparer la base de données 4. نجهز قاعدة البيانات

▼

La base de données garde les informations. Choisis une seule option : A pour SQLite, ou B pour MySQL. Après, on crée les tables.

قاعدة البيانات تحفظ المعلومات. اختر اختيارا واحدا فقط: أ لـ SQLite، أو ب لـ MySQL. بعد ذلك ننشئ الجداول.

Option A — SQLite (le plus simple) الخيار أ — SQLite (الأسهل)

Tu n’as rien à changer. Laravel a déjà DB_CONNECTION=sqlite dans .env. Le fichier de la base est database/database.sqlite. Va directement aux migrations plus bas. لا تحتاج أن تغير شيئا. Laravel فيه DB_CONNECTION=sqlite في .env. ملف القاعدة هو database/database.sqlite. اذهب مباشرة إلى Migrations في الأسفل.

Option B — MySQL avec XAMPP الخيار ب — MySQL مع XAMPP

  1. Ouvre XAMPP Control Panel. Clique Start pour Apache. Clique Start pour MySQL.
  2. افتح XAMPP Control Panel. اضغط Start أمام Apache. واضغط Start أمام MySQL.
XAMPP Apache et MySQL démarrés

Quand Apache et MySQL sont verts, c’est bon. عندما يصبح Apache و MySQL باللون الأخضر، فهذا جيد.

  1. Ouvre http://127.0.0.1/phpmyadmin. Clique Nouvelle base. Écris first_app. Choisis utf8mb4_unicode_ci. Clique Créer.
  2. افتح http://127.0.0.1/phpmyadmin. اضغط قاعدة جديدة. اكتب first_app. اختر utf8mb4_unicode_ci. اضغط إنشاء.
Créer une base dans phpMyAdmin

Le nom doit être first_app. On va mettre le même nom dans .env. يجب أن يكون الاسم first_app. سنكتب نفس الاسم في .env.

📍 Où coller ? → Dans VS Code. Ouvre .env, à la racine du projet. Remplace les lignes DB par ceci : أين نلصق؟ → في VS Code. افتح .env في أصل المشروع. عوض أسطر DB بهذا:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=first_app
DB_USERNAME=root
DB_PASSWORD=
⚠ Avec XAMPP, le mot de passe MySQL est souvent vide. Donc laisse DB_PASSWORD=. Si tu as créé un mot de passe pour root, écris-le ici. Avec DB_CONNECTION=mysql, Laravel utilise MySQL. ⚠ مع XAMPP، كلمة مرور MySQL غالبا فارغة. لذلك اترك DB_PASSWORD=. إذا وضعت كلمة مرور لـ root، اكتبها هنا. مع DB_CONNECTION=mysql، Laravel يستعمل MySQL.
Après avoir changé .env, lance php artisan config:clear. Cela dit à Laravel : relis les réglages. بعد تغيير .env، شغل php artisan config:clear. هذا يقول لـ Laravel: اقرأ الإعدادات من جديد.
📍 Où écrire ? → Dans CMD, dans le dossier first-app. Fais ceci seulement si tu as choisi MySQL. أين نكتب؟ → في CMD، داخل مجلد first-app. افعل هذا فقط إذا اخترت MySQL.
php artisan config:clear

Créer les fichiers des tables إنشاء ملفات الجداول

Même code pour SQLite et MySQL. 1) On crée 3 fichiers. 2) On colle le code. 3) On lance migrate. C’est tout.

نفس الكود لـ SQLite و MySQL. 1) ننشئ 3 ملفات. 2) نلصق الكود. 3) نشغل migrate. هذا كل شيء.

📍 Où écrire ? → Dans CMD. Va dans le dossier first-app. أين نكتب؟ → في CMD. ادخل إلى مجلد first-app.
cd first-app
php artisan make:migration create_modules_table
php artisan make:migration create_calculs_table
php artisan make:migration create_notes_modules_table

Table modulesجدول modules

📍 Où coller ? → Dans VS Code. Ouvre database/migrations/..._create_modules_table.php. Efface tout. Colle ce code. أين نلصق؟ → في VS Code. افتح database/migrations/..._create_modules_table.php. امسح كل شيء. الصق هذا الكود.
<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('modules', function (Blueprint $table) {
            $table->id();
            $table->string('code');
            $table->string('nom');
            $table->integer('coefficient');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('modules');
    }
};

Table calculsجدول calculs

📍 Où coller ? → Dans VS Code. Ouvre database/migrations/..._create_calculs_table.php. Remplace tout par ce code. أين نلصق؟ → في VS Code. افتح database/migrations/..._create_calculs_table.php. عوض كل شيء بهذا الكود.
<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('calculs', function (Blueprint $table) {
            $table->id();
            $table->decimal('note_annee1', 5, 2);
            $table->decimal('note_eff', 5, 2);
            $table->decimal('moyenne_annee2', 5, 2);
            $table->decimal('note_finale', 5, 2);
            $table->boolean('reussi');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('calculs');
    }
};

Table notes_modulesجدول notes_modules

📍 Où coller ? → Dans VS Code. Ouvre database/migrations/..._create_notes_modules_table.php. Remplace tout par ce code. أين نلصق؟ → في VS Code. افتح database/migrations/..._create_notes_modules_table.php. عوض كل شيء بهذا الكود.
<?php

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

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('notes_modules', function (Blueprint $table) {
            $table->id();
            $table->foreignId('calcul_id')->constrained('calculs')->cascadeOnDelete();
            $table->foreignId('module_id')->constrained('modules')->cascadeOnDelete();
            $table->decimal('note', 5, 2);
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('notes_modules');
    }
};
📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan migrate
php artisan migrate réussi

Si migrate réussit, les tables sont créées. إذا نجح migrate، فهذا يعني أن الجداول أُنشئت.

✅ Avec MySQL, regarde dans phpMyAdmin, base first_app. Avec SQLite, Laravel écrit dans database/database.sqlite. ✅ مع MySQL، انظر في phpMyAdmin داخل قاعدة first_app. مع SQLite، Laravel يكتب في database/database.sqlite.
⚠ Important : crée d’abord modules et calculs. Après, crée notes_modules. Ce fichier a besoin des deux autres tables. ⚠ مهم: أنشئ أولا modules و calculs. بعد ذلك أنشئ notes_modules. هذا الملف يحتاج الجدولين الآخرين.
NEXT → Étape 5 : Créer les models التالي → الخطوة 5: إنشاء Models

5. Créer les models 5. إنشاء Models

▼
📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan make:model Module
php artisan make:model Calcul
php artisan make:model NoteModule
📍 Où coller ? → Dans VS Code. Crée ou ouvre app/Models/Module.php. Colle ce code. أين نلصق؟ → في VS Code. أنشئ أو افتح app/Models/Module.php. الصق هذا الكود.
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Module extends Model
{
    protected $fillable = ['code', 'nom', 'coefficient'];
}
📍 Où coller ? → Dans VS Code. Ouvre app/Models/Calcul.php. Colle ce code. أين نلصق؟ → في VS Code. افتح app/Models/Calcul.php. الصق هذا الكود.
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Calcul extends Model
{
    protected $fillable = [
        'note_annee1', 'note_eff', 'moyenne_annee2', 'note_finale', 'reussi',
    ];

    public function notesModules()
    {
        return $this->hasMany(NoteModule::class);
    }
}
📍 Où coller ? → Dans VS Code. Ouvre app/Models/NoteModule.php. Colle ce code. أين نلصق؟ → في VS Code. افتح app/Models/NoteModule.php. الصق هذا الكود.
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class NoteModule extends Model
{
    protected $table = 'notes_modules';

    protected $fillable = ['calcul_id', 'module_id', 'note'];

    public function module()
    {
        return $this->belongsTo(Module::class);
    }

    public function calcul()
    {
        return $this->belongsTo(Calcul::class);
    }
}
⚠ Garde cette ligne : protected $table = 'notes_modules';. Sinon Laravel cherche le mauvais nom : note_modules. ⚠ اترك هذا السطر: protected $table = 'notes_modules';. بدونه Laravel يبحث عن اسم خاطئ: note_modules.
NEXT → Étape 6 : Faire le login التالي → الخطوة 6: إنشاء الدخول

6. Faire le login 6. إنشاء صفحة الدخول

▼
📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan make:controller AuthController
📍 Où coller ? → Dans VS Code. Ouvre app/Http/Controllers/AuthController.php. Colle ce code. أين نلصق؟ → في VS Code. افتح app/Http/Controllers/AuthController.php. الصق هذا الكود.
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    public function showLogin()
    {
        return view('auth.login');
    }

    public function login(Request $request)
    {
        $credentials = $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        if (Auth::attempt($credentials)) {
            $request->session()->regenerate();
            return redirect()->route('calcul.index')->with('success', 'Connexion réussie.');
        }

        return back()->withErrors([
            'email' => 'Email ou mot de passe incorrect.',
        ])->onlyInput('email');
    }

    public function logout(Request $request)
    {
        Auth::logout();
        $request->session()->invalidate();
        $request->session()->regenerateToken();
        return redirect()->route('login')->with('success', 'Déconnexion réussie.');
    }
}
📍 Où coller ? → Dans VS Code. Crée le dossier resources/views/auth/. Dedans, crée login.blade.php. Colle ce code. أين نلصق؟ → في VS Code. أنشئ المجلد resources/views/auth/. داخله، أنشئ login.blade.php. الصق هذا الكود.
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login - OFPPT Notes</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light d-flex align-items-center min-vh-100">
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-5">
            <div class="card shadow">
                <div class="card-header bg-primary text-white text-center">
                    <h1 class="h4 mb-0">Connexion OFPPT Notes</h1>
                </div>
                <div class="card-body p-4">
                    @if (session('success'))
                        <div class="alert alert-success">{{ session('success') }}</div>
                    @endif
                    @if ($errors->any())
                        <div class="alert alert-danger">
                            <ul class="mb-0">
                                @foreach ($errors->all() as $error)
                                    <li>{{ $error }}</li>
                                @endforeach
                            </ul>
                        </div>
                    @endif
                    <form method="POST" action="{{ route('login') }}">
                        @csrf
                        <div class="mb-3">
                            <label class="form-label fw-bold">Email</label>
                            <input type="email" name="email" class="form-control" value="{{ old('email') }}" required autofocus>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Mot de passe</label>
                            <input type="password" name="password" class="form-control" required>
                        </div>
                        <button type="submit" class="btn btn-primary w-100">Se connecter</button>
                    </form>
                    <p class="text-muted small text-center mt-3 mb-0">
                        Compte test : <strong>admin@ofppt.ma</strong> / <strong>password</strong>
                    </p>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>
NEXT → Étape 7 : Gérer les modules التالي → الخطوة 7: تسيير الوحدات

7. Ajouter, modifier, supprimer les modules 7. إضافة وتعديل وحذف الوحدات

▼
📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan make:controller ModuleController
📍 Où coller ? → Dans VS Code. Ouvre app/Http/Controllers/ModuleController.php. Colle ce code. أين نلصق؟ → في VS Code. افتح app/Http/Controllers/ModuleController.php. الصق هذا الكود.
<?php

namespace App\Http\Controllers;

use App\Models\Module;
use Illuminate\Http\Request;

class ModuleController extends Controller
{
    public function index()
    {
        $modules = Module::orderBy('id')->get();
        return view('modules.index', compact('modules'));
    }

    public function create()
    {
        return view('modules.create');
    }

    public function store(Request $request)
    {
        $request->validate([
            'code' => 'required|string|max:50',
            'nom' => 'required|string|max:255',
            'coefficient' => 'required|integer|min:1|max:10',
        ]);
        Module::create($request->only('code', 'nom', 'coefficient'));
        return redirect()->route('modules.index')->with('success', 'Module ajouté.');
    }

    public function edit($id)
    {
        $module = Module::findOrFail($id);
        return view('modules.edit', compact('module'));
    }

    public function update(Request $request, $id)
    {
        $request->validate([
            'code' => 'required|string|max:50',
            'nom' => 'required|string|max:255',
            'coefficient' => 'required|integer|min:1|max:10',
        ]);
        Module::findOrFail($id)->update($request->only('code', 'nom', 'coefficient'));
        return redirect()->route('modules.index')->with('success', 'Module modifié.');
    }

    public function destroy($id)
    {
        Module::findOrFail($id)->delete();
        return redirect()->route('modules.index')->with('success', 'Module supprimé.');
    }
}
Les pages Blade arrivent à l’étape 9 : index, create, edit. Pour le moment, colle juste le controller. صفحات Blade تأتي في الخطوة 9: index و create و edit. الآن الصق فقط الـ controller.
NEXT → Étape 8 : Calculer la note التالي → الخطوة 8: حساب النقطة

8. Calculer la note finale 8. حساب النقطة النهائية

▼

Voici la formule. Laravel va la calculer pour nous : (Note1A × 1 + Note2A × 3 + EFF) ÷ 9. Si le résultat est 10/20 ou plus, l’étudiant réussit.

هذه هي الصيغة. Laravel سيحسبها لنا: (Note1A × 1 + Note2A × 3 + EFF) ÷ 9. إذا كانت النتيجة 10/20 أو أكثر، فالطالب ناجح.

📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan make:controller CalculController
📍 Où coller ? → Dans VS Code. Ouvre app/Http/Controllers/CalculController.php. Colle ce code. أين نلصق؟ → في VS Code. افتح app/Http/Controllers/CalculController.php. الصق هذا الكود.
<?php

namespace App\Http\Controllers;

use App\Models\Calcul;
use App\Models\Module;
use App\Models\NoteModule;
use Illuminate\Http\Request;

class CalculController extends Controller
{
    public function index()
    {
        $modules = Module::all();
        $calculs = Calcul::orderBy('id', 'desc')->limit(5)->get();
        return view('calcul.index', compact('modules', 'calculs'));
    }

    public function store(Request $request)
    {
        $request->validate([
            'note_annee1' => 'required|numeric|min:0|max:20',
            'note_eff' => 'required|numeric|min:0|max:100',
            'notes' => 'required|array',
            'notes.*' => 'required|numeric|min:0|max:20',
        ]);

        $modules = Module::all();
        if ($modules->count() == 0) {
            return redirect()->route('modules.create')
                ->with('success', 'Ajoute d’abord au moins un module.');
        }

        $totalNotes = 0;
        $totalCoef = 0;
        foreach ($modules as $module) {
            if (!isset($request->notes[$module->id])) continue;
            $totalNotes += $request->notes[$module->id] * $module->coefficient;
            $totalCoef += $module->coefficient;
        }
        if ($totalCoef == 0) {
            return back()->withErrors(['notes' => 'Aucune note de module valide.']);
        }

        $moyenneAnnee2 = $totalNotes / $totalCoef;
        $noteFinale = round(($request->note_annee1 * 1 + $moyenneAnnee2 * 3 + $request->note_eff) / 9, 2);
        $reussi = $noteFinale >= 10;

        $calcul = Calcul::create([
            'note_annee1' => $request->note_annee1,
            'note_eff' => $request->note_eff,
            'moyenne_annee2' => round($moyenneAnnee2, 2),
            'note_finale' => $noteFinale,
            'reussi' => $reussi,
        ]);

        foreach ($modules as $module) {
            NoteModule::create([
                'calcul_id' => $calcul->id,
                'module_id' => $module->id,
                'note' => $request->notes[$module->id],
            ]);
        }

        return redirect()->route('calcul.index')->with([
            'note_finale' => $noteFinale,
            'moyenne_annee2' => round($moyenneAnnee2, 2),
            'reussi' => $reussi,
        ]);
    }

    public function destroy($id)
    {
        Calcul::findOrFail($id)->delete();
        return redirect()->route('calcul.index')->with('success', 'Calcul supprimé.');
    }
}
NEXT → Étape 9 : Créer les pages التالي → الخطوة 9: إنشاء الصفحات

9. Créer les pages Blade 9. إنشاء صفحات Blade

▼

Maintenant on crée les pages que l’utilisateur voit. Pour chaque fichier : 1) crée le fichier. 2) colle le code complet. 3) enregistre.

الآن ننشئ الصفحات التي يراها المستخدم. لكل ملف: 1) أنشئ الملف. 2) الصق الكود كاملا. 3) احفظ.

layout.blade.php

📍 Où coller ? → Dans VS Code. Crée ou ouvre resources/views/layout.blade.php. C’est la page de base. أين نلصق؟ → في VS Code. أنشئ أو افتح resources/views/layout.blade.php. هذه هي الصفحة الأساسية.
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title') - OFPPT Notes</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="d-flex flex-column min-vh-100 bg-light">
<header class="bg-primary text-white py-3">
    <div class="container">
        <h1 class="h3 mb-1">OFPPT – Calcul Note Finale</h1>
    </div>
</header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
        <div class="navbar-nav me-auto">
            <a class="nav-link" href="{{ route('calcul.index') }}">Calcul</a>
            <a class="nav-link" href="{{ route('modules.index') }}">Modules</a>
            <a class="nav-link" href="{{ route('modules.create') }}">Ajouter</a>
        </div>
        <div class="d-flex align-items-center gap-3">
            <span class="text-white small">{{ Auth::user()->name }}</span>
            <form action="{{ route('logout') }}" method="POST" class="mb-0">
                @csrf
                <button type="submit" class="btn btn-outline-light btn-sm">Déconnexion</button>
            </form>
        </div>
    </div>
</nav>
<main class="container my-4 flex-grow-1">
    @if (session('success'))
        <div class="alert alert-success">{{ session('success') }}</div>
    @endif
    @if ($errors->any())
        <div class="alert alert-danger"><ul class="mb-0">@foreach ($errors->all() as $e)<li>{{ $e }}</li>@endforeach</ul></div>
    @endif
    @yield('content')
</main>
<footer class="bg-primary text-white text-center py-3 mt-auto">
    <div class="container small">Formule : (Note1A × 1 + Note2A × 3 + EFF) ÷ 9 | Seuil ≥ 10/20</div>
</footer>
</body>
</html>

modules/index.blade.php

📍 Où coller ? → Dans VS Code. Crée resources/views/modules/index.blade.php. Cette page montre la liste des modules. أين نلصق؟ → في VS Code. أنشئ resources/views/modules/index.blade.php. هذه الصفحة تعرض قائمة الوحدات.
@extends('layout')
@section('title', 'Modules')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-3">
    <h2 class="text-primary mb-0">Liste des modules</h2>
    <a class="btn btn-primary" href="{{ route('modules.create') }}">+ Ajouter</a>
</div>
@if ($modules->count() == 0)
    <p>Aucun module.</p>
@else
<table class="table table-bordered table-striped bg-white">
    <thead class="table-primary"><tr><th>ID</th><th>Code</th><th>Nom</th><th>Coef</th><th>Actions</th></tr></thead>
    <tbody>
    @foreach ($modules as $module)
        <tr>
            <td>{{ $module->id }}</td>
            <td>{{ $module->code }}</td>
            <td>{{ $module->nom }}</td>
            <td>{{ $module->coefficient }}</td>
            <td>
                <a class="btn btn-sm btn-secondary" href="{{ route('modules.edit', $module->id) }}">Modifier</a>
                <form class="d-inline" action="{{ route('modules.destroy', $module->id) }}" method="POST" onsubmit="return confirm('Supprimer ?')">
                    @csrf @method('DELETE')
                    <button class="btn btn-sm btn-danger">Supprimer</button>
                </form>
            </td>
        </tr>
    @endforeach
    </tbody>
</table>
@endif
@endsection

modules/create.blade.php

📍 Où coller ? → Dans VS Code. Crée resources/views/modules/create.blade.php. Cette page ajoute un module. أين نلصق؟ → في VS Code. أنشئ resources/views/modules/create.blade.php. هذه الصفحة تضيف وحدة.
@extends('layout')
@section('title', 'Ajouter module')
@section('content')
<h2 class="text-primary mb-3">Ajouter un module</h2>
<form action="{{ route('modules.store') }}" method="POST" class="card card-body shadow-sm">
    @csrf
    <div class="mb-3"><label class="form-label fw-bold">Code</label>
        <input type="text" class="form-control" name="code" value="{{ old('code') }}" required></div>
    <div class="mb-3"><label class="form-label fw-bold">Nom</label>
        <input type="text" class="form-control" name="nom" value="{{ old('nom') }}" required></div>
    <div class="mb-3"><label class="form-label fw-bold">Coefficient</label>
        <input type="number" class="form-control" name="coefficient" min="1" max="10" value="{{ old('coefficient', 1) }}" required></div>
    <button class="btn btn-primary">Enregistrer</button>
    <a class="btn btn-secondary" href="{{ route('modules.index') }}">Annuler</a>
</form>
@endsection

modules/edit.blade.php

📍 Où coller ? → Dans VS Code. Crée resources/views/modules/edit.blade.php. Cette page modifie un module. أين نلصق؟ → في VS Code. أنشئ resources/views/modules/edit.blade.php. هذه الصفحة تعدل وحدة.
@extends('layout')
@section('title', 'Modifier module')
@section('content')
<h2 class="text-primary mb-3">Modifier le module</h2>
<form action="{{ route('modules.update', $module->id) }}" method="POST" class="card card-body shadow-sm">
    @csrf @method('PUT')
    <div class="mb-3"><label class="form-label fw-bold">Code</label>
        <input type="text" class="form-control" name="code" value="{{ old('code', $module->code) }}" required></div>
    <div class="mb-3"><label class="form-label fw-bold">Nom</label>
        <input type="text" class="form-control" name="nom" value="{{ old('nom', $module->nom) }}" required></div>
    <div class="mb-3"><label class="form-label fw-bold">Coefficient</label>
        <input type="number" class="form-control" name="coefficient" min="1" max="10" value="{{ old('coefficient', $module->coefficient) }}" required></div>
    <button class="btn btn-primary">Mettre à jour</button>
    <a class="btn btn-secondary" href="{{ route('modules.index') }}">Annuler</a>
</form>
@endsection

calcul/index.blade.php

📍 Où coller ? → Dans VS Code. Crée resources/views/calcul/index.blade.php. Cette page calcule la note finale. أين نلصق؟ → في VS Code. أنشئ resources/views/calcul/index.blade.php. هذه الصفحة تحسب النقطة النهائية.
@extends('layout')
@section('title', 'Calcul')
@section('content')
<h2 class="mb-3 text-primary">Calculer la note finale</h2>
@if ($modules->count() == 0)
    <a class="btn btn-primary" href="{{ route('modules.create') }}">Ajouter un module</a>
@else
<form action="{{ route('calcul.store') }}" method="POST" class="card card-body shadow-sm mb-4">
    @csrf
    <div class="mb-3">
        <label class="form-label fw-bold">Note 1ère année (/20)</label>
        <input type="number" class="form-control" name="note_annee1" min="0" max="20" step="0.01" value="{{ old('note_annee1') }}" required>
    </div>
    <div class="mb-3">
        <label class="form-label fw-bold">EFF (/100)</label>
        <input type="number" class="form-control" name="note_eff" min="0" max="100" step="0.01" value="{{ old('note_eff') }}" required>
    </div>
    <h3 class="h5 text-primary">Modules 2ème année</h3>
    <table class="table table-bordered">
        <thead class="table-primary"><tr><th>Code</th><th>Module</th><th>Coef</th><th>Note /20</th></tr></thead>
        <tbody>
        @foreach ($modules as $module)
            <tr>
                <td>{{ $module->code }}</td>
                <td>{{ $module->nom }}</td>
                <td>{{ $module->coefficient }}</td>
                <td><input type="number" class="form-control" name="notes[{{ $module->id }}]" min="0" max="20" step="0.01" value="{{ old('notes.'.$module->id) }}" required></td>
            </tr>
        @endforeach
        </tbody>
    </table>
    <button class="btn btn-primary">Calculer</button>
</form>
@endif

@if (session('note_finale') !== null)
<div class="card card-body shadow-sm mb-4">
    <p>Moyenne 2A : <strong>{{ session('moyenne_annee2') }}</strong></p>
    <p>Note finale : <strong>{{ session('note_finale') }} / 20</strong></p>
    @if (session('reussi'))
        <p class="text-success fw-bold">RÉUSSI</p>
    @else
        <p class="text-danger fw-bold">AJOURNÉ</p>
    @endif
</div>
@endif

@if ($calculs->count() > 0)
<h2 class="h5 text-primary">Derniers calculs</h2>
<table class="table table-bordered bg-white">
    <thead class="table-primary"><tr><th>#</th><th>1A</th><th>2A</th><th>EFF</th><th>Finale</th><th>Résultat</th><th></th></tr></thead>
    <tbody>
    @foreach ($calculs as $calcul)
        <tr>
            <td>{{ $calcul->id }}</td>
            <td>{{ $calcul->note_annee1 }}</td>
            <td>{{ $calcul->moyenne_annee2 }}</td>
            <td>{{ $calcul->note_eff }}</td>
            <td>{{ $calcul->note_finale }}</td>
            <td>@if($calcul->reussi)<span class="badge text-bg-success">Réussi</span>@else<span class="badge text-bg-danger">Ajourné</span>@endif</td>
            <td>
                <form action="{{ route('calcul.destroy', $calcul->id) }}" method="POST" onsubmit="return confirm('Supprimer ?')">
                    @csrf @method('DELETE')
                    <button class="btn btn-sm btn-danger">Supprimer</button>
                </form>
            </td>
        </tr>
    @endforeach
    </tbody>
</table>
@endif
@endsection
NEXT → Étape 10 : Relier les pages التالي → الخطوة 10: ربط الصفحات

10. Relier les adresses du site 10. ربط عناوين الموقع

▼
📍 Où coller ? → Dans VS Code. Ouvre routes/web.php. Efface tout le fichier. Colle ce code. أين نلصق؟ → في VS Code. افتح routes/web.php. امسح الملف كله. الصق هذا الكود.
<?php

use App\Http\Controllers\AuthController;
use App\Http\Controllers\CalculController;
use App\Http\Controllers\ModuleController;
use Illuminate\Support\Facades\Route;

Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout'])->name('logout');

Route::middleware('auth')->group(function () {
    Route::get('/', [CalculController::class, 'index'])->name('calcul.index');
    Route::post('/calculer', [CalculController::class, 'store'])->name('calcul.store');
    Route::delete('/calculs/{id}', [CalculController::class, 'destroy'])->name('calcul.destroy');

    Route::get('/modules', [ModuleController::class, 'index'])->name('modules.index');
    Route::get('/modules/create', [ModuleController::class, 'create'])->name('modules.create');
    Route::post('/modules', [ModuleController::class, 'store'])->name('modules.store');
    Route::get('/modules/{id}/edit', [ModuleController::class, 'edit'])->name('modules.edit');
    Route::put('/modules/{id}', [ModuleController::class, 'update'])->name('modules.update');
    Route::delete('/modules/{id}', [ModuleController::class, 'destroy'])->name('modules.destroy');
});
NEXT → Étape 11 : Ajouter des données test التالي → الخطوة 11: إضافة بيانات للتجربة

11. Ajouter des données et tester 11. إضافة بيانات وتجربة الدخول

▼

On va créer un compte pour tester. Email : admin@ofppt.ma. Mot de passe : password.

سننشئ حسابا للتجربة. البريد: admin@ofppt.ma. كلمة المرور: password.

📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan make:seeder UserSeeder
php artisan make:seeder ModuleSeeder
📍 Où coller ? → Dans VS Code. Ouvre database/seeders/UserSeeder.php. Ce fichier crée l’utilisateur test. أين نلصق؟ → في VS Code. افتح database/seeders/UserSeeder.php. هذا الملف ينشئ مستخدم التجربة.
<?php

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class UserSeeder extends Seeder
{
    public function run(): void
    {
        User::create([
            'name' => 'Admin OFPPT',
            'email' => 'admin@ofppt.ma',
            'password' => Hash::make('password'),
        ]);
    }
}
📍 Où coller ? → Dans VS Code. Ouvre database/seeders/ModuleSeeder.php. Ce fichier ajoute des modules de test. أين نلصق؟ → في VS Code. افتح database/seeders/ModuleSeeder.php. هذا الملف يضيف وحدات للتجربة.
<?php

namespace Database\Seeders;

use App\Models\Module;
use Illuminate\Database\Seeder;

class ModuleSeeder extends Seeder
{
    public function run(): void
    {
        $modules = [
            ['code' => 'M204', 'nom' => 'Développement front-end', 'coefficient' => 3],
            ['code' => 'M205', 'nom' => 'Développement back-end', 'coefficient' => 3],
            ['code' => 'M203', 'nom' => 'Gestion des données', 'coefficient' => 2],
            ['code' => 'M202', 'nom' => 'Approche agile', 'coefficient' => 2],
            ['code' => 'EGTS202', 'nom' => 'Français', 'coefficient' => 2],
        ];
        foreach ($modules as $m) {
            Module::create($m);
        }
    }
}
📍 Où coller ? → Dans VS Code. Ouvre database/seeders/DatabaseSeeder.php. Ce fichier lance les deux seeders. أين نلصق؟ → في VS Code. افتح database/seeders/DatabaseSeeder.php. هذا الملف يشغل الـ seeders الاثنين.
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            ModuleSeeder::class,
        ]);
    }
}
📍 Où écrire ? → Dans CMD, dans first-app. أين نكتب؟ → في CMD، داخل first-app.
php artisan migrate:fresh --seed
php artisan serve

Ouvre http://127.0.0.1:8000. Connecte-toi. Ajoute un module. Modifie un module. Calcule une note. Puis déconnecte-toi.

افتح http://127.0.0.1:8000. ادخل بالحساب. أضف وحدة. عدل وحدة. احسب نقطة. ثم اخرج.

⚠ Attention : migrate:fresh efface toutes les données. C’est OK pour apprendre sur ton PC. Ne fais pas ça sur un vrai site. ⚠ انتبه: migrate:fresh يمسح كل البيانات. هذا عادي للتعلم في حاسوبك. لا تفعل هذا في موقع حقيقي.
NEXT → Étape 12 : Corriger les erreurs التالي → الخطوة 12: إصلاح الأخطاء

12. Corriger les erreurs simples 12. إصلاح الأخطاء البسيطة

▼
Si tu vois çaإذا رأيت هذا Fais çaافعل هذا
La table n’existe pasالجدول غير موجود php artisan migrate
419 Page Expired Ajoute @csrf dans le formulaireأضف @csrf داخل النموذج
Method Not Allowed @method('PUT') / DELETE
Laravel ne trouve pas layoutLaravel لم يجد layout resources/views/layout.blade.php
notes_modules error protected $table = 'notes_modules';
Le login ne marche pasالدخول لا يعمل php artisan migrate:fresh --seed
SQLSTATE / Access denied (MySQL)SQLSTATE / Access denied (MySQL) Regarde .env. Il faut DB_CONNECTION=mysql. Il faut aussi la base first_app. Démarre MySQL dans XAMPP. Puis lance php artisan config:clearانظر إلى .env. يجب أن يكون DB_CONNECTION=mysql. ويجب أن توجد قاعدة first_app. شغل MySQL في XAMPP. ثم شغل php artisan config:clear
Unknown database 'first_app'Unknown database 'first_app' Crée la base dans phpMyAdmin. Le nom doit être le même que DB_DATABASE.أنشئ القاعدة في phpMyAdmin. يجب أن يكون الاسم مثل DB_DATABASE.
📌 SQLite et MySQL marchent tous les deux. Le code des migrations et des models reste le même. Tu changes seulement .env à l’étape 4. 📌 SQLite و MySQL يعملان معا. كود Migrations و Models يبقى نفسه. تغير فقط .env في الخطوة 4.

Bravo, c’est fini. Tu as une application complète : login, modules, calcul OFPPT. Guide MD : GUIDE-FIRST-APP-LARAVEL.md

أحسنت، انتهينا. لديك تطبيق كامل: دخول، وحدات، حساب OFPPT. الدليل MD: GUIDE-FIRST-APP-LARAVEL.md