Ray Lee | 李宗叡
Learn or Die
Published in
14 min readJan 3, 2021

--

Photo by Samantha Gades on Unsplash

# 版本

Laravel 7.x

# 前言

我喜歡使用 Laravel 開發的感覺, 除了開發快速, 程式碼簡潔且優雅之外, Laravel 框架本身也是一個很好的學習參照物。 本篇主要將官方文件重點整理成 Q&A 的形式呈現, 原子化的概念, 這方式並不適用於每個人, 但若對你有幫助, 我會很開心。

# Registering Events & Listeners

以下位於 EventServiceProvider 的 Laravel example code 的意思是?

  • Example:
<?php
protected $listen = [
'App\Events\OrderShipped' => [
'App\Listeners\SendShipmentNotification',
],
];
  • Answer: 在 EventServiceProvider 的 $listen property 中 註冊一個 Listener SendShipmentNotification 監聽 OrderShipped event

# 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 example code 的意思是?

  • Example:
<?php
Event::listen('registered.*', function ($eventName, array $data) {
//
});
  • Answer: 監聽所有 registered. 開頭的 event

以下的 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 的規則, 假設以下的 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 example code 的意思是?

  • Example:
<?php
public function shouldDiscoverEvents()
{
return true;
}
  • Answer: Laravel 預設關閉 Event Discovery, 就是會根據 convention 將 listener 註冊給 listener handle method 中 type hint 的 event class 若要開啟, 可在 EventServiceProvider 的 shouldDiscoverEvents() 中開啟

以下位於 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

# Stopping The Propagation Of An Event

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

false

# Queued Event Listeners

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
//
}
  • Answer: 將 listener class implement ShouldQueue interface, 當觸發該 listener 時, 該 job 會被 queue

# Customizing The Queue Connection & Queue Name

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
public $connection = 'sqs';
}
  • Answer: 在 listener class 當中指定 connection 為 ‘sqs’

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
public $queue = 'listeners';
}
  • Answer: 在 listener class 中使用 $queue 指定該 listener 使用的 queue

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
public $delay = 60;
}
  • Answer: 在 listener class 中, 使用 $delay 定義該 job 在被 release 回 queue 後, 至少須等待 60 秒才可在被 worker pick up 執行 Laravel 8 又叫做 backoff

# 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 example code 的意思是?

  • Example:
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
use InteractsWithQueue;

public function handle(OrderShipped $event)
{
if (true) {
$this->release(30);
}
}
}
  • Answer: 若要在 listener job 中可對 job 做 release 或 delete 操作, 需 use InteractsWithQueue

# Handling Failed Jobs

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

failed method

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Listeners;

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

class SendShipmentNotification implements ShouldQueue
{
use InteractsWithQueue;

public function handle(OrderShipped $event)
{
//
}

public function failed(OrderShipped $event, $exception)
{
//
}
}
  • Answer: 在 listener class 內定義 failed(), 當 listener job failed 時, 執行 failed() 內的邏輯

# Dispatching Events

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Http\Controllers;

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

class OrderController extends Controller
{
public function ship($orderId)
{
$order = Order::findOrFail($orderId);

// Order shipment logic...

event(new OrderShipped($order));
}
}
  • Answer: 觸發 OrderShipped event

# 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

--

--

Ray Lee | 李宗叡
Learn or Die

It's Ray. I do both backend and frontend, but more focus on backend. I like coding, and would like to see the whole picture of a product.