データベースに保存されているデータはいつも現時点での値であり、過去の値は保存されていません。しかし、レコードのデータがどう変更したかという情報は重要です。どう変更したかだけではなく、誰がいつ、アプリのどの機能を使用して、さらにはどういう理由で、という情報も必要になってきます。例えば、カスタマサポートにおいて、会員の住所が変更されて注文した商品が届かなかったとき、それらの情報があれば、いついつにお客様が住所を変更しましたね、とか即答できます。さて、これらの変更イベント時の変更情報(監査あるいは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
前後の値、キャプチャできましたね。これで変更履歴を作成するには十分な準備ができました。これらを利用すれば、変更前後の値あるいは差分を保存できますね。
メルマガ購読の申し込みはこちらから。