Laravel 6でindex()コントローラとビュー(Blade)を使ってレコード一覧を作るときに、Laravel標準ページネーションを使いつつ、キーワードによる絞り込み、1ページの表示数を指定できるようにする方法を紹介します。
指定した条件は、URLのクエリーパラメータに以下のような形で明示されるようにします。これにより、ユーザーがリンクをほかのユーザーに共有した時に、そのユーザーも同じ画面が見られます。
/customers?keyword=a&perpage=10&page=3
今回はCustomer
モデルの一覧画面という設定で見ていきましょう。
コントローラ
まずはコントローラ。
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リンク。これは標準のまま。
{{ $customers->links() }}
次に検索ボックス。
<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ページの行数指定ドロップダウンを作ります。
<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に渡しているのです。