قوالب Blade في Laravel
المتحكم يجهّز البيانات، لكن من يحولها إلى صفحة جميلة يراها الزائر؟ هنا يأتي دور الـ View، حرف V في MVC. و Laravel يكتب صفحاته بنظام قوالب اسمه Blade: HTML عادي، مع رموز بسيطة لعرض البيانات والشروط والحلقات. في هذا الدرس ستتعلم Blade، وستبني قالباً مشتركاً لكل صفحات موقعك.
أين توجد ملفات Blade؟
Section titled “أين توجد ملفات Blade؟”في المجلد resources/views، وامتداد كل ملف .blade.php. وتستدعيها من المسار أو المتحكم بالدالة view، مع البيانات:
return view('greeting', [ 'name' => 'سارة', 'courses' => ['HTML', 'CSS', 'PHP'],]);'greeting'تعني الملفresources/views/greeting.blade.php.- النقطة تعني مجلداً:
'posts.index'هيresources/views/posts/index.blade.php. - كل مفتاح في المصفوفة يصبح متغيراً داخل الصفحة:
$nameو$courses.
عرض المتغيرات
Section titled “عرض المتغيرات”<h1>أهلاً يا {{ $name }}</h1>القوسان المزدوجان {{ }} يطبعان القيمة، مثل <?= ?> في PHP، لكن مع ميزة مهمة جداً: يحميان تلقائياً من XSS. تذكّر من درس النماذج في PHP أنك كنت تكتب htmlspecialchars بنفسك؛ Blade يفعلها لك دائماً:
<p>{{ '<b>نص</b>' }}</p><p>{!! '<b>نص</b>' !!}</p><p><b>نص</b></p><p><b>نص</b></p>{{ }}: آمن، يعرض الرموز كنص. استخدمه دائماً.{!! !!}: يطبع HTML كما هو دون حماية. لا تستخدمه أبداً مع بيانات كتبها المستخدم.
وداخل {{ }} تستطيع كتابة أي تعبير PHP: {{ count($courses) }} أو {{ date('Y') }} أو {{ $price * 2 }}.
الشروط
Section titled “الشروط”بدلاً من <?php if ... ?>، يستخدم Blade توجيهات (Directives) تبدأ بـ @:
@if (count($courses) > 2) <p>أنت تدرس {{ count($courses) }} كورسات، استمر!</p>@else <p>ابدأ كورساً جديداً اليوم.</p>@endifوهناك أيضاً @elseif، و @unless (عكس if)، و @isset للتحقق من وجود متغير.
الحلقات
Section titled “الحلقات”<ul> @foreach ($courses as $course) <li>{{ $loop->iteration }}. {{ $course }}</li> @endforeach</ul>مع البيانات السابقة، هذا هو HTML الناتج (مع الشرط والعنوان):
<h1>أهلاً يا سارة</h1><p>أنت تدرس 3 كورسات، استمر!</p><ul> <li>1. HTML</li> <li>2. CSS</li> <li>3. PHP</li></ul>المتغير $loop هدية من Blade داخل كل حلقة: $loop->iteration رقم الدورة بدءاً من 1، و $loop->first و $loop->last تخبرانك هل هذا أول أو آخر عنصر، و $loop->count عدد العناصر.
وماذا لو كانت القائمة فارغة؟ @forelse تجمع الحلقة مع حالة الفراغ:
@forelse ($posts as $post) <h2>{{ $post->title }}</h2>@empty <p>لا توجد مقالات بعد.</p>@endforelseالقالب الرئيسي: لا تكرر نفسك
Section titled “القالب الرئيسي: لا تكرر نفسك”كل صفحات موقعك تشترك في نفس الهيكل: <head> وقائمة التنقل والتذييل. بدلاً من نسخها في كل صفحة، تكتبها مرة واحدة في قالب رئيسي (Layout):
<!DOCTYPE html><html lang="ar" dir="rtl"><head> <meta charset="UTF-8"> <title>@yield('title') | مدونتي</title></head><body> @include('partials.nav')
<main> @yield('content') </main>
<footer>© {{ date('Y') }} مدونتي</footer></body></html>@yield('content') فراغ يحمل اسماً، ستملؤه كل صفحة بمحتواها الخاص. تخيّل القالب الرئيسي مثل ورقة امتحان مطبوعة فيها رأس المدرسة والتذييل، وفي الوسط مساحات فارغة لكل طالب يكتب فيها إجاباته.
والآن أي صفحة ترث هذا القالب وتملأ فراغاته:
@extends('layouts.app')
@section('title', 'كل المقالات')
@section('content') <h1>كل المقالات</h1>
@forelse ($posts as $post) <article> <h2><a href="{{ route('posts.show', $post->id) }}">{{ $post->title }}</a></h2> </article> @empty <p>لا توجد مقالات بعد.</p> @endforelse@endsection@extends('layouts.app'): هذه الصفحة مبنية على القالب الرئيسي.@section('title', '...'): قيمة قصيرة في سطر واحد.@section('content')…@endsection: محتوى طويل يملأ@yield('content').route('posts.show', $post->id): رابط المسار المسمى، مع تمرير قيمة المعامل{id}.
تضمين الأجزاء: include
Section titled “تضمين الأجزاء: include”الأجزاء التي تتكرر في أماكن مختلفة، مثل قائمة التنقل، نضعها في ملف صغير مستقل:
<nav> <a href="{{ route('posts.index') }}">المقالات</a> <a href="{{ route('posts.create') }}">مقال جديد</a></nav>ونضعها في أي مكان بـ @include('partials.nav')، كما فعلنا في القالب الرئيسي.
جرّب بنفسك
Section titled “جرّب بنفسك”- أنشئ القالب الرئيسي
layouts/app.blade.phpوالجزءpartials/nav.blade.phpكما في الدرس. - أنشئ صفحة
greeting.blade.phpترث القالب، وتعرض اسماً وقائمة كورسات بـ@foreachمع$loop->iteration. - أضف مساراً
/welcome-pageيعرضها مع البيانات. - تحدٍّ: اجعل آخر عنصر في القائمة بخط عريض باستخدام
$loop->last.
أخطاء شائعة
Section titled “أخطاء شائعة”- نسيان .blade في اسم الملف: ملف
greeting.phpلن تعمل فيه رموز Blade. الاسم الصحيحgreeting.blade.php. - استخدام
{!! !!}مع بيانات المستخدم: ثغرة XSS. استخدم{{ }}إلا إذا كنت متأكداً تماماً من مصدر HTML. - نسيان @endif أو @endforeach: يظهر خطأ
syntax error, unexpected end of file. كل توجيه مفتوح يحتاج إغلاقاً.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
ما الفرق بين {{ $x }} و {!! $x !!} في Blade؟
{{ }} يمرر القيمة عبر حماية تلقائية، أما {!! !!} فيطبعها خاماً، وهذا خطير مع بيانات المستخدم.
سؤال
أي توجيه يجعل الصفحة ترث القالب الرئيسي؟
@extends يبني الصفحة على القالب، و @section يملأ فراغات @yield فيه، و @include لتضمين جزء صغير.
الخلاصة
Section titled “الخلاصة”- ملفات Blade في
resources/viewsبامتداد.blade.php، وتُعرض بـview()مع البيانات. {{ }}لعرض القيم بأمان، و{!! !!}للـ HTML الموثوق فقط.@ifو@foreachو@forelseللشروط والحلقات، و$loopيعطيك معلومات الحلقة.- القالب الرئيسي بـ
@yield، والصفحات ترثه بـ@extendsوتملؤه بـ@section. @includeلتضمين الأجزاء المتكررة مثل قائمة التنقل.