今回はLaravelでちょっと複雑なデータ取得の方法を解説します。
この記事はLaravelを少しかじったことのある方向けなので、基本的な部分は省略しています。ご了承ください。
モデルと各モデルのリレーション(Eloquent)
まず、モデルは以下の4つです。
- User(ユーザー)
- Product(商品)
- Category(商品カテゴリー)
- Bookmark(お気に入り)
各モデルのidは次のようなつながりがあり、
次のような関係性です。
public function bookmarks()
{
//1人のユーザーは多数のお気に入りを持っている
return $this->hasMany('App\Bookmark', 'user_id');
}
public function category()
{
//1つの商品は1つのカテゴリーに属している
return $this->belongsTo('App\Category', 'category_id', 'id');
}
public function products()
{
//1つのカテゴリーは多数の商品を持っている
return $this->hasMany('App\Product', 'category_id', 'id');
}
public function user()
{
//1つのブックマークは1人のユーザーに属している
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function product()
{
//1つのブックマークは1つの商品に属している
return $this->belongsTo('App\Product', 'product_id', 'id');
}
取得したいデータはユーザーの「お気に入り一覧」
今回取得するデータは、ユーザーがお気に入り登録をした商品一覧です。
お気に入り商品一覧には、それぞれが属しているカテゴリー名も必要で、なおかつ商品自体が「論理削除されていないもの」に限定します。
論理削除は、LaravelのsoftDeletes()を利用するので、商品テーブルのdeleted_atカラムが入力されていたら削除されていると判断できます。
Laravelの便利なwith関数を使ってネストした先のデータを取得する
//ログインユーザーの場合
$bookmarks = Auth::user()->bookmarks()->with('product.category')
->whereHas('product', function ($query) {
$query->whereNotNull('deleted_at'); //商品のdeleted_atカラムがnullでないもの
})->latest(); //最新のデータから取得
特定のユーザーの場合は、idを指定すれば良いですね。
さて、先ほどEloquentによりモデル同士のリレーションを定義しました。
そのため、ユーザーのお気に入りは ->bookmarks() で取得できます。
bookmarkテーブルのproduct_idによってどの商品がお気に入りなのか判別でき、->with(‘product’)で商品名やその他の情報と一緒に取得できます。
商品は、各々がそれぞれカテゴリーに属していました。
こちらのリレーションも先ほど定義しているので、->with(‘product.category’)でその商品の属しているカテゴリー情報も取得しましょう。
with関数はとても便利ですね〜!
今回のように、productとcategoryをドットで繋げることで商品の属するカテゴリー情報まで引っ張ってこれるんです。
このようなデータ取得方法を「ネストしたEagerロード」と言います。
は?
て感じですよね!
Eagerロードは、リレーションデータの遅延読み込みです。
膨大な数のクエリでタイムアウトしてしまわないように採用される仕組みだとか。
プログラミングは検索力が命ですが、こういった「専門用語」を知っているかどうかで答えにたどり着くスピードが違います。日々勉強ですな〜。