تعتمد بنية Laravel كثيرا على مزوّدي الخدمة Service providers لتحميل الأصناف Classes إلى الذاكرة مع بدء عمل التطبيق أو عند الحاجة إليها. يستخدم Laravel حاويةَ خدمة Service container لإدارة الاعتمادات بين الأصناف: ماهي الأصناف التي يعتمد عليها الصّنف الجديد للعمل؟ كيف يمكنه الحصول على كائن من هذه الأصناف؟ أين يوجد الصّنف وهل سبق لإطار العمل تحميلُه إلى الذاكرة؟ تمكننا بإعداد مزوّد خدمة وتعريفه إضافةُ صنف إلى حاويّة الخدمة ممّا يسهّل بالتالي استخدامه؛ إذ سيتعرّف إطار العمل على ما يحتاجه هذا الصّنف (أي الاعتمادات) وينشئه إن لم يكن موجودا سلفا.
سنشرح في هذا الدرس أساسيّات إنشاء مزود خدمة في Laravel.
نبدأ بإنشاء مسار سنستخدمه للتوضيح:
Route::get('/demo', 'DemoController@index');
ثم ننشئ المتحكّم:
php artisan make:controller DemoController
ثم نعرّف الدالة index
في المتحكّم:
public function index() { return view('demo.index'); }
تطلب الدالة index
تقديم العرض demo.index
؛ لذا سننشئ مجلّدا باسم demo
في مجلّد العروض وننشئ فيه عرضا باسم index.blade.php
. نضيف المحتوى التالي للعرض index
:
@extends('layouts.master') @section('content') <h1>Demo Page</h1> @endsection
يمدّد العرض index
عرضا رئيسا باسم master
ضمن مجلّد العروض layouts
. أنشئ العرض الرئيس إن احتجت لذلك.
لم ندخل في صميم الموضوع لحد السّاعة، فقط ضبطنا بعض الإعدادات البدائية. تظهر عند الدخول إلى الرابط demo/
صفحة بها عنوان Demo Page
.
إعداد مزود خدمة
سنشرح في الفقرات المواليّة كيفية إنشاء مزوّد خدمة. نبدأ بإنشاء مجلّد باسم Helpers
في مجلّد app
ثم ننشئ مجلّدا متفرعا عن Helpers
باسم Contracts
؛ بداخل الأخير ننشئ ملفّا باسم RocketShipContract.php
نضيف إليه المحتوى التالي:
<?php namespace App\Helpers\Contracts; Interface RocketShipContract { public function blastOff(); }
لاحظ تعريف الصّنف أعلاه. عرّفنا RocketShipContract
على أنه واجهة Interface. تعرّف الواجهات في PHP (ولغات برمجيّة أخرى) "عقدا" يجب على الأصناف التي تطبّق الواجهة اتّباعه. يجب على الأصناف التي تنفّذ Implement الواجهة المعرَّفة أعلاه أن تحوي دالة عمومية public
باسم blastOff
.
نأتي الآن بعد تعريف الواجهة إلى الصّنف الذي ينفّذها. تحوي الواجهة خطوطا عريضة يأتي الصّنف المنفّذ لتخصيصها. ننشئ صنفا باسم RocketShip.php
في مجلّد Helpers
ونضيف إليه المحتوى التالي:
<?php namespace app\Helpers; use App\Helpers\Contracts\RocketShipContract; class RocketShip implements RocketShipContract { public function blastOff() { return 'Houston, we have ignition'; } }
يمكن أن تعالج في هذا الصّنف الكثير من الأمور، إلا أننا لا نودّ التعقيد. كل ما تفعله هذه الدالة هو إرجاع العبارة Houston, we have ignition
.
عرفنا الواجهة وكيفيةً لتنفيذها. يأتي الآن دور مزوّد الخدمة الذي سننشئه بالأمر التالي:
php artisan make:provider RocketShipServiceProvider
ينشئ الأمر ملفّا باسم RocketShipServiceProvider.php
في المجلّد. تجد عند فتح الملف ما يلي (بعد نزع التعليقات):
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class RocketShipServiceProvider extends ServiceProvider { public function boot() { } public function register() { } }
عدّل على الملف ليصبح على النحو التالي:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use App\Helpers\RocketShip; class RocketShipServiceProvider extends ServiceProvider { protected $defer = true; public function boot() { } public function register() { $this->app->bind('App\Helpers\Contracts\RocketShipContract', function(){ return new RocketShip(); }); } public function provides() { return ['App\Helpers\Contracts\RocketShipContract']; } }
أولى التعديلات هي استدعاء الصّنف RocketShip
:
use App\Helpers\RocketShip;
ثم إضافة الخاصّية التاليّة:
protected $defer = true;
يعني تمكين الخاصيّة defer$
أننا نطلُب ألا يُحمَّل الصّنف إلا عند الضرورة؛ مما يسهِم في الرفع من أداء التطبيق.
ثم يأتي دور الدالة register
التي تربط بين الواجهة والصّنف الذي ينفّذها.
public function register() { $this->app->bind('App\Helpers\Contracts\RocketShipContract', function(){ return new RocketShip(); }); }
يتيح هذا الربط إمكانية استخدام الواجهة في أي مكان تريده وسيستخدم مزوّد الخدمة الصنف الذي تربطه بها في دالة register
تلقائيا. يزيد هذا الإعداد من مرونة التطبيق؛ فكل ما عليك فعله لتغيير سلوك الواجهة هو تعديل الصّنف المربوط بها.
التعديل الأخير هو إضافة الدالة provides
التي تُرجع الواجهة. يجب تعريف هذه الدالة عند تمكين الخاصيّة defer
.
الخطوة الأخيرة من إعداد مزوّد الخدمة هي إضافته إلى ملف إعداد التطبيق config\app.php
ضمن مصفوفة providers
(أدرجنا بعضا من محتويات الملف في الشفرة أدناه، مزوّد الخدمة الخاص بنا هو الأخير):
/* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Providers\RocketShipServiceProvider::class,
استخدام مزود الخدمة
نعود الآن للمتحكّم DemoController
ونعدّل الدالة index
كالتالي:
public function index(RocketShipContract $rocketship) { $boom = $rocketship->blastOff(); return view('demo.index', compact('boom')); }
لا تنس استيراد الواجهة:
use App\Helpers\Contracts\RocketShipContract;
نمرّر للدّالة index
كائنا من الصنف RocketShipContract
(أي الواجهة). سيعرف Laravel تلقائيا أننا نريد الصّنف RocketShip
الذي ينفّذ الواجهة. يعود السبب في ذلك إلى الربط الموجود في مزوّد الخدمة. نمرّر النتيجة المتحصّل عليها من استدعاء blastOff
إلى العرض لتقديمه.
نعدّل العرض لاستخدام المتغيّر الذي ممرناه إليه:
@extends('layouts.master') @section('content') {{ $boom }} @endsection
تظهر العبارة التاليّة في المتصفّح عند زيارة الرابط demo/
:
Houston, we have ignition
سننشئ لتوضيح المرونة التي تتيحها مزودات الخدمة صنفا آخر ينفّذ الواجهة RocketShipContract
. سنسمّي هذا الصنف الجديد RocketLauncher
ونضعه في نفس المجلد الذي يوجد به صنف التنفيذ السابق (Helpers
):
<?php namespace app\Helpers; use App\Helpers\Contracts\RocketShipContract; class RocketLauncher implements RocketShipContract { public function blastOff() { return 'Houston, we have launched!'; } }
لم نغيّر الكثير بالمقارنة مع الصنف RocketShip
السّابق؛ فقط العبارة.
نعود إلى مزوّد الخدمة ونغيّر ربط الواجهة كالتالي:
public function register() { $this->app->bind('App\Helpers\Contracts\RocketShipContract', function(){ return new RocketLauncher(); }); }
دون أن ننسى استدعاء الصّنف:
use App\Helpers\RocketLauncher;
ستلاحظ الآن تغير العبارة الظاهرة في المتصفّح عند زيارة الرابط demo/
.
لم نفعل أمورا معقّدة في الخطوات السّابقة إلا أن بالإمكان رؤية أن التعامل مع الواجهات مباشرة وترك التنفيذ الفعلي للأصناف المربوطة عبر مزوّد الخدمة يضيف الكثير من المرونة إلى بنية التطبيق.
يوجد أمران ينبغي الانتباه إليهما عند التعامل مع مزوّدات الخدمة في Laravel:
-
اجعل إضافة مزوّد الخدمة إلى ملف الإعداد
config/app.php
هي آخر الخطوات؛ بعد تعريف الواجهة ومزوّد الخدمة. إضافة صنف غير موجود إلى ملف الإعداد تؤدي إلى التشويش على عملartisan
. -
من الأفضل حذف مزوّد الخدمة ثم إنشاء واحد جديد بأداة
artisan
؛ بدلا من إعادة تسميّته. قد تؤدي إعادة التسميّة إلى عدم تحميل مزوّد الخدمة فلا يتعرّف عليه التطبيق.
ترجمة -وبتصرّف- للمقال How to Create a Service Provider in Laravel 5.1 لصاحبه Bill Keck.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.