🗞️

【Laravel】イベントとリスナの使い方

2022/12/25に公開

はじめに

Laravelではイベントリスナを使って、特定の事象が発生した時に実行される処理を定義することができます。
これはデザインパターンの一種で「Observer(観察者)パターン)」といいます。
イベントが観察される側で、リスナが観察する側です。
つまり、イベントが発行されるとリスナで定義しておいた処理が実行されるという流れです。

今回はユーザー登録を例に実装していき、イベント、リスナ、Observerパターンについて理解していただければと思います。

環境

参考

https://readouble.com/laravel/9.x/ja/events.html
https://refactoring.guru/ja/design-patterns/observer

今回の実装について

ユーザーが新規登録を行なった場合に以下の2つの処理を実装します。

  • ウェルカムメールを送信する
  • メルマガ登録を行う

これらをイベントを使う場合と使わない場合を比較して、利点についても理解していただければと思います。

イベントを使う利点とは

以下が挙げられます。

コントローラーへの記述を減らすことでのメンテナンス性向上
→全ての処理をコントローラーで行うこともできますが、イベントとリスナを使うことで処理を分離させることができ、メンテナンス姓が向上します。

変更容易性の向上
→管理者に新規ユーザーの情報を通知する新機能を追加することになった場合も、処理を別のクラスに分けているためコントローラーの記述を変更する必要が無く、他の箇所への影響範囲が最小で済みます。

テスト容易性の向上
→各クラスを個別にテストすることができるため、テストもしやすくなります。

イベントを使用しない場合

まず、イベントを使用しない場合を実装していきます。

UserControllerを作成し、以下のようにregsiterメソッドを作成します。

UserController.php

// 中略

use App\Mail\WelcomeMail;
use App\Models\MailingList;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;

// 中略

 public function register(Request $request)
{
        User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        Mail::to($request->email)->send(new WelcomeMail());

        MailingList::create([
            'email' => $request->email
        ]);

        return response()->json(['result' => 'success']);
 }

ユーザー登録後に、メール送信処理とメルマガ登録処理を行なっています。

イベントを使用する場合

次にイベントを使用する場合で実装していきます。
流れは以下の通りです。

①イベントとリスナをサービスプロバイダーに登録
②イベントとリスナの生成
③イベントの定義
④リスナの定義
⑤コントローラーでイベントを発行する

①イベントとリスナをサービスプロバイダーに登録

事前にEventServiceProviderへイベントとリスナを登録しておくことで、一括でファイルを作成することができます。
EventServiceProviderlistenプロパティに以下のようにイベントとリスナを登録します。

EventServiceProvider.php
// 中略

use App\Events\UserRegistered;
use App\Listeners\SendWelcomeMail;
use App\Listeners\SubscribeToMailingList;

// 中略

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        UserRegistered::class => [
            SendWelcomeMail::class,
            SubscribeToMailingList::class
        ]
    ];
}

②イベントとリスナの生成

以下のコマンドを入力することで、先ほど登録したUserRegisteredイベント、SendWelcomeMailリスナ、SubscribeToMailingListリスナを生成します。

$ sail artisan event:generate

③イベントの定義

app/Events配下にUserRegistered.phpが生成されているので、以下のように更新します。

UserRegistered.php

// 中略

use App\Models\User;

// 中略

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * ユーザーインスタンス
     *
     * @var App\Models\User;
     */
    public $user;

    /**
     * イベントインスタンスの生成
     *
     * @param User $user
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }
}

上記のようにUserRegisterdイベントはUserインスタンスを持つだけで、ロジックはありません。

④リスナの定義

リスナのファイルはapp/Listeners配下に生成されます。
まずは、SendWelcomeMailリスナのhandleメソッドにウェルカムメール送信処理を記述します。

SendWelcomeMail.php

// 中略

use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;

class SendWelcomeMail
{
    // 中略

    /**
     * ウェルカムメール送信処理
     *
     * @param  \App\Events\UserRegistered  $event
     * @return void
     */
    public function handle(UserRegistered $event)
    {
        Mail::to($event->user->email)->send(new WelcomeMail());
    }

handleメソッドでUserRegisteredインスタンスを受け取り、そのインスタンスが持つUserのメールアドレスに対してウェルカムメールを送信します。

次にSubscribeToMailingListhandleメソッドにメルマガ登録処理を記述します。

SubscribeToMailingList.php

// 中略

use App\Events\UserRegistered;
use App\Models\MailingList;

class SubscribeToMailingList
{
    // 中略
    
    /**
     * メルマガ登録処理
     *
     * @param  \App\Events\UserRegistered  $event
     * @return void
     */
    public function handle(UserRegistered $event)
    {
        MailingList::create([
            'email' => $event->user->email
        ]);
    }
}

同じくhandleメソッドでUserRegisteredインスタンスを受け取り、そのインスタンスが持つUserのメールアドレスを登録します。

⑤コントローラー

最後にコントローラーでイベントを発行します。
ユーザー登録後に、eventヘルパー関数を使ってUserRegisteredイベントを発行します。

UserControler.php

// 中略

use App\Events\UserRegistered;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class UserController extends Controller
{
    /**
     * ユーザー新規登録
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function register(Request $request): JsonResponse
    {
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        event(new UserRegistered($user));

        return response()->json(['result' => 'success']);
    }
}

これでユーザー登録時にUserRegisteredイベントが発行されウェルカムメール送信とメルマガ登録がされるようになったかと思います。

さいごに

今回はユーザー登録を例にLaravelのイベントとリスナを使ってみました。
少しでもお役に立てれば嬉しいです。
最後までお読みいただきありがとうございました。

Discussion