Laravelで複数検索機能を実装する手順

検索機能の実装にはたくさんのアプローチがあると思いますが、その中でも個人的に理解しやすかった方法があったので備忘録としてまとめています。
## やりたいこと
viewsの一覧画面からgetで検索したい内容を渡し、その検索結果を一覧画面に反映させます

## 前提
マイグレーションを作成します。同時にモデルも生成します。

```php:2023_01_21_122803_create_items_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateItemsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained('users');
            $table->string('name');
            $table->string('status');
            $table->integer('type');
            $table->string('detail');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('items');
    }
}

```

viewsの中でgetで送るformを作成します。nameとdetailを送る想定です

```php:show.blade.php
商品管理システム

<form action="{{route('item.show')}}" method="get">
<input type="text" name="search" placeholder="名前検索" value="{{request()->search}}" >
<input type="text" name="search2" placeholder="詳細検索" value="{{request()->search2}}" >
<button type="submit">検索</button>
</form>

```
viewsでは下記のような形で一覧を反映していきます。


```php:show.blade.php
<table>
<tr>
    <th>ID</th>
    <th>名前</th>
    <th>種別</th>
    <th>詳細</th>
</tr>
@foreach ($items as $item )
<tr>
   <td>{{$item->id}}</td>
   <td>{{$item->name}}</td>
   <td>{{$item->type}}</td>
   <td>{{ Str::limit($item->detail, 30, '...') }}</td>
</tr>
@endforeach
</table>
```
## Controllerでの処理
本題です。
検索フォームに入力があればその部分を取り出し何もなければ全てのデータを取り出す一覧画面をController側で実装します。

```php:ItemController.php
    public function show(Request $request)
    {
        $query = Item::query();
        if (!empty($request->input('search'))) {
            $search_split = mb_convert_kana($request->input('search'), 's');
            $search_split2 = preg_split('/[\s]+/', $search_split);
            foreach ($search_split2 as $value) {
                $query->Where('name', 'LIKE', "%{$value}%");
            }
        }
        if (!empty($request->input('search2'))) {
            $search_split = mb_convert_kana($request->input('search2'), 's');
            $search_split2 = preg_split('/[\s]+/', $search_split);
            foreach ($search_split2 as $value) {
                $query->Where('detail', 'LIKE', "%{$value}%");
            }
        }
        $items = $query->get();
        return view('item.show', compact('items'));
    }
```

上記のif文の処理内容について説明します。
```php:
if (!empty($request->input('search'))) {
            $search_split = mb_convert_kana($request->input('search'), 's');
            $search_split2 = preg_split('/[\s]+/', $search_split);
            foreach ($search_split2 as $value) {
                $query->Where('name', 'LIKE', "%{$value}%");
            }
        }
```
これはformから渡ってきたname='search'の中身が空かどうかで判別しています。空でない場合の処理が中に羅列してあります。
まず、mb_convert_kanaでカナを全角に変換します。第二引数は's'を記述します。これによって全角スペースを半角スペースに変換できます。詳しくはphpの公式マニュアルを参考にしてください。
- https://www.php.net/manual/ja/function.mb-convert-kana.php

次にpreg_splitで半角スペースで区切って配列に直してあげます。mb_convert_kanaで全角スペースを半角スペースに直したのはこのためです。これによって検索のキーワードをChromeみたいにスペース区切りでも検索できるようになります。
あとはformから送られてくるnameが増えた分だけ同じように複製してあげれば複数検索も可能です。

最後にforeach文で配列の中身をLikeで文字列検索してあげて、$query->get()をview側に投げれば完了です。