قوالب Blade في Laravel

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

مقدمة

يقدم Laravel محرّك قولبةٍ بسيطاً لكن قويٌّ و فعّال هو Blade. على خلاف محرّكات PHP أخرى، لا يمنع Blade المستخدم من استعمال شيفرات PHP في الواجهة، بل إنّه يحوِِّل صفحات Blade إلى شيفرة PHP ويخزِّنها تخزينًا مؤقتًا إلى حين تغييرها. ممّا يعني أنّ Blade لا يتطلب أيّ جهد أو وقت إضافي من التطبيق. تنتهي صفحات Blade بالامتداد blade.php. وتوجد عادة في مجلد resources/views.

توريث القوالب

تعريف التخطيط

إنّ من الفوائد الأساسية لاستخدام Blade هي توريث القوالب (template inheritance) واستخدام الأقسام (sections). في البداية، سنأخذ مثالًا بسيطًا لصفحة master رئيسية. ولمّا كانت معظم تطبيقات الويب تحافظ على تخطيط عام في مختلف الصفحات، فإنَّ من الملائم تعريف هذا التخطيط العامّ في واجهة Blade:

<!--resources/views/layouts/app.blade.php موجودة في-->
<html>

   <head>
       <title>App Name - @yield('title')</title>
   </head>
   <body>
       @section('sidebar')
           This is the master sidebar.
       @show
           @yield('content')

   </body> 
</html>

يمكنك الملاحظة أنّ الكود يحتوي على عناصر HTML التقليدية، لكنّه يحتوي أيضًا على التعليمتين ‎@section و ‎@yield. تُعرِّف التعليمة ‎@section قسمًا أو جزءًا لإضافة المحتوى، بينما تعرض التعليمة ‎@yield محتوى قسم معيّن.

أمّا الآن بعد أن عرّفنا تخطيطًا عامًّا للتطبيق، فسنصنع الصفحات التي سترث هذا التخطيط.

تمديد التخطيط

عند إنشاء واجهة ابن جديدة، تُستخدَم التعليمة ‎@extends لتحديد أي التخطيطات يجب على هذه الواجهة أن ترث. بإمكان الواجهات التي ترث تخطيطًا أن تضيف محتوى لأحد أقسامه باستخدام تعليمات ‎@section. كما رأينا سابقًا، يمكن إظهار هذا المحتوى باستخدام التعليمة ‎@yield.

<!-- resources/views/child.blade.php موجودة في -->

@extends('layouts.app')

@section('title', 'Page Title')

@section('sidebar')

   @parent

<p>يُضاف هذا للقائمة الرئيسية الجانبية.</p>
@endsection

@section('content')

This is my body content.
@endsection

في المثال السابق، يستخدم القسم sidebar التعليمة ‎@parent ليمدد (بدل إعادة تعريف) محتوى القسم في التخطيط. ستُعوَّض التعليمة ‎@parent بمحتواها من التخطيط عند استدعاء الواجهة.

ملاحظة: على عكس المثال الأول، انتهى القسم sidebar هنا بالتعليمة ‎@endsection بدل ‎@show. تُستعمَل التعليمة ‎@endsection للإعلان عن انتهاء قسمٍ ما، بينما تُستعمل ‎@show لإعلان انتهاء قسم وإظهاره مباشرة.

بالإمكان إعادة واجهات Blade مباشرة من صفحة المسارات وذلك باستخدام التابع المساعد العام ‎.show

Route::get('blade', function () {

   return view('child');

});

المكونات والأماكن (Components & Slots)

تُقدِم المكونات و الأماكن فوائد مشابهة لتلك التي تُقدمها الأقسام والتخطيطات و قد يجدها البعض أسهل في الفهم. في البداية. سنبدأ بصناعة مكون قابل لإعادة الاستخدام "alert" لاستخدامه في كامل التطبيق:

<!-- /resources/views/alert.blade.php -->

<div class="alert alert-danger">
    {{ $slot }}
</div>

سوف يتضمّن المتغيّر slot$ المحتوى الذي نريد إضافته إلى المكوّن. أمّا لصناعة المكوّن، يمكن استخدام الموجّه component@:

@component('alert')
   Whoops! Something went wrong!
@endcomponent

