Laravelの標準ORMライブラリEloquent
には便利な機能がたくさんあります。公式ドキュメントのこのページを読むだけでもおよそのことが実現できるのですが、ここに書かれていない機能もたくさんあります。
この記事では、わたしがLaravelでのアプリケーション開発中に「え、そんなんできるんですか?」と気づいたEloquent
の便利な機能を紹介します。
1. pushメソッドで関連モデルをまとめて保存
モデルインスタンスを保存するときは通常save
メソッドを使うことが多いですが、代わりにpush
メソッドを実行すると、関連モデルをまとめて保存することができます。
$company = Company::first(); $company->name = "ABC Corporation"; $company->address->city = "Tokyo"; $company->push();
この例だと、companyオブジェクトとその関連モデルであるaddressがまとめて保存されます。
2. increment / decrement
プロパティを指定して、値をインクリメント/デクリメントすることができます。
具体的には、
$post = Post::find($id); $post->read_count++; $post->save();
の代わりに、
$post = Post::find($id); $post->increment('read_count');
と、increment
メソッドにプロパティ名指定して実行します。
decrement
も同様にプロパティ名を指定して実行できます。インクリメント/デクリメントする数をオプションで指定することもできます。
$stationary->decrement('inventory', 5);
3. Soft deleteモデルを物理削除
論理削除 (Soft delete) をサポートするモデルでは、delete
メソッドを実行するとテーブルの列deleted_at
にシステム日時をセットしたうえでレコードを更新します。レコードはテーブルに残ったままで、物理削除は行われません。
ここで例えば、「公開済の投稿は論理削除だが、ドラフト状態の投稿は物理削除にしたい」といったニーズがあるとします。この場合はdelete
とforceDelete
メソッドを使い分けることで実現できます。
$post = Post::find($id); if ($post->draft) { $post->forceDelete(); } else { $post->delete(); }
ちなみに論理削除済を表す列deleted_at
は、モデルにDELETED_AT
という定数を定義すると任意の名前にすることができます。
class Post extends Model { const DELETED_AT = 'delete_datetime'; }
Laravel以外のアーキテクチャで動作しているアプリケーションをテーブル構造を変えずにLaravelにポーティングするときなどに使えそうですね。
4. Lifecycle Eventを抑制
公式サイトにあるように、Eloquent
では、モデルのライフサイクルに対応するイベントが発火されます。これらのイベントをフックして通知などの追加処理を行うことができるということですね。
ただテストコード中でモデルを作成するときなど、イベントを発生させずにモデルの作成や更新を行いたい場面もあると思います。こんなときはwithoutEvents
メソッドの中で該当の処理を行いましょう。
$company = Company::withoutEvents(function () { return factory(Company::class)->create(); });
5. 動的なWHERE句
「画面から入力された検索条件があれば検索条件に追加する」といった処理は
$query = User::query(); if (!empty($name)) { $query->where('name', '=', $name); } if (!empty($division)) { $query->where('division', '=', $division); } ...
という形でも書けますが、when
を使うとif
文を使わずに書けます。
$query = User::query(); $query->when(!empty($name), function($q) use ($name) { return $q->where('name', '=', $name); }); $query->when(!empty($division), function($q) use ($division) { return $q->where('division', '=', $division); });
コメント