تعداد بازدید: 4626

Event Listeners

event ها در زمان وقایع مختلف می توانند fire شوند و به دنبال آن ها یک یا چند Listener اجرا می گردند. پس event و Listener دو مفهوم مجزا در قالب یک ماژول امکانی را برای ما فراهم می کند که در زمان های خاص کارهای خاص انجام شود.

مثلا در زمان ساخته شدن یک محصول ایمیل به ادمین فرستاده می شود. که در این رابطه event واقعه ساخت محصول است و Listener ایمیلی است که به ادمین فرستاده می شود.

نکته : رابطه معنایی نزدیکی میان Event ها در لاراول و Hook ها در وردپرس وجود دارد. به طور مثال در زمان ذخیره پست (add_action => save_post) می توان تابعی با پارامتر های خاص عمل کند. همین روال را می توان در لاراول با استفاده از Event ها انجام داد.

EventServiceProvider

به طور مثال ما قصد داریم که در زمان ساخت محصول جدید (ProductCreated) دو عمل ارسال ایمیل (SendMail) و ارسال پیامک (SendSMS) را انجام دهیم.

در مسیر app/Events و app/Listeners می توان event , listeners را مشاهده کرد. برای ساخت Event و همچنین Listener های مربوط به آن باید به EventServiceProvider.php مراجعه کنید و در آن Event و Listeners را تعبیه کنید.

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'App\Events\ProductCreated' => [
            'App\Listeners\sendMail',
            'App\Listeners\sendSms'
        ]
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        //
    }
}

در کلاس بالا در متغیر $listen ما یک آرایه داریم که کلید آن Event و مقدادیر آن Listeners می باشند. این مقادیر در حال حاضر وجود ندارند ولی باید به نام پوشه ها دقت فرمایید . Events , Listeners .

در مرحله بعد برای ساخته شدن Event ها و Listener ها باید دستور زیر را اجرا کنید:

php artisan event:generate;

پس از اجرای دستور بالا فایل های زیر ساخته می شوند

  • app/Events/ProductCreated : این Event با نام ProductCreated می باشد که حاوی یک کلاس می باشد که دربردارنده اطلاعات مربوط به Listeners می باشد. (به انگلیسی Listeners Container)
  • app/Listeners/SendEmail.php , app/Listeners/SendSMS.php : این فایل یک Listeners می باشد که در زمان fire شدن واقعه ProductCreated باید اجرا گردد. متد handle در آن در زمان اجرا استفاده می شود.

Event

همان طور که می بینید نام Event را مفرد به کار می برم و نام Listeners را جمع . چون به ازای یک Event می توانیم یک یا چند Listener داشته باشیم. دقت داشته باشید این نام ها همگی در ساختار پوشه بندی جمع می باشند.

در زیر ProductCreated می باشد می خواهیم در زمان ساخت محصول آن را کار بگذاریم:

<?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 ProductCreated
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $product;
    public $user;
    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($product,$user)
    {
        $this->product = $product;
        $this->user = $user;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}

همان طور که در زمان قلاب زدن تابع به Hook در وردپرس می توانستیم پارامتر به تابع بدهیم در لاراول نیز می توانیم به Listeners های موجود از طریق Event مربوطه پارامتر ارسال کنیم.

مثلا در بالا ما شئ $product و $user را در سازنده مقدار دهی کرده ایم . این مقداریر در زمان کارگذاشتن Event در متد های Controller مقدار دهی می شوند.
روال کار به این شکل می باشده که به ازای هر پارامتر یک متغیر داخلی می سازیم و آن را در متد سازنده مقدار دهی می کنیم و بعد در ورودی متد handle موجود در Listener متغیری خواهیم داشت که به شکل شئ می باشد و تمامی پارامتر های موجود در Event با استفاده از آن قابل دسترسی می باشد.

Listeners

در مثال گفته شده ما در زمان ساخت محصول دو عمل ارسال ایمیل (SendEmail) و ارسال پیامک (SendSMS) را داریم. که این دو Listeners می باشند.

Listener های ساخته شده رو و همچنین رابطشون با Event مربوطه رو میتونید در فایل EventServiceProvider مشاهده کنید.

<?php
namespace App\Listeners;
use App\Events\ProductCreated;
use App\Mail\ProductCreated as ProductCreatedMail;
use Illuminate\Support\Facades\Mail;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendUserEmail implements ShouldQueue
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
    /**
     * Handle the event.
     *
     * @param  ProductCreated  $event
     * @return void
     */
    public function handle(ProductCreated $event)
    {
        Mail::to($event->user)->send(new ProductCreatedMail($event->product,$event->user));
    }
}

کد بالا در متد handle پارامتر ورودی event رو می گیره که در اون مقادیری که در زمان ساخت event (__construt) مقدار دهی کردیم موجوده.

