環境
Laravel: 8.82.0
PHP: 8.1.2
OR検索
文字列で検索ができるようにOR検索を導入しようとしたときでした。
とりあえず少し調べて、以下のコードで実行しました。
$keyword = $request->keyword;
$user = Auth::user();
$items = $user->items()->where("name", "like", "%".$keyword."%")
->orWhere("text", "like", "%".$keyword."%")->get();
これで OR 検索をしようとすると、
->where("name", $keyword)
は、ログインしている User の結果だけを返すのですが、
->orWhere("text", $keyword)
は、全ての Userの結果を返すのです。
なんでやねん!
とツッコミを入れながらも、改善案を探すことにしました。
ダメな理由
ダメな理由は条件の書き方にありました。
$user
のitem
に対してname
またはtext
がキーワードを含んでいたら、というつもりで書いていました。
つまり、item
に対しての条件で考えていたのです。
しかし、先程の記述では
$user
のitem
に対してname
がキーワードを含む
または、$user
に対してtext
がキーワードを含んでいたらになっていたのです。
その際に、$user
にtext
というカラムが存在しないため、
全件一致という扱いを受けて、実質$user->all()
(全ての User)と同義になってしまったという訳です。
これでは想定している動作とは異なるので、
条件の書き方を修正する必要があります。
where
でまとめる
検索してみると、where
をまとめることができるようです!
早速まとめてみます!
$keyword = $request->keyword;
$user = Auth::user();
$items = $user->items()->where(function ($query) {
$query->where("name", "like", "%".$keyword."%")
->orWhere("text", "like", "%".$keyword."%");
})->get();
これで大丈夫と思ったのですが、エラーが出ます。
スコープの問題で、「$keyword
なんて知らない」といわれます。
これでも悩みました。。。
use
で変数を渡す
そうしていると、先輩が解決方法を教えてくださり、
$keyword = $request->keyword;
$user = Auth::user();
$items = $user->items()->where(function ($query) use ($keyword) {
$query->where("name", "like", "%".$keyword."%")
->orWhere("text", "like", "%".$keyword."%");
})->get();
use
を使って解決できたのでした。