Laravel5.3 モデルによるレコード更新時の更新発生カラムの判断について
解決済
回答 1
投稿
- 評価
- クリップ 3
- VIEW 4,267
前提・実現したいこと
Laravel5.3でモデルによるレコード更新時に更新したカラムの更新履歴を記録するAPIを作成しています。
変更前と変更後のモデルを比較して対象カラムを特定する方法はないでしょうか?
テーブル
StaffテーブルにはStaffCodeとStaffName,Bushoというカラムがあり、StaFFCode='ABC'のBushoには’総務'と登録されているとします。
また、StaffHistoryというテーブルにはcolumn,Before,Afterというカラムがあり、columnには変更したカラム名、Beforeには変更前の値、Afterには変更後の値が入る想定
該当のソースコード
※$afterにはStaffテーブルのGet()と同じ構成で、Bushoのデータに’経営企画’となったレスポンスが来ているとします。
$before = Models\Staff::where('StaffCode','ABC')->first();
$after->save();
if($before->StaffName<> $after->StaffName){
$history = new Models\StaffHistory()
$history->column = 'StaffName';
$history->Before = $before->StaffName;
$history->After = $after ->StaffName;
$history->save();
}
if($before->Busho <> $after->Busho){
$history = new Models\StaffHistory()
$history->column = 'Busho';
$history->Before = $before->Busho ;
$history->After = $after ->Busho ;
$history->save();
}
実現したいこと
$beforeと$afterのカラムを一つづつ比較ではなく、モデルで比較し、変更のあったカラムの変更履歴が作成できるようにしたい。
また、他のテーブルの履歴も付けられるように拡張したいと考えており、実現するためにモデルに登録されているすべてのキー名取得、キー数取得が必要だと思いましたが方法がよくわかりませんでした。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
ちょうど自分もLaravelでリビジョンの管理をやろうとしていたところなので,その方針について回答します。
私は3番の方法を支持します。1番は最新リビジョンを高速に取得したいケースにおいては運用が難しいので論外として,私の回りの人間では,初心者もしくは現場開発者寄りの人は2,上級者もしくはライブラリ開発者寄りの人は3を支持する人が多かったです。(Twitter上でのアンケート)
また何をリビジョンとして保存するかですが,(3番を採用する時点で必然的に)何が変更されようと全部の情報を保存し直すという解になりますね。BLOB型のカラムが無ければ全然これで問題無いと思います,外部記憶が高価である時代はとっくに終焉しているので,富豪的プログラミングの考え方でいきましょう。
<< 補足 1 >>
VentureCraft/revisionable: Easily create a revision history for any laravel model
こういうのはありましたが,全テーブルのリビジョンが1つに集約されてしまうと扱いにくそうなので,個人的にはあまり使いたく無いですね…
<< 補足 2 (内容は保証しません) >>
動作未確認ですが,調べながら具体的な実装例を書いてみました。まず,以下のような方法でstaffs
ビューが作られていると仮定します。また,リビジョンはstaff_revisions
,最新リビジョンへのポインタはstaff_latests
が持つとします。staff_revisions.unique_id
,staff_latests.revision_id
で両者は相互参照し合っています。
で,保存処理一式をModels\Staff::save()
に含めてしまいましょう。ここではべた書きしましたが,トレイトをうまく作るとこの辺りを他のモデルと共通化できるかもしれません。
protected $guarded = ['id', 'created_at', 'updated_at'];
public function save(array $options = [])
{
if (!$this->isDirty()) {
return true;
}
return DB::transaction(function () use ($options) {
$exists = $this->exists;
if ($exists && $this->fireModelEvent('updating') === false) {
return false;
}
if (!$exists && $this->fireModelEvent('creating') === false) {
return false;
}
$revision = Models\StaffRevision::create(['unique_id' => $this->id] + $this->getFillable());
$latest = Models\StaffLatest::where('id', $this->id)->updateOrCreate(['revision_id' => $revision->id]);
if (!$exists) {
$revision->fill(['unique_id' => $latest->id])->save();
$this->id = $latest->id;
}
if ($this->usesTimestamps()) {
$this->updateTimestamps();
}
$this->exists = true;
$this->wasRecentlyCreated = !$exists;
$this->fireModelEvent($exists ? 'updated' : 'created', false);
$this->finishSave($options);
return true;
});
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.19%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/02/27 19:55
2017/02/28 09:15
ありがとうございました。
2017/02/28 15:54
この方法でフックするのが良さそうです!