الأحداث Events هي إجراءات يمكن لبرنامج التعرّف عليها ومن ثمّ التعامل معها. يمكن أن نأخذ مثالا على ذاك عملية تسجيل مستخدم في الموقع. عندما يكمل زائر ملء حقول الاستمارة الخاصّة بالتسجيل في موقع فإنه يكون قد فعّل حدثا يمكننا تسميّته "التسجيل في الموقع"؛ نستطيع بعد ذلك التعامل مع هذا الحدث لنقرّر ما التالي.
كانت الطريقة القديمة تقضي بكتابة شفرة برمجية مباشرةً في المتحكّم Controller للتعامل مع الحدث؛ إلا أن توسّع التطبيق وزيادة الحاجة للتعامل مع أحداث جديدة يجعل الحاجة أكبر لطريقة جديدة أنظف وأكثر قابلية للتمديد. يستجيب Laravel لهذه الحاجة بالصنف Event والأدوات المساعدة المتعلّقة به.
لا تقتصر الأحداث على إرسال البريد؛ إلا أن هذا الأخير وسيلة سهلة لشرح المبدأ. سنرى في هذا الدرس الخطوات اللازمة لتعريف حدث واستخدامه.
نفترض أن لدينا جدولا ببيانات الاتصال ببعض الأشخاص؛ ونريد أن نرسل لأحدهم بريدا في كل مرة يُعرَض فيها الرابط contacthandler/id/
حيث id
معرّف من نرسل له البريد.
سنستخدم في هذا الجدول نفس المشروع الذي أنشأناه في الدرس السابق ونزيد عليه بإنشاء نموذج Model وجدول بيانات لحفظ جهات الاتّصال.
تهيئة المشروع
لا تدخل الخطوات الواردة في هذا العنوان في صميم إدارة الأحداث في Laravel؛ إلا أننا سنحتاجها للحصول على نتيجة مرئية للمثال الذي نبنيه. سنمرّ على الخطوات دون الكثير من التفاصيل لورودها في دروس سابقة.
إنشاء النموذج Contact
ننفذ الأمر التالي في مجلّد المشروع لإنشاء نموذج باسم Contact
مع ملف التهجير الخاصّ به:
php artisan make:model Contact -m
نعدّل ملف التهجيرعلى النحو التالي:
public function up() { Schema::create('contacts', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('subject'); $table->text('body'); $table->timestamps(); }); }
أضفنا الحقول التي نريد استخدامها في جدول البيانات. ننفذ أمر التهجير لإنشاء الجدول:
php artisan migrate
بذر البيانات
سنحتاج لبيانات اتصّال للتجربة عليها. نستخدم معمل نماذج Model factory لبذر الجدول contacts
. ننشئ ملفا باسم ContactFactory.php
في المسار /app/factories
ونضيف إليه المحتوى التالي:
<?php $factory->define(App\Contact::class, function (Faker\Generator $faker){ return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'subject' => $faker->word, 'body' => $faker->text ]; });
يستدعي معمل النماذج مكتبة Faker لإدراج بيانات في جدول contacts
عبر النموذج Contact
.
ثم ننشئ صنفا للبذر:
php artisan make:seeder ContactTableSeeder
نستورد النموذج Contact
في صنف البذر ContactTableSeeder
ونستخدم معمل النماذج لتوليد بيانات عشوائية:
<?php use Illuminate\Database\Seeder; use App\Contact; class ContactTableSeeder extends Seeder { public function run() { Contact::truncate(); factory(Contact::class, 50)->create(); } }
نأتي الآن للخطوة الأخيرة قبل تنفيذ أمر البذر وهي تحرير الملف DataBaseSeeder.php
ليستدعي الصّنف ContactTableSeeder
في الدالة run
:
$this->call(ContactTableSeeder::class);
ثم ننفذ البذر:
php artisan db:seed
المسار والمتحكم
نفتح ملف routes.php
لإضافة مسار للرابط contacthandler/id/
:
Route::get('/contacthandler/{id}', 'HomeController@contactHandler');
يحيل ملف المسارات الطلب على الرابط إلى الدالة contacthandler
في المتحكّم HomeController
. نذهب للمتحكم ونضيف هذه الدالة:
public function contactHandler($id) { }
نترك الدالة خاوية لحد الساعة.
التعامل مع الأحداث
جهزنا المشروع ويمكننا الآن الانتقال إلى الأحداث والتعامل معها. نذكّر بأننا نريد إرسال بريد لصاحب جهة الاتصال عند طلب رابط به معرّفه. مثلا نرسل بريدا إلى جهة الاتصال ذات المعرّف 6
عند زيارة يُعرَض فيها الرابط contacthandler/6/
. نحصُل على البريد الإلكتروني الذي سنرسل إليه الرسالة من خلال النموذج Contact
؛ إضافة لاسمه وموضوع الرسالة وفحواها. ولدنا هذه البيانات تلقائيا أثناء البذر السابق.
تعريف الحدث
يتلخّص الأمر في أننا سننفّذ إجراءً عند وقوع الحدث "زيارة رابط المعرّف الخاص بجهة الاتصال". سنسميّ الصنف الموافق للحدث بـ ContactHandlerAction
. نستعين بأداة artisan
لإنشاء الحدث على النحو التالي:
php artisan make:event ContactHandlerAction
ستجد أن الأداة أنشأت الملف ContactHandlerAction.php
على المسار app/Events
وأضافت إليه المحتوى التالي (بعد نزع التعليقات):
class ContactHandlerAction extends Event { use SerializesModels; public function __construct() { } public function broadcastOn() { return []; } }
سنضيف خاصيّة إلى الصّنف ليصبح كالتالي:
class ContactHandlerAction extends Event { use SerializesModels; public $contact; public function __construct($contact) { $this->contact = $contact; } public function broadcastOn() { return []; } }
أضفنا متغيّرا جديدا لحفظ بيانات الاتصال واستخدامها عند الحاجة.
نعود لدالّة contactHandler
في المتحكّم HomeController
ونعدّلها لتصبح كما يلي:
public function contactHandler($id) { $contact = Contact::find($id); event (new ContactHandlerAction($contact)); return view('mail.success_view'); }
نحتاج لاستيراد الصنفين المستخدمين في الدالة (النموذج والحدث) إلى المتحكّم:
use App\Contact; use App\Events\ContactHandlerAction;
عند استدعاء الدالة contactHandler
نأخذ المعطى id
المُمرَّر في الرابط ونحيله إلى الدالة find
في النموذج Contact
من أجل العثور عليه في قاعدة البيانات.
في التعليمة التالية يبدأ عمل آلية إدارة الأحداث في Laravel: نستدعي الدالة المساعدة event
ونمرّر لها كائنا من الحدث ContactHandlerAction
الذي أنشأناه قبل قليل. نستخدم جهة الاتصال التي عثرنا عليها contact$
من أجل بناء الحدث. يعني هذا أننا أطلقنا الحدث “زيارة رابط المعرّف الخاص بجهة الاتصال” وزوّدناه بجهة الاتصال المعنيّة. مالذي يترتّب عن إطلاق الحدث؟ هذا هو ما سنراه الآن.
التعامل مع الحدث
توجد في Laravel ما تُعرَف بالمستمعات Listeners ومهمتها انتظار وقوع أحداث لتبدأ عملها. نعود لأداة artisan
وننفّذ الأمر التالي:
php artisan make:listener EmailContactListener --event="ContactHandlerAction"
ينشئ الأمر صنفا باسم EmailContactListener
للاستماع للأحداث ContactHandlerAction
. يوجد الصّنف EmailContactListener
في المجلّد /app/Listeners
ومحتواه التالي:
class EmailContactListener { public function __construct() { // } public function handle(ContactHandlerAction $event) { // } }
لاحظ أن الدالة handle
تنتظر معطى من نوع ContactHandlerAction
. يشغّل المستمِع الدالة handle
بعد تلقيه إخطارا بإطلاق الحدث ContactHandlerAction
. سنعود بعد قليل للدالة handle
بعد أن نعرّف الآلية التي سيُخطَر بها المستمِع بوقوع الحدث.
ربط الحدث بآلية التعامل معه
يوفّر Laravel مزوّد خدمة خاصًّا بالأحداث اسمه EventServiceProvider
يوجد في المجلّد /app/Providers
. إن فتحت الملف EventServiceProvider.php
ستجد التالي (إن لم يسبق لأحد التعديل عليه):
class EventServiceProvider extends ServiceProvider { protected $listen = [ 'App\Events\ContactHandlerAction' => [ 'App\Listeners\EmailContactListener', ], ]; public function boot(DispatcherContract $events) { parent::boot($events); // } }
ما يهمّنا هنا هو الخاصيّة listen$
. نعدّلها لتصبح على النحو التالي:
protected $listen = [ 'App\Events\ContactHandlerAction' => [ 'App\Listeners\EmailContactListener', ], ];
يمكن تعريف أكثر من مستمِع لنفس الحدث (لاحظ أن قيمة App\Events\ContactHandlerAction
في الخاصيّة هي مصفوفة Array).
تمكننا الآن العودة إلى المنصِت بعد أن أعلمنا Laravel بالرابط بينه والحدث.
تنفيذ آلية التعامل مع الحدث
نعدّل الدالة handle
لتصبح على النحو التالي:
public function handle(ContactHandlerAction $event) { $data = [ 'name' => $event->contact->name, 'email' => $event->contact->email, 'subject' => $event->contact->subject, 'body' => $event->contact->body ]; Mail::send('mail.email_view',$data , function($message) use($data) { $message->from('hsoub@academy.com', 'Hsoub Academy'); $message->to($data['email'])->subject($data['subject']); }); if (Mail::failures()){ throw new EmailSendingException; } }
نعرّف مصفوفةً باسم data$
تحوي اسم جهة الاتصال، بريدها الإلكتروني، موضوع الرسالة وفحواها. نعثُر على هذه البيانات من الكائن contact
الذي مررناه للحدث event
عند زيارة الرابط. نستخدم هذه البيانات لجدولة إرسال بريد عبر الدالة Mail::send
. تأخذ الدالة Mail::send
عرضا View تستخدمه لتنسيق الرسالة والبيانات التي أخذناها من جهة الاتصال. ثم نختبر أخطاء إرسال البريد الإلكتروني بالدالة Mail::failures
؛ فإن وجدت أخطاء استخدمنا استثناءً Exception مخصّصًا لمعالجتها. يمكنك الحصول على هذا الاستثناء في الملف المرفق أو مراجعة الدرس الخاص بالاستثناءات.
نحن الآن جاهزون تقريبا لتجربة الأحداث والتعامل معها في Laravel. بقي لنا إنشاء بضعة عروض لحاجات تطبيقنا المختلفة: mail.success_view
في المتحكّم، mail.email_view
لتنسيق الرسالة، إضافة لعروض أخرى قد تحتاجها أثناء تخصيص الاستثناء. يمكنك الحصول عليها في الملف المرفق.
بقيت لنا خطوة أخيرة قبل اختبار التطبيق: إعداد Laravel لإرسال البريد. يوفّر Laravel وسيلة لمحاكاة إرسال البريد يمكننا استخدامها للتجربة. ابحث في ملف متغيّرات النظام env.
عن المعطى MAIL_DRIVER
وعيّن قيمته بـlog
:
MAIL_DRIVER=log
نطلُب بهذه الطريقة من Laravel كتابة البريد في ملفّ السجل بدلا من إرساله. هذه الطريقة مفيدة أثناء الاختبار.
افتح الرابط التالي في المتصفّح (ضع اسم المضيف المناسب بدلا من laraveltips
):
http://laraveltips.dev/contacthandler/45
ملحوظة: لا يتعدّى عدد جهات الاتصال التي أضفناها الخمسين؛ سيؤدي البحث عن جهة اتصال بمعرّف أكبر من 50
إلى خطأ يمكنك التقاطه في استثناء كما فعلنا في درس استخدام الاستثناءات Exceptions المخصَّصة في Laravel.
ثم اذهب إلى ملف السجل storage/logs/laravel.log
للتأكد من نجاح معالجة الحدث؛ ستجد في آخر الملف ما يشبه التالي:
[2016-03-30 22:16:29] local.DEBUG: Message-ID: <8c79163440df2d3b5bbb3efd97ad549f@laraveltips.dev> Date: Wed, 30 Mar 2016 22:16:29 +0000 Subject: distinctio From: Hsoub Academy <hsoub@academy.com> To: fFranecki@example.net MIME-Version: 1.0 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
يليه محتوى العرض المستخدم لتنسيق الرسالة (mail.email_view
في المثال). إن حدثت مشكلة في إرسال البريد فسيتولّى الاستثناء -إن أعددتَه - إظهار العرض المناسب للزائر؛ وفي حال سريان الأمور على الوجه الأمثل فسيُظهر المتحكّم العرض mail.success_view
للدلالة على نجاح الإرسال.
الملف المرفق: الأحداث في Laravel.zip
ترجمة -وبتصرّف- للمقال Eventing in Laravel 5.1 لصاحبه Bill Keck.
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.