Laravel - Digging Deeper - Events

# 前言

學習一個框架, Ray 的想法是, 在深入理解底層實作的原理之前, 應該先知道這個框架的 使用方法; 先學習怎麼使用這個前人造的輪子, 再學習怎麼樣一個輪子。
所以本篇文章重點在於細讀官方文件, 並將內容理解後以 Q&A 的方式記錄下來, 加速學習以及查詢。




# Registering Events & Listeners

Laravel 中, 如果我想要註冊一個 event, 可以在 EventServiceProvider哪一個 property 中註冊?

$listen property

Laravel 中, 如果我的 event 為 App\Events\OrderShipped, listener 為 App\Listeners\SendShipmentNotification, 在以下的 example 中, 我可以怎麼做?
  • Example:

    <?php
    protected $listen = [
    // what should I put here?
    ];
  • Answer:

    <?php
    protected $listen = [
    'App\Events\OrderShipped' => [
    'App\Listeners\SendShipmentNotification',
    ],
    ];


# Generating Events & Listeners

Laravel 中, 我先在 EventServiceProvider 的 $listen protected property 定義好 event 跟 listener 之後, 怎麼使用 CLI 讓定義好的 event 跟 listener 自動產生?
php artisan event:generate

# Manually Registering Events

Laravel 中, 如果我想要定義 closure based event, 我可以在哪一個檔案中定義?

EventServiceProvider

Laravel 中, 如果我想要定義 closure based event, 我可以在 EventServiceProvider 中的 哪一個 method 中定義?

boot method

以下的 Laravel example code 的意思是?
  • Example:

    <?php
    public function boot()
    {
    parent::boot();

    Event::listen('event.name', function ($foo, $bar) {
    //
    });
    }
  • Answer:
    在 EventServiceProvider 的 boot method 定義 closure based event, 第一個 argument 為該 event name, closure 內為 trigger event 時要做的事, 相當於定義於 Listener 中的邏輯


# Wild Event Listeners

Laravel 中, 如果我想要一個 listener 監聽多個 events, 在以下的 example 中, 假設我的 event name 為 registered 開頭的, 在以下的 example 中, 我可以怎麼做?
  • Example:

    <?php
    Event::listen('what should I put here?', function ($eventName, array $data) {
    //
    });
  • Answer:

    <?php
    Event::listen('registered.*', function ($eventName, array $data) {
    //
    });
以下的 Laravel example code 的意思是?
  • Example:

    <?php
    Event::listen('event.*', function ($eventName, array $data) {
    //
    });
  • Answer:
    監聽 wildcard event, 第一個 argument 為 event name, 第二個為該 event 的 data


# Event Discovery

Laravel Event 中, Event Discovery 的規則, 會 scan 哪一個資料夾中的 Listeners?

Listeners directory

Laravel Event 中, Event Discovery 的規則, 會 scan 每一個 Listener 的 哪一個 method?

handle method

Laravel Event 中, Event Discovery 的規則, 當 scan 到 Listener 中的 handle method 時, 會將這個 Listener 註冊給哪一個 Event?

該 Listener handle method 中 type-hint 的 event

Laravel Event 中, Event Discovery 的規則, 假設以下的 Listener 為我 scan 到的 Listener, Laravel 會將這個 Listener 註冊給哪一個 event?
  • Example:

    <?php
    use App\Events\PodcastProcessed;

    class SendPodcastProcessedNotification
    {
    public function handle(PodcastProcessed $event)
    {
    //
    }
    }
  • Answer:
    PodcastProcessed event

Laravel Event 中, Event Discovery 的規則, 預設是關閉的還是打開的?

關閉的

Laravel Event 中, Event Discovery 的規則, 預設是關閉的, 若要打開它, 可以在哪一個 class 中打開?

EventServiceProvider

Laravel Event 中, Event Discovery 的規則, 預設是關閉的, 若要打開它, 可以使用 EventServiceProvider 中的 哪一個 method 打開?

shouldDiscoverEvents

Laravel Event 中, Event Discovery 的規則, 預設是關閉的, 若要打開它, 在下面的 example 中, 該怎麼做?
  • Example:

    <?php
    /**
    * Determine if events and listeners should be automatically discovered.
    *
    * @return bool
    */
    public function shouldDiscoverEvents()
    {
    // 這邊該 return 什麼?
    }
  • Answer:

    <?php
    /**
    * Determine if events and listeners should be automatically discovered.
    *
    * @return bool
    */
    public function shouldDiscoverEvents()
    {
    return true;
    }
