【Laravel】EloquentモデルのObserverの活用

著者:杉浦

【Laravel】EloquentモデルのObserverの活用

 LaravelのEloquentにはObserverという仕組みがあります。ObserverはEloquentのイベント発生によって発火するメソッドの集まりです。
Eloquent:利用の開始 6.0 Laravel#オブザーバ
 Observerは次のようにartisanでボイラープレート的なモノを生成できます。

php artisan make:observer UserObserver --model=User

 以下の様に生成されたクラスをLaravelの起動時処理で登録することによってイベント監視が動作します。

<?php

namespace App\Providers;

use App\Observers\UserObserver;
use App\User;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    //省略
    /**
     * 全アプリケーションサービスの初期起動
     *
     * @return void
     */
    public function boot()
    {
        User::observe(UserObserver::class); // ここでモデル::observe(オブザーバクラス::class)が基本
        Post::observe([PostObserver::class, BBSObserver::class); // 複数でもOK
        foreach (['Post', 'Comment'] as $className) {// 共通のオブザーバを使うならこんな書き方もあり
            /* @var Eloquent $className */
            $className::observe(UpdateTalkedAtObserver::class);
        }
    }
}

 オブザーバの使い時は色々あります。例えば、ある集約全体における更新日時を記録する場合です。
 LaravelのEloquentにはタイムスタンプを自動記録する機能があり、あるレコードを更新した際にそのレコード内の特定のカラム(デフォはupdated_at)に日時を記録してくれます。これだけでも便利なのですが、これだけではシステムの要求を満たせない場合もあります。例えば、あるユーザの情報が複数テーブルに分割されており、いずれかの情報が更新された時にユーザ情報が更新されたとし、その更新日時を記録する必要がある、という場合です。より具体的に次のER図のテーブル構成があるとします。

 ブログへの投稿かコメントを行った時にユーザの最終発言日時を記録する、とします。このような時、次のObserverを作ると要求を満たせます。

class UpdateTalkedAtObserver
{
    public function created(Eloquent $postOrComment) // 宣言した型に依らず、登録したEloquentクラスのインスタンスが渡される
    {
        $postOrComment->user->talked_at = $postOrComment->created_at;
        $postOrComment->user->save();
    }

    public function updated(Eloquent $postOrComment) // 宣言した型に依らず、登録したEloquentクラスのインスタンスが渡される
    {
        $postOrComment->user->talked_at = $postOrComment->updated_at;
        $postOrComment->user->save();
    }
}

 他にもログ取り、検索テーブル用の同期、削除や復元の連鎖など使うと楽になる場面がいくらかあります。また単にモデルのコードが膨れ上がらないための分割としても使えます。

  • この記事いいね! (1)

著者について

杉浦 administrator