はじめに
LaravelのSoftDeletes、便利なんですが、論理削除されているかの判定に使用するカラムはDateTime型でないといけません。しかし皆さんもおそらく遣る方無い事情により論理削除の判定をフラグ形式(0か1のinteger)で持たなければならないことがあるでしょう。そんなときのためにこれを作りました。
SoftDeletesでboolean形式の削除フラグを使用するためのLaravelプラグインです。
テストもなく作り捨て感満載の退廃的なLaravelプラグインなんですが、せっかくPackagistで公開したし、LaravelのModelに付属するtraitの挙動やグローバルクエリスコープなど学びが多かったので経緯をまとめます。作ったプラグインの使い方が知りたい人はREADME.md見てください。がんばって英語で書きました。
SoftDeletesについて
SoftDeletes
SoftDeletesはModelに付属するtraitとして実装されています。これをuseしてあげると簡単に論理削除が実装できる、という便利traitです。今回はこれをextendsしたSoftDeleteFlagTraitというtraitをつくりました。
中身をもうちょい細かく見ていきます。
bootSoftDeletes()
Modelの初期起動メソッドです。Model自体の初期起動メソッドはboot()ですが、Modelにくっつけるtraitでboot<trait名>()というメソッドを作っておくと、こちらも実行してくれます。(staticメソッドでなければいけません)
bootSoftDeletes()ではaddGlobalScope()(後述)でSoftDeletingScope(後述)を追加してるんですが、今回は別のGlobalScopeをaddしたいので、継承先では空メソッドで上書きし、新たにbootSoftDeleteFlagTrait()を作っています。
addGlobalScope()
GlobalScopeをaddします。Laravelにはクエリスコープという機能があり、Modelで使用する制約(where()とか)を共通化することができます。SoftDeletesでは
->where('deleted_at', null)
をすべての処理に適用したいので、グローバルスコープとして導入しています。(特定のModelにのみ、任意のタイミングで適用したい場合はローカルスコープ機能を使用します)
initializeSoftDeletes()
こちらもModelの初期起動メソッドです。boot()と同様、initialize<trait名>()でtraitの初期起動メソッドを実行してくれます。こちらはstaticでないメソッドに使います。Laravel 5.7以降で使用できるようです。
SoftDeletesではdatesプロパティにdeleted_atを追加することで、deleted_atプロパティを自動的にCarbonインスタンスへ変換するようにしています。ですが僕らの削除フラグはbooleanなのでこの処理を噛まされると困ります。先程と同様に継承先では空メソッドで上書きしてやります。(空メソッドで上書きするのってなんとなくあんまりキレイじゃない気がするんですがどうなんでしょう)
runSoftDelete()
SoftDeletesでは削除時にこのメソッドが呼ばれます。Modelのdeleted_atプロパティに現在のタイムスタンプを格納したうえで、データベースのdeleted_atカラムを現在の日時に更新します。あわせてupdated_atカラムも現在の日時に更新しています。
今回はこの処理を改変し、削除フラグにあたるカラムをtrue(1)に更新するようにしました。
restore()
名前の通り、削除を切り戻す際に呼ばれるメソッドです。論理削除フラグをnullにします。この処理も上書きし、削除フラグをnullではなくfalse(0)に更新するようにしました。
SoftDeletingScope
SoftDeletesで使用するScopeクラスです。ScopeはScopeインターフェースにしたがってapply()メソッドを実装する必要があります。
このScopeもそのまま使うわけにはいかないので、これを継承したSoftDeleteFlagScopeを作ります。
apply()
apply()メソッドは渡されたBuilderインスタンスに条件を付与します。元ネタであるSoftDeletingScopeではdeleted_atカラムがnullであることを指定するwhere()を実行していますが、今回SoftDeleteFlagScopeでは削除フラグがfalse(0)であることを指定するwhere()に置き換えます。
extend()
Laravelのmacro機能を使ってBuilderに4つのメソッドを追加します。これによりSoftDeletesが組み込まれたModelのBuilderで下記メソッドが実行できるようになりますが、これらもよしなに置き換えておきます。詳しくは実装を参照。
restore()withTrashed()withoutTrashed()onlyTrashed()
おわりに
CakePHPのプラグイン作ったときも思いましたが、プラグイン実装は自然とフレームワークのコアを読む必要が出てくるので勉強になります。今回は既存のものをextendsしたtraitとScope作っただけでしたが、次はもうちょっと凝ったものを作りたい。