Laravel クエリの切り出し、ローカルスコープ

クエリの切り出し

コントローラでの記述を無くし、ファットコントローラを防ぐ為、モデルに共通クエリ制約(ローカルスコープ)の定義する。 readouble.com

ローカルスコープ

お作法として、メソッドの頭にscopeとつけて引数に$queryとし、戻り値に$queryと書く必要がある。

※スコープの中では->get->pagenateなどは書かない。そこでクエリ処理がが止まる為

コントローラーで使う場合はメソッド名のscopeを外した名前を書く。

モデル
<?php
public function scopeAvailableItems($query)
    {
//t_stocksテーブルのproduct_idをグループ化して、Havingでquantityを結合
        $stocks = DB::table('t_stocks') 
//Laravelの場合、select内でsumを使うため クエリビルダのDB::rawで対応する
        ->select('product_id', DB::raw('sum(quantity) as quantity')) 
        ->groupBy('product_id') 
        ->having('quantity', '>', 1);
        return $query

        ->joinSub($stocks, 'stock', function($join){
//さらにproductとshopテーブルをjoinで結合
        $join->on('products.id', '=', 'stock.product_id'); })

//shopsテーブルのidとproductsテーブルのproduct_idを結合
        ->join('shops', 'products.shop_id', '=', 'shops.id')
        ->join('secondary_categories', 'products.secondary_category_id', '=', 'secondary_categories.id')

//imagesテーブルのidとproductsテーブルのimage1を結合
        ->join('images as image1', 'products.image1', '=', 'image1.id')

//shopsとproductsのis_sellingがtrueならgetする
        ->where('shops.is_selling', true)
        ->where('products.is_selling', true)

//複数のテーブルを紐付ける為、同じ列名が存在するのでテーブル名.列名 as 名前のように指定する。
        ->select('products.id as id', 'products.name as name', 'products.price' ,'products.sort_order as sort_order',
        'products.information', 'secondary_categories.name as category' ,'image1.filename as filename');
    }
  • WHERE・・・「GROUP BY」の影響の前に条件が適応
  • HAVING・・・「GORUP BY」の影響のあとに条件が適応
コントローラー
<?php
public function index()
    {
        $products = Product::availableItems()->get();
        return view('user.index', compact('products'));
    }