Edited at

Laravel 6で一覧ページに検索窓とページ行数指定を付ける

 Laravel 6でindex()コントローラとビュー(Blade)を使ってレコード一覧を作るときに、Laravel標準ページネーションを使いつつ、キーワードによる絞り込み、1ページの表示数を指定できるようにする方法を紹介します。

 指定した条件は、URLのクエリーパラメータに以下のような形で明示されるようにします。これにより、ユーザーがリンクをほかのユーザーに共有した時に、そのユーザーも同じ画面が見られます。

/customers?keyword=a&perpage=10&page=3

image.png

今回はCustomerモデルの一覧画面という設定で見ていきましょう。


コントローラ

まずはコントローラ。


CustomerController.php

    public function index(Request $request)

{
$query = Customer::query();

$keyword = $request->input('keyword');
if (!empty($keyword)) {
$query->where('name', 'like', '%' . $keyword . '%');
}

$perpage = $request->input('perpage', 10);

//paginate
$customers = $query->paginate($perpage);
return view('customers.index', ['customers' => $customers->appends($request->except('page')), 'request'=>$request->except('page')]);
}


順に見ていきます。

検索キーワードと表示行数の入力をコントローラで受け取るため、Requestオブジェクトをパラメータに追加します。

public function index(Request $request)

次に検索条件を追加できるようにCustomerモデルからクエリービルダーを取得します。

        $query = Customer::query();

検索キーワードをGetパラメータから取得し、指定があればwhere句を追加します。

        $keyword = $request->input('keyword');

if (!empty($keyword)) {
$query->where('name', 'like', '%' . $keyword . '%');
}

また、表示行数もGetパラメータから取得し、指定があればその数値、なければ10行とします。

Requestオブジェクトのinputメソッドに第2パラメータを指定すると、規定値として処理してくれます。

        $perpage = $request->input('perpage', 10);

指定条件で絞って、さらにページ処理(Pagination)を施した結果のCustomer一覧を取得します。

        $customers = $query->paginate($perpage);

最後にcustomers.indexというblade(ビュー)に、絞り込んだ$customersを渡します。

        return view('customers.index', ['customers' => $customers->appends($request->except('page')), 'request'=>$request->except('page')]);

このとき、customerのPaginationがpage以外のGetパラメータを適切に取り扱えるよう、以下のようにパラメータを渡しています。

'customers' => $customers->appends($request->except('page'))

さらにbladeに、手動でGetパラメータ全体(Page以外)を渡しています。

'request'=>$request->except('page')]


 ビュー

まずPaginationリンク。これは標準のまま。


index.blade.php

{{ $customers->links() }}


次に検索ボックス。


index.blade.php

<form method="get">

@foreach ($request as $key=>$value)
@if ($key!="keyword")
<input type="hidden" name="{{$key}}" value="{{$value}}" />
@endif
@endforeach
<input type="text" class="form-control" name="keyword" placeholder="Name" value="{{$request["keyword"] ?? ""}}">
</form>

自分のパラメータであるkeyword以外についてはhiddenで保持します。ただしpageはコントローラ側で排除したので、ここに保持されません。つまり、キーワード検索を実施すると必ず1ページ目に戻ることになります。

さらに、inputボックスの値は{{$request["keyword"] ?? ""}}とし、キーワードが既に指定されていればそれ、なければ空文字列とします。なお、??はPHP7以降で導入されたnull合体演算子という便利な三項演算子です。

同じように1ページの行数指定ドロップダウンを作ります。


index.blade.php

<form method="get">

@foreach ($request as $key=>$value)
@if ($key!="perpage")
<input type="hidden" name="{{$key}}" value="{{$value}}" />
@endif
@endforeach
<select class="custom-select" name="perpage" onchange="this.form.submit()">
<option value="10" {{($request["perpage"] ?? "")==10?"selected":""}}>10</option>
<option value="20" {{($request["perpage"] ?? "")==20?"selected":""}}>20</option>
<option value="50" {{($request["perpage"] ?? "")==50?"selected":""}}>50</option>
<option value="100" {{($request["perpage"] ?? "")==100?"selected":""}}>100</option>
</select>
</form>

形は違いますがやってることは上と同じです。

本来なら行数指定がまだの場合、デフォルトの選択が何になるか明示すべきですが、デフォルトの選択肢が一番上に来ているため、初期状態の"selected"指定はなし=一番上になる、ということにして手抜きしています。


なぜcustomersに格納されているパラメータを使わないのか

 コントローラからビューに渡す$customersには、実はクエリーパラメータが格納されています。しかし、このパラメータは仕様上protectedになっていて、blade内で読むことはできません。そのため、自前で$requestをbladeに渡しているのです。