چون در این Listener از ارسال ایمیل استفاده می کنیم لذا ProductCreatedMail را import کرده ایم که قالب ارسال ایمیل می باشد و خود نیز باید به آن پارامترهایی حین instanse فرستاده شود.

چون عمل ارسال ایمیل یک کد زمان بر (slow task) می باشد لذا باید از Queue استفاده کنیم که برای همین منظور کلاس را ShouldQueue پیاده سازی (implement) کرده ایم. بنا بر این این Listener زمانی که queue:work در حال Run باشد اجرا می گردد.

<?php

namespace App\Listeners;

use Kavenegar\KavenegarApi;
use App\Events\ProductCreated;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendUserSms implements ShouldQueue
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  ProductCreated  $event
     * @return void
     */
    public function handle(ProductCreated $event)
    {
        $sms = new KavenegarApi(env('KAVENEGAR_API_KEY'));
        $sms->send(env('KAVENEGAR_SENDER'),"09360000000","{$event->product->name} Was Created");
    }
}

در کد بالا نحوه استفاده از پارامتر های Event را در متد handle می توانید مشاهده کنید.

در این Listener نیاز به ارسال پیامک است که پکیج مربوطه از قبل از طریق composer افزوده شده است.

همان طور که می دانید برای ارسال پیامک نیاز به استفاده از وب سرویس ها می باشد. به همین منظور درخواست های Http ارسال می شود و می توان گفت به علت زمان بر بودن کد باید به صورت Background Proccessing یا همان Queue باید انجام شود که برای همین منظور کلاس را از ShouldQueue پیاده سازی (implement) کرده ایم. بنابراین این Listener زمانی که queue:work در حال Run باشد اجرا می گردد.

Event Fire

تا الان ما Event را ساختیم . دو Listener برای آن پیاده سازی کردیم. حالا باید Event را در جایی که لازم است (یعنی در متد مربوطه) کار بگذاریم تا در زمان اجرای متد Fire گردد و به دنبال آن Listener ها اجرا شوند.
پس Listener گوش به اجرای Event دوخته و Event در مکانی کار گذاشته شده تا Fire گردد.

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests\storeProduct;
use App\Events\ProductCreated;
use App\products;
use App\category;
class ProductController extends Controller
{

    public function saveProduct(storeProduct $request)
    {
        $user = Auth::user();
        $request->validated();
        $product_params = $request->except(['_token','category_id']);
        $product_params['status'] = 1;
        $product = $user->products()->create($product_params);
        $product->categories()->attach($request->get('category_id'));
        
        event(new ProductCreated($product,$user));

        return view('dashboard');
    }

}

برای فراخوانی Event نیاز داریم تا App\Events\ProductCreated را import کنیم.چون باید از کلاس ProductCreated موجود در Event شئ ساخته بشه .

برای کار گذاشتن Event در مکان موجود باید از تابع کمکی event استفاده کنیم و در درون آن از Event Class ساخته شده که در مثال ما ProductCreated می باشد استفاده کنیم و پارامتر ایی که Event لازم دارد را به سازنده آن بدهیم که در مثال ما Eloquent Object های $product و $user می باشد.

حال با توجه به پیاده سازی ساختار های بالا :

  • Event ProductCreated
  • Listener SendEmail
  • Listener SendSms

در زمان اجرای متد saveProduct یا همان زمان ذخیره محصول ساخته شده Event ما Fire می شود و به دنبال آن Listener ها اجرا می شوند یعنی ایمیل و پیامک برای کاربران مربوطه ارسال می گردد.

حال می تواند Listener ها به صورت sync یا Queue اجرا شوند.

Listeners Queue

همان طور که در مثال دیدید در پروسه های زمان بر در Listener نیاز پیدا خواهیم کرد که اجرا را به Queue بسپاریم که برای این منظور باید کد زیر Run باشد :

php artisan queue:work

در استفاده از Queue باید تنظیماتی انجام گردد. به طور مثال اگر Queue_Driver برابر با database باشد نیاز داریم تا migration های آن را بسازیم.
اگر نیازی به Background Proccessing در Listener نبود نیازی به implements ShouldQueue نمی باشد و کد ها همزمان با فراخوانی در متد controller اجرا می شود (sync)

اشتراک گذاری :

مدیر وب سایت گنوتک . برنامه نویسی رو با زبان C در هفده سالگی شروع کردم . در حال حاضر به برنامه نویسی php برپایه معماری MVC , HMVC و همچنین سیستم مدیریت محتوای WordPress و فریم ورک محبوب لاراول علاقه مند هستم و دوست دارم اطلاعاتم رو با شما به اشتراک بگذارم.

6 دیدگاه برای Event Listeners

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *