データベースに保存されているデータはいつも現時点での値であり、過去の値は保存されていません。しかし、レコードのデータがどう変更したかという情報は重要です。どう変更したかだけではなく、誰がいつ、アプリのどの機能を使用して、さらにはどういう理由で、という情報も必要になってきます。例えば、カスタマサポートにおいて、会員の住所が変更されて注文した商品が届かなかったとき、それらの情報があれば、いついつにお客様が住所を変更しましたね、とか即答できます。さて、これらの変更イベント時の変更情報(監査あるいはAudit情報)、Laravelではどのように効率的にDBに保存することが可能でしょうか?
Eloquentのイベントメソッド
LaravelのEloquentを利用すると、DBのイベント、つまりレコードの作成、変更、削除の3つのイベントに連結したメソッドが提供されています。そして、それらのイベントが発生する前あるいは後においてユーザー定義のコードをコールバックさせることが可能です。これらを利用したら、希望するAuditの情報をキャプチャすることが簡単にできます。
さてLaravelのデフォルトのプロジェクトを使って見てみましょう。
まず、UserのクラスにDBのレコード変更後のイベントのコールバックを作成します。以下のようにbootメソッドにおいて見慣れないクラスメソッドupdatedをコールすることで可能となります。
namespace App; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; ... protected static function boot() { parent::boot(); static::updated(function () { echo "updated\n"; }); } }
ちなみに、updatedは更新後にコールされるものですが、新規作成後は、created、削除後はdeletedというメソッドになります。
tinkerを使用して実行してみます。
>>> $user = User::find(1); => App\User {#3048 id: 1, name: "近藤 篤司", email: "manabu.takahashi@example.net", email_verified_at: "2020-02-13 04:27:15", created_at: "2020-02-13 04:27:15", updated_at: "2020-05-17 18:31:32", } >>> $user->update(['email' => 'test@example.com']); updated => true
コールバックで定義したupdatedが表示されましたね!
変更前後の情報の取得
DBのレコード変更イベントでユーザー定義の関数をコールバックを確認できたら、次は変更前後でのレコードの情報をどうやって取得するかです。以下見てください。コールバックにそれらの情報を表示するコードを追加しました。
namespace App; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; class User extends Authenticatable { use Notifiable; ... protected static function boot() { parent::boot(); static::updated(function ($model) { echo "updated\n"; print_r($model->original); print_r($model->attributes); }); } }
tinkerで実行してみます。
>>> $user = User::find(1); [!] Aliasing 'User' to 'App\User' for this Tinker session. => App\User {#3067 id: 1, name: "近藤 篤司", email: "test@example.com", email_verified_at: "2020-02-13 04:27:15", created_at: "2020-02-13 04:27:15", updated_at: "2020-05-17 18:59:31", } >>> $user->update(['email' => 'test2@example.com']); updated Array ( [id] => 1 [name] => 近藤 篤司 [email] => test@example.com [email_verified_at] => 2020-02-13 04:27:15 [password] => $2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi [remember_token] => cDvZkS5nOA [created_at] => 2020-02-13 04:27:15 [updated_at] => 2020-05-17 18:59:31 ) Array ( [id] => 1 [name] => 近藤 篤司 [email] => test2@example.com [email_verified_at] => 2020-02-13 04:27:15 [password] => $2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi [remember_token] => cDvZkS5nOA [created_at] => 2020-02-13 04:27:15 [updated_at] => 2020-05-17 19:03:27 ) => true
前後の値、キャプチャできましたね。これで変更履歴を作成するには十分な準備ができました。これらを利用すれば、変更前後の値あるいは差分を保存できますね。
メルマガ購読の申し込みはこちらから。