Laravel Activity Logを使って簡単に変更履歴機能を実装しよう

# はじめに
変更履歴の機能を実装するのって、考慮する事も多いし、大変ですよね？
Laravel Activity Logを使うと、簡単に変更履歴の機能を実装できます。
この記事では、laravel-activitylogをどのように導入するか説明します。

# やりたい事
- データの作成・更新・削除のユーザの動作に対して履歴を残したい。
- 変更履歴データを画面に表示したい。

# 使うライブラリ
laravel-activitylog
https://github.com/spatie/laravel-activitylog

# 実装手順
## 1.下記のコマンドを実行する。  
- ライブラリのインストール  

```
$ composer require spatie/laravel-activitylog
```
```
$ php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="activitylog-migrations"
```
## 2.マイグレーションの実行
- migrateを実行してactivity_logテーブルを作成します。

```php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateActivityLogTable extends Migration
{
    
    /**
     * Run the migrations.
     */
    public function up()
    {
        Schema::connection(config('activitylog.database_connection'))->create(config('activitylog.table_name'), function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('log_name')->nullable();
            $table->text('description');
            $table->nullableMorphs('subject', 'subject');
            $table->nullableMorphs('causer', 'causer');
            $table->json('properties')->nullable();
            $table->timestamps();
            $table->index('log_name');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down()
    {
        Schema::connection(config('activitylog.database_connection'))->dropIfExists(config('activitylog.table_name'));
    }
}
```


```
$ php artisan migrate
```

## 3.Modelの修正
- useでLogsActivityを指定するのと、$logAttributesの配列に変更履歴に残したいカラムを指定します。


```diff
<?php

/**
 * Class User
 * @package App\Entities\Models
 */
class User extends Authenticatable 
{  
+    use LogsActivity;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'name_kana',
        'tel',
        'is_active',
        'suspended_at',
        'access_permission',
    ];  


+       public function getActivitylogOptions(): LogOptions
+    {
+        return LogOptions::defaults()
+            ->logOnly([
+              'name',
+              'name_kana',
+              'tel',
+              'is_active',
+              'suspended_at',
+              'access_permission',
+            ]);
+    }


```

## 4.Controllerの修正
- activity()で対象のModel指定します。
- causedBy()で更新作業を実行するユーザを指定します。
- log()でDBのdescriptionに入る内容を定義します。


```diff
<?php
/**
 * Class UserProfilesController
 * @package App\Http\Controllers
 */
class UserProfilesController extends Controller
{
    /**
     * @param ProfileUpdateRequest $request
     * @param User $user
     */
    public function update(ProfileUpdateRequest $request, User $user)
    {
        $loginUser = auth()->user();
        $params = $request->validated();

        DB::transaction(function () use ($user, $params, $loginUser) {
+            activity('user')
+                ->causedBy($loginUser)->log("{$loginUser->name}さんが{$user->name}さんのユーザ詳細情報を更新");
+            $this->updateUserProfile($user, $params);
        });
```

## 登録されるデータの例
```
+----+----------+-------------------------------------+---------------------+------------+--------------+-----------+-------------+-------------------------------------+---------------------+---------------------+
| id | log_name | description                         | subject_id | subject_type             | causer_id | causer_type                 | properties                          | created_at          | updated_at          |
+----+----------+-----------------------------------------------------------------+------------+--------------+-----------+-------------+-------------------------------------+---------------------+---------------------+
|  1 | user     | "鈴木さんがユーザ1さんのユーザ詳細情報を更新"　|         1  | App\Entities\Models\User |         1 | App\Entities\Models\User    | {"business_name":"Best Restaurant"} | 2021-08-04 14:58:06 | 2021-08-04 14:58:06 |
+----+----------+-----------------------------------------------------------------+------------+--------------+-----------+-------------+-------------------------------------+---------------------+---------------------+
```

あとはDBに登録されたデータを取得して、表示させたい画面に表示させればOKです！