في بعض الأحيان، من المفيد تعريف عدّة أماكن (solts) لمكوّن واحد. لنقم على سبيل المثال بتغيير 'alert' التي أنشأناها لتسمح بإضافة 'title'. تُظهَر الأماكن المعنونة عن طريق استعمال متغيّرات تحمل نفس الأسماء:

@component('alert')

   @slot('title')
       Forbidden
   @endslot
   You are not allowed to access this resource!

@endcomponent

تمرير بيانات إضافية للمكونات

قد نحتاج في بعض الأحيان إلى تمرير بيانات إضافية لأحدى المكوّنات، ولهذا بالإمكان تمرير مصفوفة معلومات كمعامل ثاني للتعليمة ‎@component. كل المعلومات المُمَرّرة ستكون متاحة لقالب المكوّن على شكل متغيّرات:

@component('alert', ['foo' => 'bar'])
    ...
@endcomponent

أسماء بديلة للمكوّن

إن كانت المكوّنات محفوظة في ملف داخلي، بالإمكان إعطاؤها أسماءً بديلةً لتسهيل استخدامها. على سبيل المثال، إن كان المكوّن موجودًا في resources/views/components/alert.blade.php فسيكون بالإمكان استخدام التابع component لإعطاء إسم بديل للمكون components.alert ليصبح alert. في العادة يمكن القيام بهذا في التابع boot في صفحة AppServiceProvider

use Illuminate\Support\Facades\Blade;
Blade::component('components.alert','alert');

بعد إعطاء الاسم البديل للمكوّن، يمكن استخدامه عن طريق تعليمة:

@alert(['type' => 'danger'])

   You are not allowed to access this resource!

@endalert

يمكن حذف المعامل إن لم تكن له حاجة:

@alert

   You are not allowed to access this resource!

@endalert

إظهار البيانات

يمكن إظهار البيانات المُمرّرة إلى الواجهة عن طريق إحاطة المتغيّرة بأقواس معقوفة. على سبيل المثال، لدينا المسار التالي:

Route::get('greeting', function () {

   return view('welcome', ['name' => 'Samantha']);

});

يُعرَض محتوى المتغيّر name كما يلي:

Hello, {{ $name }}

بالطبع لستَ محدودًا بإظهار محتوى المتغيّرات المُمرّرة للواجهة، بل يمكن أيًضا إظهار نتائج دوال PHP، بل يمكن وضع أي كود PHP

The current UNIX timestamp is {{ time() }}

ملاحظة: ستُمرَّر محتويات الأقواس المعقوفة {{ }} تلقائيًا إلى دالة htmlspecialchars PHP للحد من هجمات XSS.

عرض البيانات غير المهرّبة

في العادة، ستُمرَّر بيانات الأقواس المعقّفة إلى الدالة htmlspecialchars للحد من هجمات XSS. إن أردت أن تكون البيانات مهربةً (escaped) ، فيمكن استعمال التركيب التالي:

Hello, {!! $name !!}

كن حذرًا عند عرض بيانات مقدّمة من المستخدم! استخدم دائمًا البيانات المُهرَّبة بين أقواس معقوفة للحد من الهجمات.

عرض صيغة JSON

في بعض الأحيان، قد نمرّر مصفوفة بيانات بُغية عرضها على هيئة صيغة JSON لتعريف متغير JavaScript. على سبيل المثال:

<script>

   var app = <?php echo json_encode($array); ?>;

</script>

لكن عوض استخدام الدالة json_encode، يمكن استخدام التعليمة ‎@json:

<script>

   var app = @json($array);

</script>

ترميز كائن HTML

في الحالة العاديّة، blade [والمساعد e بصفة أخص] يرمِّز كائنات HTML بصفة مضاعفة. إن أردت إيقاف الترميز المضاعف يمكنك استدعاء التابع Blade::withoutDoubleEncoding من التابع boot في الصفحة AppServiceProvider:

<?php

namespace App\Providers;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider {

   /**
    * .التمهيد لخدمات التطبيق
    *
    * @return void
    */
   public function boot()
   {
       Blade::withoutDoubleEncoding();
   }

}

استعمال Blade مع إطارات JavaScript

لمّا كانت العديد من إطارات JavaScript تستعمل الأقواس المعقوفة للتعبير على أن جملة معيّنة يجب أن تظهر في المتصفح، يمكن استخدام الرمز @ لإعلام محرّك الإظهار في Blade بأن الجملة يجب أن تبقى كما هي دون تغيير:

<h1>Laravel</h1>

