laravelで検索機能を実装する

今回は文字列を入力して部分一致検索、プルダウンメニューから選択して検索を行う機能を実装します。具体的には下記の画面でユーザ名、棋力、好きな戦法による検索を行います。
![11fdea620d70330aa57c7896d10a1faa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477146/70300c4e-c3e3-29d1-be21-af5d63b9b03d.png)


Userモデルは以下のように name（ユーザ名）、stength（棋力）、tactics（好きな戦法）というカラムを定義します。

```

class User extends Authenticatable
{
    protected $fillable = [
        'name','strength','tactics',
    ];
}
```


コントローラは以下のようなindexメソッドを定義します。

```
class SearchController extends Controller
{
    public function index(Request $request){
        $query = User::query();
        
　　　　　//$request->input()で検索時に入力した項目を取得します。
        $search1 = $request->input('strength');
        $search2 = $request->input('tactics');
        $search3 = $request->input('name');

         // プルダウンメニューで指定なし以外を選択した場合、$query->whereで選択した棋力と一致するカラムを取得します
        if ($request->has('strength') && $search1 != ('指定なし')) {
            $query->where('strength', $search1)->get();
        }
      
         // プルダウンメニューで指定なし以外を選択した場合、$query->whereで選択した好きな戦法と一致するカラムを取得します
        if ($request->has('tactics') && $search2 != ('指定なし')) {
            $query->where('tactics', $search2)->get();
        }
        
        // ユーザ名入力フォームで入力した文字列を含むカラムを取得します
        if ($request->has('name') && $search3 != '') {
            $query->where('name', 'like', '%'.$search3.'%')->get();
        }
        
　　　　//ユーザを1ページにつき10件ずつ表示させます
        $data = $query->paginate(10);
     
        return view('users.search',[
            'data' => $data
        ]);
    }
}
```

検索ボタンを押したときのルーティングを以下のように記述します。

```
//検索ボタンを押すとコントローラのindexメソッドを実行します
Route::get('Search','SearchController@index')->name('search');
```

ユーザ検索ページのビューを以下のように記述します。

```
    <div class="row">
        <div class="col-sm-4">
            <div class="text-center my-4">
                <h3 class="brown border p-2">ユーザ検索</h3>
            </div>
            {!! Form::open(['route' => 'search', 'method' => 'get']) !!}
                <div class="form-group">
                    {!! Form::label('text', 'ユーザ名:') !!}
                    {!! Form::text('name' ,'', ['class' => 'form-control', 'placeholder' => '指定なし'] ) !!}
                </div>
                <div class="form-group">
                    {!! Form::label('strength', '棋力:') !!}
                    {!! Form::select('strength', ['指定なし' => '指定なし'] + Config::get('strength.kiryoku') ,'指定なし') !!}
                </div>
                <div class="form-group">
                    {!! Form::label('tactics', '好きな戦法:') !!}
                    {!! Form::select('tactics', ['指定なし' => '指定なし'] + Config::get('tactics.senpou') , '指定なし') !!}
                </div>
                {!! Form::submit('検索', ['class' => 'btn btn-primary btn-block']) !!}
            {!! Form::close() !!}
        </div>
        <div class="col-sm-8">
            <div class="text-center my-4">
                <h3 class="brown p-2">ユーザ一覧</h3>
            </div>
            
            <div class="container">
                <!--検索ボタンが押された時に表示されます-->
                @if(!empty($data))
                    <div class="my-2 p-0">
                        <div class="row  border-bottom text-center">
                            <div class="col-sm-4">
                                <p>ユーザ名</p>
                            </div>
                            <div class="col-sm-4">
                                <p>棋力</p>
                            </div>
                            <div class="col-sm-4">
                                <p>好きな戦法</p>
                            </div>
                        </div>
　　　　　　　　　　　　　　//検索条件に一致したユーザを表示します
                        @foreach($data as $item)
                                <div class="row py-2 border-bottom text-center">
                                    <div class="col-sm-4">
                                        <a href="">{{ $item->name }}</a>
                                    </div>
                                    <div class="col-sm-4">
                                        {{ $item->strength }}
                                    </div>
                                    <div class="col-sm-4">
                                        {{ $item->tactics }}
                                    </div>
                                </div>
                        @endforeach
                    </div>
                    {{ $data->appends(request()->input())->render('pagination::bootstrap-4') }}
                @endif
            </div>
        </div>
    </div>

```
ここでは以下のように、あらかじめconfigディレクトリにstrength.phpを作成して'kiryoku'という配列を定義しています。上記のビューではconfig::get('strength.kiryoku')でその配列を取得して、プルダウンメニューを作成しています。さらに`['指定なし' => '指定なし'] + config::get('strength.kiryoku')`としてkiryoku配列に「指定なし」という要素を追加しています。


config/strength.php

```

<?php 
return array(
    'kiryoku' => array(
  '10級' => '10級', 
  '9級' => '9級', 
  '8級' => '8級', 
  '7級' => '7級',
  '6級' => '6級', 
  '5級' => '5級', 
  '4級' => '4級', 
  '3級' => '3級',
  '2級' => '2級', 
  '1級' => '1級', 
  '初段' => '初段', 
  '二段' => '二段',
  '三段' => '三段', 
  '四段' => '四段', 
  '五段' => '五段', 
  '六段' => '六段',
  ),
);
?>
```
config::get('tactics.senpou')も同様です。
config/tactics.php

```
<?php 
return array(
    'senpou' => array(
  '角換わり' => '角換わり', 
  '矢倉' => '矢倉', 
  '相掛かり' => '相掛かり', 
  '横歩取り' => '横歩取り',
  '向かい飛車' => '向かい飛車', 
  '三間飛車' => '三間飛車', 
  '四間飛車' => '四間飛車', 
  '中飛車' => '中飛車'
  ),
);
?>
```

ユーザ名のみで検索すると、以下のように正しく表示されました。
![40f910bb147f96bbc5217e4810dd315e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477146/df34dcd3-4f48-8ca9-bde3-696781e0729d.png)

また棋力、好きな戦法で検索した場合も、以下のように正しく表示されました。
![78290b7b15c518d244dee790a40b7dc0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477146/1aaf2f25-24e2-5570-7f28-e3b35c602290.png)

今回の検索機能のポイントは、コントローラの`$request->input`メソッドと`$query->where`メソッドかなと思いました。あとプルダウンメニューの実装はconfigファイルを使用しましたが、意外と躓きました。プルダウンメニューはほかの方法でより簡単に実装できるのかもしれません。