Laravelの検索機能の基本操作を学ぶ

来週以降検索機能の実装を行っていくので検索機能について基本を抑えていく。

# 基本的な「部分一致」検索
記事(post)のタイトルに対しての例

コントローラー

    public function search(Request $request)
    {
        $keyword = $request->input('keyword');
        //inputの入力データを$keywordに格納    
        $posts = Post::query();
        //Postモデルに対してインスタンスを取得する。
        if ($keyword) {
        //keywordが空でなければ真
            $posts->where(function($query) use ($keyword) {
            //keywordを利用して検索条件を追加。
                $query->where('title', 'like', '%' . $keyword . '%')
                
                //whereで絞る。where(カラム名, 比較演算子, 比較する値)
                //like 部分一致
                //'%'0文字以上 「.」
                //titleカラムの場所でkeywordの値がどこかに入っていれば。
                      ->orWhere('content', 'like', '%' . $keyword . '%');
                      //orWhereまたはを追加。
            });
        }
    
        $posts = $posts->latest()->paginate(10);
        //latest()最新順
        //paginate(10)１ページあたり10件

    
        return view('posts.index', compact('posts', 'keyword'));    
    }

上記の内容でタイトル、内容のカラムの中にkeywordが入っているものを絞り込みで出す。

# 複数条件検索（複数の入力項目）

タイトルとキーワード、作成日で検索する場合


    public function search(Request $request)
    {
        $query = Post::query();
        //Postモデルに対してクエリビルダーインスタンスを作成。
    
        if ($request->filled('title')) {
            $query->where('title', 'like', '%' . $request->input('title') . '%');
        }
        //titleというキーが存在すること。
        //タイトルカラムで部分一致
    
        if ($request->filled('from_date')) {
            $query->whereDate('created_at', '>=', $request->input('from_date'));
        }
        //wherreDateは日付の比較を行うメソッド。
        //'>='開始日以降の条件
    
        if ($request->filled('to_date')) {
            $query->whereDate('created_at', '<=', $request->input('to_date'));
        }
        //'<='終了日以前
    
        $posts = $query->latest()->paginate(10);
    
        return view('posts.index', compact('posts'));
    }

これで
titleカラムにキーワードがあり、かつ、入力された日時以降から入力された日時までの範囲で縛る。

# 関連モデルを使った検索

PostがCategoryに属していてカテゴリ名で検索する場合


モデル
    public function category()
    {
        return $this->belongsTo(Category::class);
    }


コントローラー

    public function search(Request $request)
    {
        $keyword      = $request->input('keyword');
        $categoryName = $request->input('category');
        //ユーザーが入力した情報を取得。
    
        $query = Post::query();
        //インスタンスを生成して検索できるようにする。
        if ($keyword) {
            $query->where(function ($q) use ($keyword) {
                $q->where('title', 'like', '%' . $keyword . '%')
                  ->orWhere('content', 'like', '%' . $keyword . '%');
            });
            //検索のグループ化
            //whereの条件をまとめている・
            //titleまたはcontentにkeywordが含まれている。
        }
    
        if ($categoryName) {
            $query->whereHas('category', function ($q) use ($categoryName) {
                $q->where('name', 'like', '%' . $categoryName . '%');
            });
        }
        //whereHasメソッドリレーションが設定されている場合、リレーション先の条件を絞る。
        //categoryを絞っていく。
        //nameにcategoryNameが含まれているもの。
        //それの部分一致。
    
        $posts = $query->latest()->paginate(10);
    
        return view('posts.index', compact('posts', 'keyword', 'categoryName'));
    }

上記の内容でtitleかcontentにkeywordが入っている。
かつ
categoryテーブルのnameカラムにcategoryNameが入っているもの。
を検索できるようになる。


## 補足と追加
### クロージャ(無名関数)
名前を持たずにその場で定義できる使い捨ての関数。


    $func = function($x) {
        return $x * 2;
    };
    echo $func(5); // 10

($x)はその中で使うパラメーターを入れる変数。

    $query->where(function ($q) use ($keyword) {
        $q->where('title', 'like', '%' . $keyword . '%')
          ->orWhere('content', 'like', '%' . $keyword . '%');
    });

function($q)がクロージャ
useを使うことで定義した場所以外の外部変数を取り込むことができる。

検索の基本はこれだけっぽい。
でもリレーション先とかの引き出し方とか分かればもうできるはずだよね。
明日この基本知識を元に追加機能にチャレンジしていく。