以下位於 EventServiceProvider 的 Laravel example code 的意思是?
  • Example:

    <?php
    protected function discoverEventsWithin()
    {
    return [
    $this->app->path('Listeners'),
    ];
    }
  • Answer:
    若有開啟 Event Discovery, 預設會掃描 ‘app/Listeners’ 資料夾內的 events, 若要變更資料夾位置, 可在 discoverEventsWithin() 中定義

Laravel production 環境中, 我們可能不想要框架在每一個 request 都去 scan 所有的 listeners, 可以使用哪一個 CLI 來將 events 以及 listeners cache 住?
php artisan event:cache
Laravel production 環境中, 我們可能不想要框架在每一個 request 都去 scan 所有的 listeners, 所以使用 CLI 來 cache events 以及 listeners, 如果我要將 cache 拿掉, 可以使用哪一個 CLI?
php artisan event:clear
Laravel 中, 如果我想要使用 CLI 來顯示所有 events 以及 listeners 的對應關係, 可以使用哪一個 CLI?
php artisan event:list




# Defining Events

Laravel Event 中, 會寫到邏輯嗎?

不會哦




# Defining Listeners

Laravel 中, 如果我在定義好 event, listener 的關係之後, 使用 CLI 產生各自檔案, 假設我的 event 是 OrderShipped, 那在下面的 listener example 中, 哪一個 class 會自動的被 type-hint?
  • Example:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;

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

    /**
    * Handle the event.
    *
    * @param \App\Events\OrderShipped $event
    * @return void
    */
    public function handle(這裡會是什麼?)
    {
    // Access the order using $event->order...
    }
    }
  • Answer:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;

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

    /**
    * Handle the event.
    *
    * @param \App\Events\OrderShipped $event
    * @return void
    */
    public function handle(OrderShipped $event)
    {
    // Access the order using $event->order...
    }
    }


# Stopping The Propagation Of An Event

Laravel 中, 如果我想要停止某個 listener 對某個 event 的傳播, 那我可以在該 listener 的 handle method 中回傳什麼?

false




# Queued Event Listeners

Laravel 中, 如果我想要 queue 一個 listener, 那在以下的 example 中, 該如何修改?
  • Example:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implement 這邊該放什麼?
    {
    //
    }
  • Answer:

    <?php
    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    //
    }


# Customizing The Queue Connection & Queue Name

Laravel 中, 如果我想要在 listener 當中自定義 connection 為 sqs, 那在以下的 example 中, 可以怎麼修改?
  • Example:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    }
  • Answer:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    /**
    * The name of the connection the job should be sent to.
    *
    * @var string|null
    */
    public $connection = 'sqs';
    }
Laravel 中, 如果我想要在 listener 當中自定義 queue 為 listeners, 那在以下的 example 中, 可以怎麼修改?
  • Example:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    }
  • Answer:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    /**
    * The name of the queue the job should be sent to.
    *
    * @var string|null
    */
    public $queue = 'listeners';
    }
Laravel 中, 如果我想要在 listener 當中自定義 delay 時間為 60 秒, 那在以下的 example 中, 可以怎麼修改?
  • Example:

    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    }
  • Answer:

    <?php
    <?php

    namespace App\Listeners;

    use App\Events\OrderShipped;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class SendShipmentNotification implements ShouldQueue
    {
    /**
    * The time (seconds) before the job should be processed.
    *
    * @var int
    */
    public $delay = 60;
    }


# Conditionally Queueing Listeners

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App\Listeners;

    use App\Events\OrderPlaced;
    use Illuminate\Contracts\Queue\ShouldQueue;

    class RewardGiftCard implements ShouldQueue
    {
    public function handle(OrderPlaced $event)
    {
    //
    }

    public function shouldQueue(OrderPlaced $event)
    {
    return $event->order->subtotal >= 5000;
    }
    }
  • Answer:
    當 Order model 的 subtotal attribute 大於等於 5000 時, queue 該 listener


# Manually Accessing The Queue

Laravel Events & Listeners 中, 如果我想要在程式碼中可以手動的 release 或 delete 該 listener job, 那我可以在該 Listener 中使用哪一個 trait?

InteractsWithQueue trait