Hello, @{{ name }}.

في هذا المثال، سيحذف blade الرمز @ لكنه سيبقي على الجملة {{name}} كما هي ممّا سيسمح لها بأن تُعالَج في إطار JavaScript الذي تستخدمه.

التعليمة ‎@verbatim

إن كنت تعرض متغيرات JavaScript في قسم كبير من الشيفرة يمكنك إحاطة شيفرة HTML بالتعليمة ‎@verbatim حتّى لا تضطر لإسباق كل تعليمة عرض بالرمز @:

@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim

بنى التحكم

بالإضافة لتوريث القوالب وعرض البيانات يُقدّم Blade اختصارات مفيدة لبنى تحكّم PHP الشائعة مثل عبارات التحكّم وحلقات التكرار. هذه الاختصارات توفّر طريقة سهلة ومقتضبة لاستخدام بنى التحكّم في حين تبقى مألوفةً ومشابهةً لنظيراتها من تعابير PHP.

العبارة if

يمكنك صياغة البنية if باستخدام التعليمات ‎@if، و ‎@elseif، و ‎@else، و ‎@endif. هذه التعليمات تعمل تمامًا مثل نظيراتها في PHP.

@if (count($records) === 1)

   I have one record!

@elseif (count($records) > 1)

   I have multiple records!

@else

   I don't have any records!

@endif

يُوفِّر Blade الموجّه ‎@unless كوسيلة لتسهيل الاستخدام:

@unless (Auth::check())

   You are not signed in.

@endunless

إضافة للموجّهات الشَّرطية التي ذكرناها، يُوفّر Blade التعليمتين ‎@isset و‎@empty كاختصارين لنظيريهما من دوال PHP:

@isset($records)
  // معرّف وذو قيمة $records
@endisset

@empty($records)
 // "empty" أصبح $records
@endempt

تعليمات الاستيثاق

تُستخدم التعليمات ‎@auth و ‎@guest للتحقّق بسرعة من إذا ما كان المستخدم مسجلًا الدخول أو كان زائرًا:

@auth

  // ...هذا المستخدم مسجّل الدخول
@endauth

@guest

  // ...هذا المستخدم غير مسجّل الدخول
@endguest

إذا لزم الأمر، يمكن استخدام حارس الاستيثاق (authentication guard) والذي يجب التحقق منه عند استعمال إحدى التعليمتين ‎@auth أو ‎@guest:

@auth('admin')

  // ...هذا المستخدم مسجّل الدخول

@endauth

@guest('admin')

  // ...هذا المستخدم غير مسجّل الدخول

@endguest

تعليمات الأقسام

يمكن التحقّق إذا كان القسم به محتوى أم لا باستخدام التعليمة ‎@hassection:

@hasSection('navigation')
    <div class="pull-right">
        @yield('navigation')
    </div>

    <div class="clearfix"></div>
@endif

العبارة switch

تُصاغ البنية switch باستخدام الموجّهات ‎@switch، و ‎@case، و ‎@break، و ‎@default، و ‎@endswitch:

@switch($i)
   @case(1)
       First case...
       @break
   @case(2)
       Second case...
       @break
   @default
       Default case...

@endswitch

الحلْقات

بالإضافة للعبارات الشَّرطية، يوفِّر Blade تعليمات بسيطة للعمل مع بنى PHP الحلقيّة. تعمل هذه التعليمات بطريقة مشابهة لنظيرتها في PHP:

@for ($i = 0; $i < 10; $i++)
    The current value is {{ $i }}
@endfor

@foreach ($users as $user)
    <p>This is user {{ $user->id }}</p>
@endforeach

@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>No users</p>
@endforelse

@while (true)
    <p>I'm looping forever.</p>
@endwhile

ملاحظة: عند استخدام البنى الحلقية، يمكن استخدام المتغيّرات الحلقية لكسب معلومات مهمة عن الحلقات، كمعلومات عن عدد التكرار في الحلقة.

عند استخدام الحلقات يمكن إنهاء الحلقة أو تجاوز التكرار الجاري:

@foreach ($users as $user)

   @if ($user->type == 1)
       @continue
   @endif
{{$user->name }}
   @if ($user->number == 5)
       @break
   @endif

@endforeach

يمكن إضافة عبارة شرطية مع التعليمة في نفس السطر:

@foreach ($users as $user)

   @continue($user->type == 1)
    <li>{{ $user->name }}</li>
   @break($user->number == 5)

@endforeach

المتغيّر loop

عند استخدام العبارات الحلقية، يُنشَأ المتغيّر ‎$loop ويكون جاهزًا للاستخدام. يوفّر هذا المتغيّر عدّة معلومات مفيدة مثل إن كان التكرار الحالي الأول أو الأخير في الحلقة:

@foreach ($users as $user)

   @if ($loop->first)
       This is the first iteration.
   @endif
   @if ($loop->last)
       This is the last iteration.
   @endif

This is user {{$user->id }}

@endforeach

عندما تكون في حلقات متداخلة كليًا، يمكن الولوج للمتغيّر ‎$loop الخاصّ بالحلقة الأم أو الحلقة الخارجية باستخدام الخاصّية parent:

@foreach ($users as $user)

   @foreach ($user->posts as $post)
       @if ($loop->parent->first)
           This is first iteration of the parent loop.
       @endif
   @endforeach

@endforeach

المتغيّر ‎$loop يحتوي أيضًا على عدّة خاصيات أخرى مفيدة:

الخاصّية التعريف
loop->index$ فهرس حلقة التكرار الحالية (يبدأ من 0).
loop->iteration$ حلقة التكرار الحالية (تبدأ من 1).
loop->remaining$ عدد حلقات التكرار المتبقية.
loop->count$ العدد الكلّي للعناصر في مصفوفة المعلومات المكرّرة.
loop->first$ إن كانت حلقة التكرار الحاليّة هي الأولى أم لا.
loop->last$ إن كانت حلقة التكرار الحالية هي الأخيرة أم لا.
loop->depth$ عمق التداخل في الحلقة الحالية.
loop->parent$ في حالة الحلقات المتداخلة، المتغيّر ‎$loop للحلقة الأم.

التعليقات

يسمح Blade بإضافة تعليقات في الواجهات. على عكس تعليقات HTML، فإن تعليقات Blade ليست مُضمّنة في شيفرة HTML الناتج من التطبيق:

{{-- هذا التعليق لن يظهر في الصفحة النهائية HTML --}}

PHP

من المفيد في بعض الأحيان تضمين كود PHP في الواجهة. يمكن استخدام الموجّه php@ لتنفيذ مقطع من كود PHP في القالب:

@php

  //

@endphp

ملاحظة: رغم أنّ Blade يوفّر هذه الخاصّية إلّا أنّ الإكثار من استخدامها يعني أن القالب يحتوي على الكثير من التحليل المنطقي.

تضمين الواجهات الفرعية

تسمح التعليمة ‎@include بتضمين واجهة في واجهة أخرى. كل المتغيّرات المتاحة للواجهة الأم متاحة أيضًا للواجهة المضمّنة:

<div>
    @include('shared.errors')

    <form>
        <!-- Form محتويات قسم -->
    </form>
</div>

بالإضافة إلى أنها سترث كل بيانات الواجهة الأم، يمكن أيضا تمرير مصفوفة بيانات إضافية إلى الواجهة المضمّنة:

@include('view.name', ['some' => 'data'])

بالطبع إذا ضمّنت واجهة غير موجودة سيصدر Laravel خطأً. إذا أردت تضمين واجهة لست متأكدًا من وجودها، يمكنك استخدام التعليمة ‎@includeif:

@includeWhen($boolean, 'view.name', ['some' => 'data'])

لتضمين الواجهة الأولى الموجودة من مصفوفة واجهات، يمكن استخدام التعليمة ‎@includeFirst:

@includeFirst(['custom.admin', 'admin'], ['some' => 'data'])

تحذير: من المفضّل تجنّب استخدام الثّوابت _DIR_ و _FILE_ في الواجهات لأنها تشير إلى أماكن وجود الواجهات المترجمة والمخزّنة مؤقتًا.

إظهار الواجهات في المجموعات

بالإمكان دمج التضمين و الحلقات في سطر واحد باستخدام التعليمة each@:

@each('view.name', $jobs, 'job')

المعامل الأول هو الواجهة الجزئية التي ستُظهَر لكل عنصر من المصفوفة أو المجموعة.

