【Laravel】Eloquentのリレーションを論理削除無視でロードする

  • 2022年6月3日
  • 2022年6月3日
  • Laravel

 Laravel にはデータベースに対応するモデルクラスである Eloquent が用意されており、その中ではテーブル同士の関係を表現するリレーションという仕組みも用意されています。これを次の様に使うことで JOIN 句を用いずとも N+1 問題を避けつつ、いい感じに SQL が実行され、データを呼び出せます。

// with メソッドで Laravel がリレーション元を使って
// いい感じに SELECT * FROM リレーション先 WHERE IN () しつつ
// 結果をリレーション元のプロパティに追加してくれます。
$users = User::with('podcasts')->get();

// もし↑で with していない場合、
// ここでループの度に SELCT * FROM podcasts WHERE user_id = ? の様な SQL を発行してしまいます
foreach ($users->flatMap->podcasts as $podcast) {
    echo $podcast->subscription->created_at;
}

// 最初のクエリ発行時に with を使わずとも load メソッドでリレーション先を呼べます。
$users->load('podcasts')

Eloquent:リレーション 9.x Laravel

 こんな感じで便利な with や load ですがしばしばリレーション先を細かい制御をしつつ呼び出したい時があります。例えば論理削除を無視して呼び出す時などです。そういった時は次の様に書けます。

$users = User::with([
    // ここではキーで指定したリレーションメソッド名が返すリレーションクエリクラスのインスタンスを受け取るクロージャを使えます。
    'podcasts' => static function(\Illuminate\Database\Eloquent\Relations\HasMany $query) {
        // Laravel 組み込みの論理削除はグローバルスコープに↓のクラス名で登録されています
        $query->withoutGlobalScope(\Illuminate\Database\Eloquent\SoftDeletingScope::class)
            ->where('type', PodcastType::HOGE); // 普通のSQLで使うような句も構築できます
    }
])->get();

// load の場合も同様に配列で指定できます。

 このあたりを駆使していくと素の JOIN に近い感覚のクエリを構築することを少なくできます。「表で一覧画面を見たい」などの要望があった場合はどうにも JOIN 句込みの SQL が便利ですが、API など構造化されたデータの方が望ましい局面では特に便利な機能です。
 

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG