こんにちは!
見出しは、なんか某アニメ映画のタイトルみたいなになっていますが、、、
要は、Laravelでリレーションを組んでいた場合、主テーブルに紐付いている従テーブルを絞り込むか、従テーブルを元に主テーブルを絞り込むか、の解説をしていきます。
主テーブル・・・・・主キー(id)を持つテーブル
従テーブル・・・・・外部キー(***_id)を持つテーブル
今回は例として、
ゲーム情報を取得時に、特定のユーザーが登録しているゲームのお気に入り情報を取得する場合 (withメソッドを使う)
ゲーム情報を取得時に、特定のユーザーがお気に入りをしているゲームを取得 (whereHasメソッドを使う)
というケースを考えます。
目次
環境
今回の環境
- PHP 8.1.1
- Laravel 9.19
テーブル構造
記事用なので簡潔に書きます。
ゲーム一覧テーブル (game)
ゲーム一覧を管理するテーブルになります。
| カラム名 | データ内容 | FK | 
| id | ID | |
| game_name | ゲーム名 | 
ゲームお気に入りテーブル (favorite)
ゲームをお気に入りした場合、このテーブルにレコードが追加されます。
| カラム名 | データ内容 | FK | 
| id | ID | |
| game_id | ゲームID | ○ | 
| user_id | ユーザーID | ○ | 
ユーザーテーブル (users)
ユーザーを管理するテーブルになります。
| カラム名 | データ内容 | FK | 
| id | ID | |
| name | ユーザー名 | 
モデルファイル
ゲーム一覧モデル
ゲームモデルに、ゲームお気に入りモデルのリレーションを設定します。
ゲームは、いろんなユーザーがお気に入り登録できるので、1対多の関係になります。
public function favorite()
{
    return $this->hasMany('App\Models\FavoriteGames');
}リレーション先を絞り込む場合
リレーション先を絞り込む(主テーブルに紐付いている従テーブルを絞り込む)場合を見ていきます。
例えば、特定のユーザーのお気に入り情報が欲しい場合、リレーション先である、お気に入りテーブルのuser_idを絞り込む必要があります。
その場合、以下のようにwithメソッドの中でクロージャーを使います。
Games::with(['favorite' => function ($query) use ($user_id) {
    $query->where('user_id', $user_id);
}])->where('id', $game_id)->first();実際にゲームid=1のゲーム取得時に、ユーザーid=2のお気に入り情報のみを取得したい場合は、以下のようになります。
>>> Games::with(['favorite' => function ($query) {
        $query->where('user_id', 2);
    }])->where('id', 1)->first();
=> App\Models\Games {#3687
     id: 1,
     game_name: ファイナルファンタジー
     favorite: Illuminate\Database\Eloquent\Collection {#4831
       all: [
         App\Models\FavoriteGames {#4226
           id: 2,
           games_id: 1,
           user_id: 2,
         },
       ],
     },
   }withメソッドのクロージャー内で、user_idを絞らないと、そのゲームお気に入り登録しているすべてのユーザー情報も取得してしまいます。
>>> Games::with(['favorite'])->where('id', 1)->first();
=> App\Models\Games {#3687
     id: 1,
     game_name: ファイナルファンタジー
     favorite: Illuminate\Database\Eloquent\Collection {#4831
       all: [
         App\Models\FavoriteGames {#4224  => ここユーザーの情報入らない
           id: 1,
           games_id: 1,
           user_id: 1,
         },
         App\Models\FavoriteGames {#4226
           id: 2,
           games_id: 1,
           user_id: 2,
         },
       ],
     },
   }リレーション先で絞り込む場合
次にリレーション先で絞り込む(従テーブルを元に主テーブルを絞り込む)場合を見ていきます。
今回の場合、特定のユーザーが、お気に入りをしているゲームのみ取得したい場合、になります。
その場合、以下のようにwhereHasメソッドを使います。
Games::whereHas('favorite', function ($query) use ($user_id) {
    $query->where('user_id', $user_id);
});実際に、ユーザーid=2がお気に入り登録しているゲームを取得してみます。
>>> Games::whereHas('favorite', function ($query) {
        $query->where('user_id', 2);
    })->get();
=> Illuminate\Database\Eloquent\Collection {#3697
     all: [
       App\Models\Games {#3708
         id: 60,
         game_name: "ポケモン",
       },
       App\Models\Games {#3680
         id: 61,
         game_name: "デジモン",
       },
       App\Models\Games {#3715
         id: 62,
         game_name: "フジモン",
       },
     ],
   }以上になります。
