【Laravel】知ってると便利なEloquentの機能5選

プログラミング
この記事は約4分で読めます。

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にシステム日時をセットしたうえでレコードを更新します。レコードはテーブルに残ったままで、物理削除は行われません。

ここで例えば、「公開済の投稿は論理削除だが、ドラフト状態の投稿は物理削除にしたい」といったニーズがあるとします。この場合はdeleteforceDeleteメソッドを使い分けることで実現できます。

$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);
});

コメント

タイトルとURLをコピーしました