مقدمه‌ای بر ایونت‌ها در لاراول

یکی از امکانات خوبی که لاراول بعنوان یک فریمورک خفن در اختیار شما برنامه نویسان دون‌پایه قرار میده، امکان تعریف ایونت هست. ایونتها کلاسهای ساده ای هستند که با یک تعداد Listener (شنونده؟ گوش به زنگ؟) کار میکنن. ایونتها به شما کمک میکنن تا اکشنهای مختلف یک ماموریت خاص در یک پروژه رو از هم جدا کنید. یعنی چی؟ یعنی یک کاربر میاد و در اپلیکیشن شما ثبت نام میکنه، شما میخواهید یک ایمیل یا یک پیامک حاوی کد تایید بفرستید. تعریف ایونت به شما کمک میکنه که بتونید این عمل ارسال اس ام اس یا ایمیل رو از ماموریت اصلی اون تکه کد که همانا ثبت نام کاربره جدا کنید.


در واقع شما یک ایونت به نام "ثبت نام کاربر" تعریف میکنید که کارش این است که اطلاعات اولیه کاربر رو در دیتابیس ذخیره کنه و منتظر تایید هویت اون آدم از طریق مثلا ارسال اس ام اس باشه. یک Listener هم برای این ایونت تعریف میکنید و بهش میگید آقا جان شما گوش به زنگ باش که هر موقع رویداد ثبت نام کاربر در سیستم اتفاق افتاد، براش یه کد رندوم جنریت کنی و بفرستی.

حالا شاید بپرسید خب کد ارسال sms رو همونجا بیخ کد ثبت نام مینویسیم دیگه چه کاریه. اولا که بیاید سعی کنیم یک متد بیش از یک کار رو در اون لحظه انجام نده، چون کثیف کاری میشه، همه‌ی ما هم تجربه ی کد کثیف نوشتن رو داریم. دوما فرض کنید شما یک رویدادی در سیستم دارید که وقتی اتفاق میفته باید چندین پیامد دیگه داشته باشه. مثلا شما در یک فروشگاه اینترنتی یک سفارشی رو تایید میکنید و بنابراین باید برای کاربر ایمیل، اس ام اس و نوتیفکیشن ارسال بشه. طبیعتا هر کدام از اینها پیاده سازی منحصر به فرد خودشون رو دارن و منطقی نیست همه چیز رو بیخ هم قرار بدیم. پس بهتره یک ایونت تایید سفارش ایجاد کنیم و چند listener مختلف براش تعریف کنیم تا هر کدوم گوش به زنگ باشن که اگر رویداد تایید سفارش اتفاق افتاد، هر کدوم ماموریت خودشون رو انجام بدن.

پس اگر تا اینجا موافقید که استفاده از ایونت ها کار خوبیه، در ادامه نگاهی بندازیم به اینکه چطور باید ایونت ها رو ثبت کرد.

برای ثبت ایونتها و Listener ها، شما باید فایل EventServiceProvider.php رو از مسیر app/Providers باز کنید و اونجا در داخل آرایه‌ی listen$ مسیر تمام ایونت ها و listener های خودتون رو بنویسید:

protected $listen = [
        'App\Events\OrderApproved' => [
                'App\Listeners\SendOrderApprovementNotifications',
         ],
];

شما میتونید هر چند تا ایونت و به ازای هر کدوم هر چند تا listener که خواستید رو بالا در قالب آرایه تعریف کنید. حالا باید دستور پایین رو در ترمینال و در مسیر اصلی پروژه بزنید تا دایرکتوری های ایونت ها و listener ها ساخته بشن و همینطور فایلها ایجاد و به این دایرکتوریها اضافه بشن. توضیح اینکه لاراول به صورت پیشفرض دایرکتوری های Events و Listeners رو نداره و بعد از اجرای دستور زیر اونها ایجاد میشن:

➜  ~ php artisan event:generate

موقعی که دستور بالا رو اجرا کنید، فایل OrderApproved.php در مسیر app/Events و فایل SendOrderApprovementNotifications.php در مسیر app/Listeners ایجاد میشن. اگر فایلها رو باز کنید و نگاهی به داخلشون بندازید میبینید که لاراول زحمت شما رو کم کرده و namespace ها و کلاسهای مرتبط رو خودش برای شما تولید کرده. بدون درد و خونریزی.

هر بار که دستور فوق رو در ترمینال اجرا کنید، لاراول یه نگاه به فایل EventServiceProvider.php میندازه. اگر ایونت یا listener جدیدی به آرایه اضافه شده باشه اونها رو برای شما ایجاد میکنه.

فایل ایونت:

<?php 

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class OrderApproved
{
        use Dispatchable, InteractsWithSockets, SerializesModels;
        /**
        * Create a new event instance.
        *
        * @return void
        */
        public function __construct()
        {
                //
        }
        /**
        * Get the channels the event should broadcast on.
        *
        * @return \Illuminate\Broadcasting\Channel|array
        */
        public function broadcastOn()
        {
                return new PrivateChannel('channel-name');
        }
}

فایل Listener:

<?php

namespace App\Listeners;

use App\Events\OrderApproved;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendOrderApprovementNotifications
{
        /**
        * Create the event listener.
        *       
        * @return void
        */
        public function __construct()
        {
                //
        }
        /**
        * Handle the event.
        *
        * @param  OrderApproved  $event
        * @return void
        */
        public function handle(OrderApproved $event)
        {
               //
        }
}

برای اینکه یک ایونت رو هم به همراه listener هاش اجرا کنید کافیه یک خط کد بنویسید در هر جایی که نیازی به اجرای ایونت داشتید:

event(new OrderApproved());

در مقاله‌ی بعدی در مورد صف ها و اینکه چطور میتونید ایونتهاتون رو برای اجرا در زمانهای مشخص صف بندی کنید خواهم نوشت.