المعامل الثاني هو المجموعة أو المصفوفة التي ستُكرَّر بينما المعامل الثالث هو اسم المتغيّر التي سيخصّص لحلقة التكرار الحالية في الواجهة. فعلى سبيل المثال، إن كنت تقوم بالتكرار في مصفوفة أعمال jobs، عادة ستصل إلى كل عمل عن طريق متغيّر job في الواجهة الجزئية. يكون المفتاح لحلقة التكرار الحالية متاحا في المتغيّر key من الواجهة الجزئية.

يمكن أيضًا تمرير معامل رابع للتعليمة ‎@each. يحدّد هذا المعامل الواجهة التي يجب إظهارها في حال كانت المصفوفة الممرّرة فارغة:

@each('view.name', $jobs, 'job', 'view.empty')

ملاحظة: الواجهات المُظهَرة باستخدام التعليمة ‎@each ترث متغيّرات الواجهة الأم. إن كانت المتغيّرات إجباريةً في الواجهة اابن، فيجب استخدام الموجّه ‎@foreach و ‎@include بدًلا عن each@.

المكادس (Stacks)

يسمح Blade باستخدام مكادس (stacks) التي يمكن إظهارها في أماكن أخرى في الواجهات أو التخطيطات. يكون هذا مفيدًا في حالة تعريف مكتبة JavaScript ضرورية للواجهات الأبناء:

@push('scripts')

   <script src="/example.js"></script>

@endpush

يمكنك الدفع إلى المكدس مرّات عديدة ثمّ لإظهار محتوى المكدس الكامل، يُمرَّر اسم المكدس كمعامل للتعليمة ‎@stack:

<head>
    <!-- Head محتويات قسم -->

    @stack('scripts')
</head>

إذا أردت إضافة محتوى لبداية المكدس، يمكن استعمال التعليمة ‎@prepend:

@push('scripts')

   This will be second...

@endpush

// لاحقا
@prepend('scripts')

  This will be first...

@endprepend

حقن الخدمات (Service Injection)

تُستخدَم التعليمة ‎@inject لجلب خدمة من حاوية الخدمات. المعامل الأول المُمرَّر للتعيمة هو اسم المتغيّر التي سيحتوي الخدمة بينما المعامل الثاني هو اسم الصنف أو الواجهة للخدمة:

@inject('metrics', 'App\Services\MetricsService')

<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>

تمديد Blade

يسمح Blade بتعريف تعليمات خاصّة باستعمال التابع directive. عندما يلاقي معالج Blade تعليمات خاصّة فإنّه سينجز دالة رد النداء (callback) بالتعبير الذي تحتويه التعليمة. سنُنشِئ في المثال التالي تعليمةً ‎@datetime($var)‎ التي تقبل المعامل var$ كنسخة من الصنف DateTime:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * .تحميل أوّلي لتسجيل الخدمات
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('datetime', function ($expression) {
            return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
        });
    }

    /**
     * .تسجيل الارتباطات في الحاوية
     *
     * @return void
     */
    public function register()
    {
       //
    }
}

كما في المثال السابق، يُربَط التابع format بأي عبارة مُمرَّرة للتعليمة. لذا فإنّ النتيجة المُولَّدة من التعليمة هي:

<?php echo ($var)->format('m/d/Y H:i'); ?>

ملاحظة: بعد تغيير طريقة عمل التعليمة يجب حذف الواجهات المخزّنة مؤقتًا عن طريق أمر artisan التالي:

view:clear

تخصيص العبارات الشرطية

تعريف موجّهات مخصّصة أكثر تعقيدًا بكثير من تعريف عبارات شرطيّة مخصّصة. لهذا يُوفّر Blade التابع Blade::if للتعريف السريع لتعليمات شرطية مخصصة. على سبيل المثال، لنصنع تعليمةً شرطيةً تتثبّت من البيئة الحالية للتطبيق. يمكن وضع التعريف في التابع boot في AppServiceProvider:

use Illuminate\Support\Facades\Blade;

/**

* .تحميل أوّلي لتسجيل الخدمات
*
* @return void
*/

public function boot() {

   Blade::if('env', function ($environment) {
       return app()->environment($environment);
   });

}

بعد التعريف، يمكن استعمال الصيغة الشرطية المخصوصة بسهولة في باقي القالب:

@env('local')

  // ...التطبيق في البيئة المحلية
@elseenv('testing')

  // ...التطبيق في بيئةالاختبار
@else

  // ...التطبيق ليس في البيئة المحلية وليس في بيئة الاختبار
@endenv

مصادر