Laravelのページネーションのコードリーディングメモ。
$users = User::paginate(15);
<div class="container">
@foreach ($users as $user)
{{ $user->name }}
@endforeach
</div>
{{ $users->links() }}
ページネーションデータの準備
Builder::paginate()
で処理されます。
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null, $total = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$total = value($total) ?? $this->toBase()->getCountForPagination();
$perPage = ($perPage instanceof Closure
? $perPage($total)
: $perPage
) ?: $this->model->getPerPage();
$results = $total
? $this->forPage($page, $perPage)->get($columns)
: $this->model->newCollection();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
Paginator::resolveCurrentPage()
ではPaginator::currentPageResolver()
で設定したClosureを使ってページ番号を取得します。
Paginator::currentPageResolver(function ($pageName = 'page') use ($app) {
$page = $app['request']->input($pageName);
if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
return (int) $page;
}
return 1;
});
page
のリクエストパラメータから番号を取得、バリデーションした上で値を返しています。
Builder::getCountForPagination()
ではモデルのカウントを取っています。
https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Query/Builder.php#L3034-L3078
Builder::forPage()
ではページ番号、1ページあたりのレコード数を使ってOFFSET/LIMITでレコードを取得します。
public function forPage($page, $perPage = 15)
{
return $this->offset(($page - 1) * $perPage)->limit($perPage);
}
BuildsQueries::paginator()
ではLengthAwarePaginatorクラスのインスタンスを作成します。
protected function paginator($items, $total, $perPage, $currentPage, $options)
{
return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact(
'items', 'total', 'perPage', 'currentPage', 'options'
));
}
ページネーションの表示
LengthAwarePaginator::links()
は LengthAwarePaginator::render()
を呼び出しています。
public function links($view = null, $data = [])
{
return $this->render($view, $data);
}
render()
はビューをレンダリングしています。引数なしだと$defaultViewである pagination::tailwind
をレンダリングします。
public function render($view = null, $data = [])
{
return static::viewFactory()->make($view ?: static::$defaultView, array_merge($data, [
'paginator' => $this,
'elements' => $this->elements(),
]));
}
https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/LengthAwarePaginator.php#L89-L95 https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/AbstractPaginator.php#L117 https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/resources/views/tailwind.blade.php
pagination::
のnamespaceとビューファイル定義は以下で行っています。
public function boot()
{
$this->loadViewsFrom(__DIR__.'/resources/views', 'pagination');
// ...(省略)...
}
simplePaginate()
と cursorPaginate()
ちなみに、 simplePaginate()
の方を呼び出すと Paginator
のインスタンスが返り、これの links()
render()
メソッドは pagination::simple-tailwind
のビューをレンダリングしています。
https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/Paginator.php#L94-L111
https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/AbstractPaginator.php#L124
cursorPaginate()
は BuildsQueries::paginateUsingCursor()
経由で CursorPaginator
のインスタンスを返しています。
public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null)
{
$perPage = $perPage ?: $this->model->getPerPage();
return $this->paginateUsingCursor($perPage, $columns, $cursorName, $cursor);
}
https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Builder.php#L976-L981 https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Concerns/BuildsQueries.php#L371-L452