Laravel Events & Listeners 中, 如果我想要在程式碼中可以手動的 release 或 delete 該 listener job, 在以下的 example 中, 可以怎麼修改?
  • Example:

    <?php

    namespace App\Listeners;

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

    class SendShipmentNotification implements ShouldQueue
    {
    // 這邊要加什麼?

    /**
    * Handle the event.
    *
    * @param \App\Events\OrderShipped $event
    * @return void
    */
    public function handle(OrderShipped $event)
    {
    if (true) {
    $this->release(30);
    }
    }
    }
  • Answer:

    <?php

    namespace App\Listeners;

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

    class SendShipmentNotification implements ShouldQueue
    {
    use InteractsWithQueue;

    /**
    * Handle the event.
    *
    * @param \App\Events\OrderShipped $event
    * @return void
    */
    public function handle(OrderShipped $event)
    {
    if (true) {
    $this->release(30);
    }
    }
    }


# Handling Failed Jobs

Laravel Event & Listener 中, 如果我想要在 Listener 失敗後做相對應的邏輯, 那我可以在 Listener 當中定義哪一個 method?

failed method

Laravel Event & Listener 中, Listener class 中的 failed method 可以定義該 Listener 失敗後要執行的邏輯, 請問 failed method 接收的參數是?
  • event instance
  • exception
Laravel Event & Listener 中, Listener class 中的 failed method 可以定義該 Listener 失敗後要執行的邏輯, 請回答以下問題?
  • Example:

    <?php

    namespace App\Listeners;

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

    class SendShipmentNotification implements ShouldQueue
    {
    use InteractsWithQueue;

    /**
    * Handle the event.
    *
    * @param \App\Events\OrderShipped $event
    * @return void
    */
    public function handle(OrderShipped $event)
    {
    //
    }

    /**
    * Handle a job failure.
    *
    * @param \App\Events\OrderShipped $event
    * @param \Exception $exception
    * @return void
    */
    public function failed(這裡頭的是?)
    {
    //
    }
    }
  • Answer:

    <?php

    namespace App\Listeners;

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

    class SendShipmentNotification implements ShouldQueue
    {
    use InteractsWithQueue;

    /**
    * Handle the event.
    *
    * @param \App\Events\OrderShipped $event
    * @return void
    */
    public function handle(OrderShipped $event)
    {
    //
    }

    /**
    * Handle a job failure.
    *
    * @param \App\Events\OrderShipped $event
    * @param \Exception $exception
    * @return void
    */
    public function failed(OrderShipped $event, $exception)
    {
    //
    }
    }




# Dispatching Events

Laravel 中, 如果我想要 dispatch 一個 event, 在以下的 example 中, 可以怎麼修改?
  • Example:

    <?php

    namespace App\Http\Controllers;

    use App\Events\OrderShipped;
    use App\Http\Controllers\Controller;
    use App\Order;

    class OrderController extends Controller
    {
    /**
    * Ship the given order.
    *
    * @param int $orderId
    * @return Response
    */
    public function ship($orderId)
    {
    $order = Order::findOrFail($orderId);

    // Order shipment logic...

    // 這邊該使用什麼?
    }
    }
  • Answer:

    <?php

    namespace App\Http\Controllers;

    use App\Events\OrderShipped;
    use App\Http\Controllers\Controller;
    use App\Order;

    class OrderController extends Controller
    {
    /**
    * Ship the given order.
    *
    * @param int $orderId
    * @return Response
    */
    public function ship($orderId)
    {
    $order = Order::findOrFail($orderId);

    // Order shipment logic...

    event(new OrderShipped($order));
    }
    }




# Event Subscribers

# Writing Event Subscribers

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App\Listeners;

    class UserEventSubscriber
    {
    public function handleUserLogin($event) {}

    public function handleUserLogout($event) {}

    public function subscribe($events)
    {
    $events->listen(
    'Illuminate\Auth\Events\Login',
    'App\Listeners\UserEventSubscriber@handleUserLogin'
    );

    $events->listen(
    'Illuminate\Auth\Events\Logout',
    'App\Listeners\UserEventSubscriber@handleUserLogout'
    );
    }
    }
  • Answer:
    在 EventSubscriber 的 subscribe method 中定義 event 以及 listener, 然後直接在此 class 中定義 listener 邏輯


# Registering Event Subscribers

以下的 Laravel example code 的意思是?
  • Example:

    <?php

    namespace App\Providers;

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

    class EventServiceProvider extends ServiceProvider
    {
    protected $listen = [
    //
    ];

    protected $subscribe = [
    'App\Listeners\UserEventSubscriber',
    ];
    }
  • Answer:
    使用 EventServiceProvider 的 $subscribe property 來註冊事先已建立的 UserEventSubscriber’, EventSubscriber 可以在一個 class 中定義多個 listener 邏輯, 並 map 與之相對應的 event, 這樣就不需要建立多個 class, 每個 class 只定義一個 listener

<未完成> Kubernetes - Volumes Laravel - The Basics - Logging

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×