【Laravel】PostgreSQLのtrigger機能を使って履歴を取る方法
こんにちは。
ニシザワです。
本日は、Laravelに於いて、PostgreSQLのtrigger機能を用いた履歴作成について書いていきます。
本ブログではLaravelのインストール方法は説明しません
PostgreSQL:15.2
こちらの決済ステータスを更新する際に、履歴を作成するようにします。
最初に全コードを書いてしまいます。
説明はその下に書いていきます。
TG_OPで、実行された操作(insert,update,delete)を判定可能です。
NEWで、入力されたデータを取得できます。
こちらはinsertとupdate時しか使えません。
OLDで、更新前のデータを取得できます。
こちらはupdateとdelete時しか使えません。
NEW.status != OLD.statusで比較することで、変更があったかを判定します。
ここを指定しないとfunction内のIF (TG_OP = \'UPDATE\')等が実行されないので注意してください。
EXECUTE FUNCTIONで、実行するfunctionを指定します。
functionを使えば色々とできるので、ぜひ使ってみてください。
本日は以上となります。
ニシザワです。
本日は、Laravelに於いて、PostgreSQLのtrigger機能を用いた履歴作成について書いていきます。
本ブログではLaravelのインストール方法は説明しません
環境
Laravel:10.xPostgreSQL:15.2
履歴作成
決済テーブルのステータス履歴を取りたいと仮定します。
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('settlements', function (Blueprint $table) {
$table->uuid('id')->comment('ID');
$table->string('status', 15)->comment('決済ステータス');
$table->timestamp('updated_at')->comment('更新日時');
$table->timestamp('created_at')->comment('作成日時');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('settlements');
}
};
こちらの決済ステータスを更新する際に、履歴を作成するようにします。
最初に全コードを書いてしまいます。
説明はその下に書いていきます。
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('settlement_status_histories', function (Blueprint $table) {
$table->uuid('settlement_id')->comment('決済ID');
$table->string('history_type', 6)->comment('タイプ(create,update,delete');
$table->string('status', 15)->comment('決済ステータス');
$table->timestamp('created_at')->comment('作成日時');
$table->index('settlement_id');
});
DB::unprepared('DROP FUNCTION IF EXISTS update_insert_settlement_status_history');
DB::unprepared('
CREATE FUNCTION update_insert_settlement_status_history() RETURNS TRIGGER AS
$update_insert_settlement_status_history$
BEGIN
IF (TG_OP = \'UPDATE\') THEN
IF (NEW.status != OLD.status) THEN
INSERT INTO settlement_status_histories VALUES (NEW.id, \'update\', NEW.status, NEW.updated_at);
RETURN NEW;
END IF;
ELSEIF (TG_OP = \'INSERT\') THEN
INSERT INTO settlement_status_histories VALUES (NEW.id, \'create\', NEW.status, NEW.created_at);
RETURN NEW;
END IF;
END;
$update_insert_settlement_status_history$
LANGUAGE plpgsql;
CREATE TRIGGER trigger_settlement_status_update_or_create
AFTER INSERT OR UPDATE
ON settlements
FOR EACH ROW
EXECUTE FUNCTION update_insert_settlement_status_history();
');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
DB::unprepared('DROP TRIGGER trigger_settlement_status_update_or_create ON settlements');
DB::unprepared('DROP FUNCTION update_insert_settlement_status_history');
Schema::dropIfExists('settlement_status_histories');
}
};
説明
DB::unprepared('DROP FUNCTION IF EXISTS update_insert_settlement_status_history');
php artisan migrate:fresh を実行した際にfunctionは削除されないため、存在していたら削除する記述を入れています。
BEGIN
IF (TG_OP = \'UPDATE\') THEN
IF (NEW.status != OLD.status) THEN
INSERT INTO settlement_status_histories VALUES (NEW.id, \'update\', NEW.status, NEW.updated_at);
RETURN NEW;
END IF;
ELSEIF (TG_OP = \'INSERT\') THEN
INSERT INTO settlement_status_histories VALUES (NEW.id, \'create\', NEW.status, NEW.created_at);
RETURN NEW;
END IF;
END;
functionの実行内容になっています。TG_OPで、実行された操作(insert,update,delete)を判定可能です。
NEWで、入力されたデータを取得できます。
こちらはinsertとupdate時しか使えません。
OLDで、更新前のデータを取得できます。
こちらはupdateとdelete時しか使えません。
NEW.status != OLD.statusで比較することで、変更があったかを判定します。
CREATE TRIGGER trigger_settlement_status_update_or_create
AFTER INSERT OR UPDATE
ON settlements
FOR EACH ROW
EXECUTE FUNCTION update_insert_settlement_status_history();
AFTERの後に、実行されるタイミングを指定します。ここを指定しないとfunction内のIF (TG_OP = \'UPDATE\')等が実行されないので注意してください。
EXECUTE FUNCTIONで、実行するfunctionを指定します。
DB::unprepared('DROP TRIGGER trigger_settlement_status_update_or_create ON settlements');
DB::unprepared('DROP FUNCTION update_insert_settlement_status_history');
downで、functionとtriggerを削除しています。
まとめ
PostgreSQLのtrigger機能を用いることで、履歴を作成することができます。functionを使えば色々とできるので、ぜひ使ってみてください。
本日は以上となります。