ページネーションのデータを変える」の続きです。検索画面を用意して検索結果をページネーションします。

検索画面のページネーション

まず、こんな検索画面を作りたいです。

検索項目に値を入れると、値により絞り込まれた検索結果が表示されます。ごく普通の検索画面です。画面の右下にはページネーションも表示されます。ここでは1画面に2レコードだけ表示です。

routeの定義は、GETだけで十分です。そう、検索条件はすべてURLに入れます。

...
Route::get('/search', [SearchController::class, 'index'])->name('search');
..

コントローラの作成も簡単です。あまりにも短いのでカットせずにすべて見せてしまいます。


namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function index(Request $request)
    {
        $query = User::query();

        if ($value = $request->name) {
            $query->where('name', 'like', "%{$value}%");
        }

        if ($value = $request->email) {
            $query->where('email', 'like', "%{$value}%");
        }

        $users = $query->paginate(2);

        return view('user.search', compact('users'));
    }
}

しかし、このコード大いに問題ありです。先の画面でページネーションの2ページをクリックすると、

検索結果3件だったのに10件になっているし、ページネーションも2ページから5ページに。2ページ目なら表示するのは1件のみでは。
おかしいところだらけです。一番の問題はGETだから、ブラウザのURLには入力した値が追加されるのに、?page=2だけです。

この問題の解決はとても簡単です。

上のコントローラのコードで、withQueryString()を以下のように追加するだけなのです。


...
    public function index(Request $request)
    {
        $query = User::query();

        if ($value = $request->name) {
            $query->where('name', 'like', "%{$value}%");
        }

        if ($value = $request->email) {
            $query->where('email', 'like', "%{$value}%");
        }

        $users = $query->paginate(2)->withQueryString(); //ここに追加

        return view('user.search', compact('users'));
    }
...

修正した2ページ目の画面です。

URLに?email=example.com&page=2とクエリーの文字列が入っていますね。

クエリーをリファクター

上のコントローラのコードでは条件文のifを使い検索のクエリーを作成しています。
それ自体は問題は何もありません。すでに十分わかりやすいです。
しかし、Laravel風にすると以下のようにも書くことができます。


...
class SearchController extends Controller
{
    public function index(Request $request)
    {
        $query = User::query()
            ->when($request->name, function($query, $value) {
                    return $query->where('name', 'like', "%{$value}%");
            })
            ->when($request->email, function($query, $value) {
                return $query->where('email', 'like', "%{$value}%");
            });

        $users = $query->paginate(2)->withQueryString();

        return view('user.search', compact('users', 'request'));
    }
}
...

whereでなくwhenの関数となっているところに注意してください。最初の引数の値が存在するなら次で定義する匿名関数を実行です。

By khino