Database: Pagination
Table of Contents
Introduction
他のフレームワークでは、 pagination は非常に困難な作業になることがあります。それに対し、Laravel の pagination アプローチは新鮮な息吹を提供することでしょう。Laravel の paginator は、query builderとEloquent ORMと統合されており、設定不要で database レコードの pagination を簡単に、便利に提供します。
default として、 paginator が生成する HTML はTailwind CSS フレームワーク と互換性があります。ただし、ブートストラップの pagination サポートも利用可能です。
Tailwind JIT
もし Laravel の default な Tailwind の pagination views と Tailwind JIT エンジンを使用している場合、tailwind.config.js
ファイルの content
キーが Laravel の pagination views を参照するように、アプリケーションを確認すべきです。それにより、その Tailwind クラスはパージされないでしょう:
content: [
'./resources/**/*.blade.php',
'./resources/**/*.js',
'./resources/**/*.vue',
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
],
Basic Usage
Query ビルダー結果のページネーション
いくつかの方法があります。最も簡単な方法は、query ビルダーやエロキュアント queryでpaginate
method を使用することです。paginate
method は、現在 user が閲覧しているページに基づいて、自動的に query の"limit"と"offset"を設定します。default では、現在のページは HTTP request のpage
query ストリング引数の value によって検出されます。この value は Laravel によって自動的に検出され、また、生成される links に自動的に挿入されます。
この例では、paginate
method に渡される唯一の引数は、"ページあたり"に表示したいアイテムの数です。この場合、1 ページあたり15
項目を表示したいと指定しましょう。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Show all application users.
*/
public function index(): View
{
return view('user.index', [
'users' => DB::table('users')->paginate(15)
]);
}
}
シンプルな Pagination
paginate
method は、レコードを database から取得する前に、 query によって一致したレコードの総数を数えます。これは、 paginator がレコードのページ数を合計でどれだけあるかを知るために行われます。しかし、アプリケーションの UI で総ページ数を表示する予定がないなら、レコード数を数える query は必要ありません。
したがって、あなたが application の UI で単純な "Next" と "Previous" links だけを表示する必要がある場合は、simplePaginate
method を使って、 single , 効率的な query を実行することができます。
$users = DB::table('users')->simplePaginate(15);
Eloquent 結果のページネーション
あなたはまた、Eloquentのクエリをページ分割することもできます。この例では、App\Models\User
model をページ分割し、1 ページあたり 15 レコードを表示する予定であることを示します。ご覧の通り、構文は、query ビルダーの結果をページ分割するのとほぼ同一です。
use App\Models\User;
$users = User::paginate(15);
もちろん、他の制約をwhere
句のような query に設定した後で、paginate
method を呼び出すことができます。
$users = User::where('votes', '>', 100)->paginate(15);
また、simplePaginate
の method を使用して Eloquent models をページネーションすることも可能です:
$users = User::where('votes', '>', 100)->simplePaginate(15);
同様に、cursorPaginate
method を使用して、 cursor paginate Eloquent models を行うことができます。
$users = User::where('votes', '>', 100)->cursorPaginate(15);
ページごとの複数の Paginator インスタンス
時には、あなたの application によって rendering された single 画面上で 2 つの別々の paginator を render する必要があるかもしれません。ただし、両方の paginator インスタンスが現在のページを保存するために page
query string パラメータを使用すると、2 つの paginator が競合します。この競合を解決するために、paginator の現在のページを保存するために使用したい query string パラメータの名前を、 paginate
、simplePaginate
、そして cursorPaginate
method へ提供された第 3 引数を通して指定することができます。
use App\Models\User;
$users = User::where('votes', '>', 100)->paginate(
$perPage = 15, $columns = ['*'], $pageName = 'users'
);
Cursor Pagination
paginate
とsimplePaginate
は、SQL の"offset"句を使用してクエリを作成しますが、 cursor pagination は、"where"句を作成して query に含まれる並べ替えられた列の values を比較し、Laravel の全ての pagination メソッドの中で最も効率的な database パフォーマンスを提供します。この pagination の method は、大量のデータセットや無限スクロールの user インターフェースに特に適しています。
オフセットベースの pagination は、URL の query string にページ番号を含むのに対して、 paginator ベースの pagination は、 query string に cursor の string を配置します。 cursor は、次のページネーションされた query が開始するべき場所と、それが paginate するべき方向を含むエンコードされた string です。
http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
cursorPaginate
method を使用して、 query ビルダーが提供する cursor ベースの paginator インスタンスを作成することができます。この method は、Illuminate\Pagination\CursorPaginator
のインスタンスを返します。
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
cursor paginator インスタンスを取得したら、通常paginate
やsimplePaginate
メソッドを使用するときと同じように、ページネーション結果を表示することができます。 cursor paginator が提供するインスタンスメソッドの詳細については、cursor paginator インスタンスの method ドキュメンテーションをご参照ください。
WARNING
あなたの query は、 cursor pagination を活用するためには"order by"句を含める必要があります。さらに、" query "が並べ替えるカラムは、ページングしているテーブルに所属している必要があります。
Cursor vs. オフセット Pagination
offset ページネーションと cursor ページネーションの違いを図示するために、いくつかの SQLqueries の例を見てみましょう。次の両方の queries は、id
で並べ替えられたusers
テーブルの結果の 2 ページ目を表示します。
# Offset Pagination...
select * from users order by id asc limit 15 offset 15;
# Cursor Pagination...
select * from users where id > 15 order by id asc limit 15;
cursor pagination query はオフセット pagination に対して次のような利点を提供します:
- 大規模なデータセットに対しては、 cursor pagination が order by 列がインデックス化されている場合には、より良いパフォーマンスを提供します。これは、offset 句が以前に一致した data すべてをスキャンするためです。
- 頻繁に書き込みが行われるデータセットの場合、オフセットの pagination は、結果が最近ページに追加されたり、ページから削除された場合、 user が現在閲覧しているページでレコードを skip したり、重複を表示する場合があります。
ただし、 cursor pagination には以下の制限があります:
simplePaginate
のように、 cursor pagination は次および前の links の表示のみに使用でき、ページ番号付きの links の生成をサポートしていません。- 順序付けは、少なくとも一つの unique column または unique な列の組み合わせに基づいていることが必要です。
null
の values が含まれる列はサポートされていません。 - "order by"句内の Query 式は、エイリアスが付けられ、"select"句に追加されている場合にのみサポートされます。
- パラメータを含む Query 式はサポートされていません。
手動で Paginator を作成する
時々、メモリにすでに持っている array のアイテムを渡して、手動で pagination インスタンスを作成したい場合があります。それは、Illuminate\Pagination\Paginator
、Illuminate\Pagination\LengthAwarePaginator
、または Illuminate\Pagination\CursorPaginator
インスタンスを作成することにより、あなたのニーズに応じて行うことができます。
Paginator
およびCursorPaginator
クラスは、結果セット内のアイテムの総数を知る必要はありません。しかし、そのため、これらのクラスには最後のページのインデックスを取得するメソッドがありません。LengthAwarePaginator
は、Paginator
とほぼ同じ引数を受け入れますが、結果セット内のアイテムの総数を数える必要があります。
つまり、Paginator
は query ビルダーのsimplePaginate
method に対応し、CursorPaginator
はcursorPaginate
method に対応し、LengthAwarePaginator
はpaginate
method に対応します。
WARNING
手動で paginator インスタンスを作成するときは、paginator に渡す結果の array を手動で"スライス"する必要があります。 これがどのように行うかわからない場合は、 array_slice PHP 関数を確認してください。
Pagination URL のカスタマイズ
デフォルトでは、 default によって生成される links は、現在のリクエストの URI と match します。しかし、 paginator の withPath
method は、 paginator が links を生成する際に使用する URI をカスタマイズすることができます。例えば、 paginator に http://example.com/admin/users?page=N
のような links を生成させたい場合、withPath
method に /admin/users
を渡す必要があります。
use App\Models\User;
Route::get('/users', function () {
$users = User::paginate(15);
$users->withPath('/admin/users');
// ...
});
Query String Values の追加
appends
を使用して、ページング links の querystring に 追加できます。例えば、各ページング links に sort=votes
を 追加するには、appends
に次のように呼び出しを行うべきです:
use App\Models\User;
Route::get('/users', function () {
$users = User::paginate(15);
$users->appends(['sort' => 'votes']);
// ...
});
withQueryString
method を使用すると、現在の request の querystring の values をすべてページネーション link に追加することができます:
$users = User::paginate(15)->withQueryString();
Hash フラグメントの追加
paginator によって生成された URL に "hash fragment" を追加する必要がある場合は、fragment
method を使用できます。たとえば、各 pagination リンクの末尾に #users
を追加するには、次のように fragment
method を呼び出す必要があります:
$users = User::paginate(15)->fragment('users');
Displaying Pagination Results
paginate
method を呼び出すと、Illuminate\Pagination\LengthAwarePaginator
のインスタンスが返されます。一方、simplePaginate
method を呼び出すと、Illuminate\Pagination\Paginator
のインスタンスが返されます。そして最後に、cursorPaginate
method を呼び出すと、Illuminate\Pagination\CursorPaginator
のインスタンスが返されます。
これらのオブジェクトは、結果セットを説明するいくつかのメソッドを提供します。これらのヘルパーメソッドに加えて、 paginator のインスタンスはイテレータであり、 array としてループすることができます。したがって、結果を retrieved したら、結果を表示し、ページの links をBladeを用いて render することができます。
<div class="container">
@foreach ($users as $user)
{{ $user->name }}
@endforeach
</div>
{{ $users->links() }}
links
method は、結果セット内の他のページへの links を rendering します。これらの links のそれぞれは、すでに適切な page
query ストリング variables を含んでいます。links
method によって生成された HTML は、Tailwind CSS フレームワーク と互換性があることを覚えておいてください。
Pagination リンクウィンドウの調整
paginator が pagination links を表示するとき、現在のページ番号だけでなく、現在のページの前後 3 ページの links も表示されます。onEachSide
method を使うと、 paginator によって生成された links の中央、スライディングウィンドウの現在のページの両側に、何個の追加の links `を表示するかを制御できます。
{{ $users->onEachSide(5)->links() }}
結果を JSON に変換する
Laravel paginator classes はIlluminate\Contracts\Support\Jsonable
インターフェース契約を実装し、toJson
method を公開しているため、 pagination の結果を JSON に変換するのは非常に簡単です。また、 route や controller action から paginator インスタンスを返すことで、それを JSON に変換することもできます。
use App\Models\User;
Route::get('/users', function () {
return User::paginate();
});
paginator からの JSON array には、total
、current_page
、last_page
などの meta 情報が含まれます。結果レコードは JSON 配列のdata
キーを介して利用できます。以下は、 route から paginator インスタンスを返すことで作成される JSON の例です:
{
"total": 50,
"per_page": 15,
"current_page": 1,
"last_page": 4,
"first_page_url": "http://laravel.app?page=1",
"last_page_url": "http://laravel.app?page=4",
"next_page_url": "http://laravel.app?page=2",
"prev_page_url": null,
"path": "http://laravel.app",
"from": 1,
"to": 15,
"data":[
{
// Record...
},
{
// Record...
}
]
}
Customizing the Pagination View
default では、ページネーションの links を表示するために rendering される views はTailwind CSS フレームワークと互換性があります。しかし、Tailwind を使用していない場合、自由に自分の views を定義してこれらの links を rendering することができます。links
method をページネーターのインスタンスで呼び出す際には、views の名前を method の最初の引数として渡すことができます。
{{ $paginator->links('view.name') }}
<!-- Passing additional data to the view... -->
{{ $paginator->links('view.name', ['foo' => 'bar']) }}
ただし、 pagination views をカスタマイズする最も簡単な方法は、vendor:publish
command を使用してこれらをresources/views/vendor
ディレクトリにエクスポートすることです:
php artisan vendor:publish --tag=laravel-pagination
この command は、アプリケーションの resources/views/vendor/pagination
ディレクトリに views を配置します。このディレクトリ内の tailwind.blade.php
ファイルは、 default pagination view に対応しています。このファイルを編集して pagination HTML を変更することができます。
異なるファイルを default のページネーション view として指定したい場合、App\Providers\AppServiceProvider
の method であるboot
内で、paginator のdefaultView
とdefaultSimpleView
method を呼び出すことができます:
<?php
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Paginator::defaultView('view-name');
Paginator::defaultSimpleView('view-name');
}
}
Bootstrap の使用
Laravel には Bootstrap CSS を使用して構築された pagination views が含まれています。これらの views をデフォルトの Tailwind views の代わりに使用するには、App\Providers\AppServiceProvider
class の boot
method 内で paginator の useBootstrapFour
または useBootstrapFive
method を呼び出すことができます:
use Illuminate\Pagination\Paginator;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Paginator::useBootstrapFive();
Paginator::useBootstrapFour();
}
Paginator / LengthAwarePaginator Instance Methods
各々の paginator インスタンスは、以下のメソッドを通じて追加の pagination 情報を提供します:
Method | Description |
---|---|
$paginator->count() | 現在のページのアイテム数を取得します。 |
$paginator->currentPage() | 現在のページ番号を取得します。 |
$paginator->firstItem() | 結果の最初のアイテムの結果番号を取得します。 |
$paginator->getOptions() | ページネータの option を取得します。 |
$paginator->getUrlRange($start, $end) | pagination の URL の範囲を作成します。 |
$paginator->hasPages() | 複数のページに split するための十分なアイテムがあるかどうかを判断します。 |
$paginator->hasMorePages() | data ストアにさらなるアイテムがあるかどうかを判断します。 |
$paginator->items() | 現在のページの項目を取得します。 |
$paginator->lastItem() | 結果の中で最後のアイテムの結果番号を取得します。 |
$paginator->lastPage() | 最後の利用可能なページのページ番号を取得します。(simplePaginate を使用している場合は利用できません)。 |
$paginator->nextPageUrl() | 次のページの URL を取得します。 |
$paginator->onFirstPage() | paginator が最初のページにあるかどうかを決定します。 |
$paginator->perPage() | ページごとに表示するアイテムの数。 |
$paginator->previousPageUrl() | 前のページの URL を取得します。 |
$paginator->total() | data ストア内のマッチングアイテムの総数を決定します。(simplePaginate を使用している場合は利用できません)。 |
$paginator->url($page) | 指定されたページ番号の URL を取得します。 |
$paginator->getPageName() | ページの保存に使用される query string 変数を取得します。 |
$paginator->setPageName($name) | ページを保存するために使用する query string 変数を設定します。 |
$paginator->through($callback) | 各アイテムをコールバックを使用して Transform します。 |
Cursor Paginator Instance Methods
各々の cursor paginator インスタンスは、以下の方法を通じて追加の pagination 情報を提供します:
Method | Description |
---|---|
$paginator->count() | 現在のページのアイテム数を取得します。 |
$paginator->cursor() | 現在の cursor インスタンスを取得します。 |
$paginator->getOptions() | ページネータの option を取得します。 |
$paginator->hasPages() | 複数のページに split するのに十分なアイテムがあるかどうかを判断します。 |
$paginator->hasMorePages() | data ストアにさらにアイテムがあるかどうかを決定します。 |
$paginator->getCursorName() | cursor を保存するために使用される query string variable を取得します。 |
$paginator->items() | 現在のページのアイテムを取得します。 |
$paginator->nextCursor() | 次のアイテムセットのための cursor インスタンスを取得します。 |
$paginator->nextPageUrl() | 次のページの URL を取得します。 |
$paginator->onFirstPage() | paginator が最初のページにあるかどうかを決定します。 |
$paginator->onLastPage() | paginator が最後のページにあるかどうかを判断します。 |
$paginator->perPage() | ページごとに表示するアイテムの数。 |
$paginator->previousCursor() | 前のアイテムセットの cursor インスタンスを取得します。 |
$paginator->previousPageUrl() | 前のページの URL を取得します。 |
$paginator->setCursorName() | query string variable を設定して、 cursor を保存します。 |
$paginator->url($cursor) | 与えられた cursor インスタンスの URL を取得します。 |