動作環境
- Laravel 8.40.0
- PHP 8.0.3
- macOS 12.0.1
今回はフォーム検索機能を実装し、複数のパラメーターやキーワードに一致したものをデータベースから取得する方法を解説したいと思います。
さらに、検索キーワードに一致した文字列は黄色のマーカーを引いて表示するようにしてみます。
コントローラーの設定
今回は、旅行サイトの口コミをデータベース化したものから、フォームに入力した内容にマッチした口コミを取得し表示するというアプリケーションを例に説明していきます。
コントローラーにsearchアクションを定義していきます。
public function search(Request $request)
{
$q = Kuchikomi::query();
if(isset($request->client_id)){
$q->where('client_id', '=',$request->client_id);
}
if(isset($request->OTA)){
$q->where('OTA', '=',$request->OTA);
}
if(isset($request->score)){
$q->where('score', '=',$request->score);
}
if(isset($request->start_date)){
$q->where('reviewed_date', '>=',$request->start_date);
}
if(isset($request->end_date)){
$q->where('reviewed_date', '>=',$request->end_date);
}
if(isset($request->end_date)){
$q->where('score', '=',$request->score);
}
if(isset($request->keyword) && $request->keyword_type === "or"){
$keywords = explode(",", $request->keyword);
$q->where(function ($query) use($keywords) {
foreach($keywords as $keyword){
$query->orWhere('review', 'LIKE',"%$keyword%");
}
});
} elseif(isset($request->keyword)) {
$keywords = explode(",", $request->keyword);
foreach($keywords as $keyword){
$q->where('review', 'LIKE',"%$keyword%");
}
}
// \DB::enableQueryLog();
$results = $q->get();
// dd(\DB::getQueryLog());
$results->count=count($results);
// 文字をハイライトする
if(isset($request->keyword)) {
foreach($results as $result){
$keywords = explode(",", $request->keyword);
$result->review = $this->search_text_highlight($keywords, $result->review);
}
}
// クライアントユーザー(is_admin=0)のみを抽出する
$users=DB::table('users')->where('is_admin', 0)->get();
return view('kuchikomis/searchResults',['results' => $results,'users'=>$users]);
}
/**
* 文字列から検索したい文字を検索しヒットしたらハイライトする
*
* @param array $keywords 検索したいキーワード
* @param string $target_string 検索対象の文字列
* @return string $target_string
*/
public function search_text_highlight($keywords, $target_string)
{
// 検索対象文字列が空であれば、文字列をそのまま返す
if(empty($keywords)){
return $target_string;
}
foreach($keywords as $keyword){
// 検索文字列がヒットしたらハイライトして返す
if( ($pos = mb_strpos($target_string, $keyword, 0, 'UTF-8')) !== false ){
// 対象文字列から、検索文字列を取得する
$str = mb_substr($target_string, $pos, mb_strlen($keyword, 'UTF-8'), 'UTF-8');
// 対象文字列から検索文字列をハイライトする
$target_string = str_replace($str, "<span style='background-color:yellow'>{$str}</span>", $target_string);
}
}
return $target_string;
}
解説
検索フォームのパラメーターによってWhere句を動的に組み立てていく
検索フォームは入力した内容によって様々な条件の組み合わせが渡ってくるので、それに対応できるように、if文でクエリを組み立てていきます。
if文をコンパクトにしたいという場合は{}を省略して下記のように1行の書き方でも可能。
if(isset($request->client_id)) $q->where('client_id', '=',$request->client_id);
実行されるSQLを確認したい場合は下記のようにクエリを囲んでみる。
クエリが複雑になってきた際に、実際どのようなSQLが実行されるか確認できるので便利です。
\DB::enableQueryLog();
$results = $q->get();
dd(\DB::getQueryLog());
検索条件にキーワード含まれている場合、マッチしたテキストに黄色マーカーを引く
検索条件にマッチしたデータを全て取得後、search_text_highlight()関数でテキストに黄色マーカーを引いていきます。
str_replaceで検索文字列を<span style='background-color:yellow'>hoge</span>に置換していくことでblade側で表示する際に黄色マーカーが引かれます。
>> 参考:【Laravel】BladeでHTMLを出力させる方法
今回はviewのフォーム部分の解説は省略いたしますが、これで検索を実行するとsearchアクションが動作し、検索結果を表示すると同時にマッチしたキーワードがあれば黄色マーカーで検索結果を表示してくれるようになります。