【Laravel】カスタムイベントリスナーの有効・無効をイベントを発行する際に決められるようにする

 Laravelでカスタムイベントリスナーを任意のタイミングで有効化、無効化する方法を説明します。これは特にLaravelが用意したイベントリスナー(例えば xxx::saving)はそのまま実行しつつ、自前で用意したイベントリスナーは動かしたくないといった場合に便利です。

 まず通常通りにイベントリスナーを定義します。Laravelでは EventServiceProvider でリスナーを登録します。以下はその一例です:

<?php

namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Event\Event\ModelCreated;
use App\Event\Listeners\SaveNotification;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event to listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        ModelCreated::class   => [SaveNotification::class],
    ];
    // 省略
}
<?php

namespace App\Event\Listeners;

use App\Event\Event\ModelCreated;

class SaveNotification
{
    public function handle(ModelCreated $event): void
    {
        // イベントを元に実行する処理
    }
}

 次にこのイベントリスナーを動的に有効化・無効化する機能を追加します。こうすると外部から有効・無効が切り替えられます。

<?php

namespace App\Event\Listeners;

use App\Event\Event\ModelCreated;

class SaveNotification
{
    public static bool $isActive = true;

    public function handle(ModelCreated $event): void
    {
        if(self::$isActive) {
            // イベントを元に実行する処理
        }
    }
}

/*** 使用例 ***/
SaveNotification::$isActive = false;
// ここにモデル作成処理
SaveNotification::$isActive = true;

 外部から直接プロパティを変更する方法の難点は処理後に戻し忘れがある点です。これに対処するために次の withoutListen ようなメソッドを用意します。このメソッドはコールバック関数を受け取り、その関数内でのみリスナーを無効化します。

<?php

namespace App\Event\Listeners;

use App\Event\Event\ModelCreated;

class SaveNotification
{
    private static bool $isActive = true;

    public static function withoutListen(callable $callback): void
    {
        $currentIsActive = self::$isActive;
        try {
            self::$isActive = false;
            $callback();
        } finally {
            self::$isActive = $currentIsActive;
        }
    }

    public function handle(ModelCreated $event): void
    {
        if(self::$isActive) {
            // イベントを元に実行する処理
        }
    }
}

/*** 使用例 ***/
SaveNotification::withoutListen(function () {
    // ここにモデル作成処理
});

 この方法では、コールバック内で処理が実行される間、リスナーが一時的に無効化されます。処理が終了すると、自動的にリスナーが再び有効化されるため、戻し忘れのリスクを最小限に抑えることができます。この現状態フラグ保持、try、フラグ立て、finally、フラグ戻しの流れは一時的にフラグを立てるような処理を書く時に使いまわしやすいです。

 このようにしてイベントの発火点の側から任意のイベントリスナーにイベントを処理させる、させないを制御できるようになります。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG