تخطَّ إلى المحتوى

قوالب Blade في Laravel

الدرس 4 من 11 · Laravel

المتحكم يجهّز البيانات، لكن من يحولها إلى صفحة جميلة يراها الزائر؟ هنا يأتي دور الـ View، حرف V في MVC. و Laravel يكتب صفحاته بنظام قوالب اسمه Blade: HTML عادي، مع رموز بسيطة لعرض البيانات والشروط والحلقات. في هذا الدرس ستتعلم 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.
resources/views/greeting.blade.php
<h1>أهلاً يا {{ $name }}</h1>

القوسان المزدوجان {{ }} يطبعان القيمة، مثل <?= ?> في PHP، لكن مع ميزة مهمة جداً: يحميان تلقائياً من XSS. تذكّر من درس النماذج في PHP أنك كنت تكتب htmlspecialchars بنفسك؛ Blade يفعلها لك دائماً:

<p>{{ '<b>نص</b>' }}</p>
<p>{!! '<b>نص</b>' !!}</p>
الناتج
<p>&lt;b&gt;نص&lt;/b&gt;</p>
<p><b>نص</b></p>
  • {{ }}: آمن، يعرض الرموز كنص. استخدمه دائماً.
  • {!! !!}: يطبع HTML كما هو دون حماية. لا تستخدمه أبداً مع بيانات كتبها المستخدم.

وداخل {{ }} تستطيع كتابة أي تعبير PHP: {{ count($courses) }} أو {{ date('Y') }} أو {{ $price * 2 }}.

بدلاً من <?php if ... ?>، يستخدم Blade توجيهات (Directives) تبدأ بـ @:

@if (count($courses) > 2)
<p>أنت تدرس {{ count($courses) }} كورسات، استمر!</p>
@else
<p>ابدأ كورساً جديداً اليوم.</p>
@endif

وهناك أيضاً @elseif، و @unless (عكس if)، و @isset للتحقق من وجود متغير.

<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):

resources/views/layouts/app.blade.php
<!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') فراغ يحمل اسماً، ستملؤه كل صفحة بمحتواها الخاص. تخيّل القالب الرئيسي مثل ورقة امتحان مطبوعة فيها رأس المدرسة والتذييل، وفي الوسط مساحات فارغة لكل طالب يكتب فيها إجاباته.

والآن أي صفحة ترث هذا القالب وتملأ فراغاته:

resources/views/posts/index.blade.php
@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}.

الأجزاء التي تتكرر في أماكن مختلفة، مثل قائمة التنقل، نضعها في ملف صغير مستقل:

resources/views/partials/nav.blade.php
<nav>
<a href="{{ route('posts.index') }}">المقالات</a>
<a href="{{ route('posts.create') }}">مقال جديد</a>
</nav>

ونضعها في أي مكان بـ @include('partials.nav')، كما فعلنا في القالب الرئيسي.

  1. أنشئ القالب الرئيسي layouts/app.blade.php والجزء partials/nav.blade.php كما في الدرس.
  2. أنشئ صفحة greeting.blade.php ترث القالب، وتعرض اسماً وقائمة كورسات بـ @foreach مع $loop->iteration.
  3. أضف مساراً /welcome-page يعرضها مع البيانات.
  4. تحدٍّ: اجعل آخر عنصر في القائمة بخط عريض باستخدام $loop->last.
  • نسيان .blade في اسم الملف: ملف greeting.php لن تعمل فيه رموز Blade. الاسم الصحيح greeting.blade.php.
  • استخدام {!! !!} مع بيانات المستخدم: ثغرة XSS. استخدم {{ }} إلا إذا كنت متأكداً تماماً من مصدر HTML.
  • نسيان @endif أو @endforeach: يظهر خطأ syntax error, unexpected end of file. كل توجيه مفتوح يحتاج إغلاقاً.

سؤال

ما الفرق بين {{ $x }} و {!! $x !!} في Blade؟

سؤال

أي توجيه يجعل الصفحة ترث القالب الرئيسي؟

  • ملفات Blade في resources/views بامتداد .blade.php، وتُعرض بـ view() مع البيانات.
  • {{ }} لعرض القيم بأمان، و {!! !!} للـ HTML الموثوق فقط.
  • @if و @foreach و @forelse للشروط والحلقات، و $loop يعطيك معلومات الحلقة.
  • القالب الرئيسي بـ @yield، والصفحات ترثه بـ @extends وتملؤه بـ @section.
  • @include لتضمين الأجزاء المتكررة مثل قائمة التنقل.