【Laravel 6.0】モデルのイベントを監視してデータ操作時のログを取る話

# はじめに

データ変更や作成の度に個別にロギング処理を追加するのは面倒だったので、
オブザーバを使ってモデルのイベントを検知して、ログを出力してみました。

環境は「**Laravel Framework 6.18.42**」です。

## 本編
### サービスプロバイダを追加
#### Artisanコマンド
まずはArtisanコマンドでObserverのサービスプロバイダを追加していきましょう。

```terminal
[root@c10fd46073bc:/var/www#: php artisan make:provider ObserverServiceProvider
Provider created successfully.
```

#### サービスプロバイダの登録
```terminal
   'providers' => [
        （中略）
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
        App\Providers\ObserverServiceProvider::class, // 追加しました
],
```

### モデルのオブザーバを設定
監視対象のモデルを追加したい場合は、コメント部分に追加します。

```php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class ObserverServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        // 監視するモデルとオブザーバのペアを適宜追加する
        \App\Models\Wallet::observe(\App\Observers\Models\WalletObserver::class);
    }
}
```
### オブザーバの定義
今回はお財布モデルに適用してみます。
モデルの監視は複数に増えていくことを想定して、
Interface,Traitで共通化しておきました。

#### インターフェイスを実装
[Laravel 6.x Eloquent：利用の開始](https://readouble.com/laravel/6.x/ja/eloquent.html)に記載の
イベントのインターフェイスを定義します。

```php
<?php

namespace App\Observers\Models;

interface ModelObserverInterface
{
    /**
     * Handle the model "created" event.
     *
     * @param $eloquent
     */
    public function created($eloquent);

    /**
     * Handle the model "updated" event.
     *
     * @param $eloquent
     */
    public function updated($eloquent);
}
```

#### オブザーバのトレイトを作成
`Log::info`の部分はお好きなログ出力に書き換えてください。

```php
<?php

namespace App\Observers\Models;

use Illuminate\Support\Facades\Log;

trait ModelObserveLoggable
{
    /**
     * Handle the model "created" event.
     *
     * @param $eloquent
     */
    public function created($eloquent)
    {
        // 出力サンプル
        // [WalletObserver]:App\Observers\Models\ModelObserveLoggable::created{'data'=> 'データ'}
        Log::info(("[$this->name]:".__METHOD__),$eloquent->toArray());
    }

    /**
     * Handle the model "updated" event.
     *
     * @param $eloquent
     * @return void
     */
    public function updated($eloquent)
    {
        // 出力サンプル
        // [WalletObserver]:App\Observers\Models\ModelObserveLoggable::updated{'data'=> 'データ'}
        Log::info(("[$this->name]:".__METHOD__),$eloquent->toArray());
    }
}
```
#### お財布モデルのオブザーバを定義

```php:app.php
<?php

namespace App\Observers\Models;

use App\Observers\Models\ModelObserverInterface;
use App\Observers\Models\ModelObserveLoggable;

class WalletObserver implements ModelObserverInterface
{
    use ModelObserveLoggable;

    // モデル名に書き換え
    protected $name = 'WalletObserver';
}
```

### 出力ログ確認
`$wallet->create()`や`$wallet->update()`を実行すると、
無事に以下のようなログが出力されました。

```terminal:laravel.log
[2020-10-21 18:40:43] local.INFO: [WalletObserver]:App\Observers\Models\ModelObserveLoggable::created {"user_id":1,"name":"作ったお","id":100} 
[2020-10-21 18:44:53] local.INFO: [WalletObserver]:App\Observers\Models\ModelObserveLoggable::updated {"id":101,"user_id":1,"name":"変更したお"} 
```

# おわりに
検知するオブザーバのメソッドをTrait化しているため、簡単に使い回しができるかと思います。

監視したいモデルのオブザーバをクラスファイルを追加して、
`ObserverServiceProvider`にモデルとオブザーバを紐付けするだけで、
モデルのデータベースの変更などイベント等をロギングすることができました。

### 参考
[Laravel 6.x Eloquent：利用の開始](https://readouble.com/laravel/6.x/ja/eloquent.html)