Laravel 8.x Database:ペジネーション

イントロダクション

他のフレームワークでは、ペジネーション(ページ付け)は非常に苦労することがあります。Laravelのペジネーションへのアプローチが簡単であると思っていただけるよう願っています。LaravelのペジネーションはクエリビルダおよびEloquent ORMと統合されており、設定をしなくても便利で使いやすいペジネーションを提供します。

デフォルトでは、ペジネータによって生成されたHTMLはTailwind CSSフレームワークと互換性があります。ただし、Bootstrapペジネーションのサポートも利用できます。

Tailwind JIT

LaravelのデフォルトのTailwind pagination viewとTailwind JITエンジンを使用している場合、アプリケーションのtailwind.config.jsファイルのcontentキーで、Laravelのペジネーションビューを参照し、そのTailwindクラスがパージされないようにする必要があります。

content: [
    './resources/**/*.blade.php',
    './resources/**/*.js',
    './resources/**/*.vue',
    './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
],

基本的な使い方

ペジネーションクエリビルダ結果

アイテムをペジネーションする方法はいくつかあります。最も簡単な方法は、クエリビルダまたはEloquentクエリpaginateメソッドを使用することです。paginateメソッドは、ユーザーが表示している現在のページに基づいて、クエリの"limit"と"offset"の設定を自動的に処理します。デフォルトでは、現在のページはHTTPリクエストのpageクエリ文字列引数の値から検出されます。この値はLaravelによって自動的に検出され、ペジネータが生成するリンクにも自動的に挿入されます。

この例では、paginateメソッドへ渡す引数は、唯一「ページごと」に表示するアイテムの数です。例として、ページごとに「15」個のアイテムを表示するように指定してみましょう。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;

class UserController extends Controller
{
    /**
     * アプリケーションのすべてのユーザーを表示
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('user.index', [
            'users' => DB::table('users')->paginate(15)
        ]);
    }
}

シンプルなペジネーション

paginateメソッドは、データベースからレコードを取得する前に、クエリで一致するレコードの総数をカウントします。これは、ペジネータが合計で何ページ分のレコードがあるかを知るために行います。ただし、アプリケーションのUIに合計ページ数を表示する予定がない場合は、レコード数のクエリは不要です。

したがって、アプリケーションのUIに単純な「次へ」リンクと「前へ」リンクのみを表示する必要がある場合は、simplePaginateメソッドを使用して、単一で効率的なクエリが実行できます。

$users = DB::table('users')->simplePaginate(15);

Eloquent結果のペジネーション

Eloquentクエリをページ分割することもできます。この例では、App\Models\Userモデルをページ分割し、ページごとに15レコードを表示するプランであることを示します。ご覧のとおり、構文はクエリビルダの結果のペジネーションとほぼ同じです。

use App\Models\User;

$users = User::paginate(15);

もちろん、where句など、クエリに他の制約を設定した後、paginateメソッドを呼び出すこともできます。

$users = User::where('votes', '>', 100)->paginate(15);

EloquentモデルをペジネーションするときにsimplePaginateメソッドを使用することもできます。

$users = User::where('votes', '>', 100)->simplePaginate(15);

同様に、cursorPaginateメソッドをEloquentモデルのカーソルページングに使用できます。

$users = User::where('votes', '>', 100)->cursorPaginate(15);

1ページ上のマルチペジネータインスタンス

アプリケーションがレンダーするひとつの画面上で、 2つの別々のぺジネータをレンダーする必要がある場合があります。しかし、両方のペジネータのインスタンスが現在のページを格納するのにpageというクエリ文字列パラメータを使っていると、2つのペジネータが衝突してしまいます。この衝突を解決するにはpaginatesimplePaginatecursorPaginateの各メソッドの第3引数に、ペジネータの現在のページを格納するために使いたいクエリストリングパラメータの名前を渡してください。

use App\Models\User;

$users = User::where('votes', '>', 100)->paginate(
    $perPage = 15, $columns = ['*'], $pageName = 'users'
);

カーソルページング

paginatesimplePaginateがSQLの"offset"句を使用してクエリを作成するのに対し、カーソルペジネーションは "where"句を使い制約し、効率的なデータベースパフォーマンスを実現します。このペジネーションの方法は、特に大規模なデータセットや、「無限」にスクロールするユーザーインターフェイスに適しています。

ペジネイタが生成するURLのクエリ文字列にページ番号を含めるオフセットベースのペジネーションとは異なり、カーソルベースのペジネーションでは、クエリ文字列に「カーソル」文字列を配置します。カーソルは、ページ処理した次のクエリがページ処理を開始すべき場所と、ページ処理すべき方向を示すエンコードした文字列です。

http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0

カーソルベースのペジネータインスタンスを作成するには,クエリビルダが提供するcursorPaginateメソッドを使用します。このメソッドは,Illuminate\Pagination\CursorPaginatorインスタンスを返します。

$users = DB::table('users')->orderBy('id')->cursorPaginate(15);

カーソルページネータインスタンスを取得したら、paginatesimplePaginateメソッドを使うときと同様に、ペジネーションの結果を表示します。カーソルペジネータが提供するインスタンスメソッドの詳細は、カーソルペジネータインスタンスのドキュメントを参照してください。

Note: カーソルのペジネーションを利用するには、クエリに "order by"句を含める必要があります。

カーソル vs. オフセットペジネーション

オフセットページングとカーソルページングの違いを説明するために、いくつかのSQLクエリの例を見てみましょう。以下のクエリはどちらも、usersテーブルの結果をidで並べた「2ページ目」を表示します。

# オフセットページング
select * from users order by id asc limit 15 offset 15;

# カーソルページング
select * from users where id > 15 order by id asc limit 15;

カーソルページングクエリは、オフセットページングに比べて以下の利点があります。

ただし、カーソルペジネーションには以下の制限があります。

ペジネータの手動生成

場合によっては、ペジネーションインスタンスを手動で作成し、メモリ内にすでにあるアイテムの配列を渡すことができます。必要に応じて、Illuminate\Pagination\PaginatorIlluminate\Pagination\LengthAwarePaginatorIlluminate\Pagination\CursorPaginatorインスタンスを生成することでこれが行えます。

PaginatorCursorPaginatorクラスは結果セットのアイテムの総数を知る必要はありません。しかしこのため、これらのクラスには最後のページのインデックスを取得するメソッドがありません。LengthAwarePaginatorPaginatorとほぼ同じ引数を取りますが、結果セットのアイテムの総数をカウントする必要があります.

つまり,PaginatorはクエリビルダのsimplePaginateメソッドに、CursorPaginatorcursorPaginateメソッドに,LengthAwarePaginatorpaginateメソッドに、それぞれ対応しています。

Note: ペジネーションインスタンスを手動で作成する場合は、ペジネーションに渡す結果の配列を手動で「スライス」する必要があります。これを行う方法がわからない場合は、array_slicePHP関数を確認してください。

ペジネーションURLのカスタマイズ

デフォルトでは、ペジネータにが生成するリンクは、現在のリクエストのURIと一致します。ただし、ペジネータのwithPathメソッドを使用すると、リンクを生成するときにペジネータが使用するURIをカスタマイズできます。たとえば、ペジネータでhttp://example.com/admin/users?page=Nのようなリンクを生成したい場合は、/admin/userswithPathメソッドに渡します。

use App\Models\User;

Route::get('/users', function () {
    $users = User::paginate(15);

    $users->withPath('/admin/users');

    //
});

クエリ文字列の追加

appendsメソッドを使用して、ペジネーションリンクのクエリ文字列へ追加できます。たとえば、各ペジネーションリンクにsort=votesを追加するには、appendsを以下のように呼び出します。

use App\Models\User;

Route::get('/users', function () {
    $users = User::paginate(15);

    $users->appends(['sort' => 'votes']);

    //
});

現在のリクエストのすべてのクエリ文字列値をペジネーションリンクに追加する場合は、withQueryStringメソッドを使用できます。

$users = User::paginate(15)->withQueryString();

ハッシュフラグメントの追加

paginatorによって生成されたURLに「ハッシュフラグメント」を追加する必要がある場合は、fragmentメソッドを使用できます。たとえば、各ペジネーションリンクの最後に#usersを追加するには、次のようにfragmentメソッドを呼び出します。

$users = User::paginate(15)->fragment('users');

ペジネーション結果の表示

paginateメソッドを呼ぶと、Illuminate\Pagination\LengthAwarePaginatorインスタンスが返され,simplePaginateメソッドを呼ぶと、Illuminate\Pagination\Paginatorインスタンスが返されます。そして、cursorPaginateメソッドを呼び出すと、Illuminate\CursorPaginatorインスタンスが返されます。

これらのオブジェクトは、結果セットを表示するメソッドをいくつか提供しています。これらヘルパメソッドに加え、ペジネータインスタンスはイテレータであり、配列としてループ処理も可能です。つまり、結果を取得したら、Blade を使って結果を表示したり、ページリンクをレンダーしたりできるのです。

<div class="container">
    @foreach ($users as $user)
        {{ $user->name }}
    @endforeach
</div>

{{ $users->links() }}

linksメソッドは、結果セットの残りのページへのリンクをレンダーします。これらの各リンクには、適切なpageクエリ文字列変数がすでに含まれています。linksメソッドが生成するHTMLは、Tailwind CSSフレームワークと互換性があることを忘れないでください。

ペジネーションリンクウィンドウの調整

ページネータがページ処理用のリンクを表示する際には、現在のページ番号に加え、現在のページの前後3ページ分のリンクが表示されます。onEachSideメソッドを使用して、ページネータが生成するリンクの中央のスライディングウィンドウ内の現在のページの両側に表示する追加のリンク数を制御できます。

{{ $users->onEachSide(5)->links() }}

結果のJSONへの変換

LaravelペジネータクラスはIlluminate\Contracts\Support\Jsonableインターフェイスコントラクトを実装し、toJsonメソッドを提供しているため、ペジネーションの結果をJSONに変換するのは非常に簡単です。ルートまたはコントローラアクションから返すことで、ペジネーションインスタンスをJSONに変換することもできます。

use App\Models\User;

Route::get('/users', function () {
    return User::paginate();
});

ペジネーターからのJSONは、totalcurrent_pagelast_pageなどのメタ情報を持っています。結果レコードは、JSON配列のdataキーを介して利用できます。ルートからペジネーションインスタンスを返すことによって作成された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":[
        {
            // レコード…
        },
        {
            // レコード…
        }
   ]
}

ペジネーションビューのカスタマイズ

デフォルトでは、ペジネーションリンクを表示するためにレンダリングされたビューは、Tailwind CSSフレームワークと互換性があります。ただし、Tailwindを使用しない場合は、これらのリンクをレンダーするために独自のビューを自由に定義できます。paginatorインスタンスでlinksメソッドを呼び出すとき、メソッドの最初の引数としてビュー名を渡すことができます。

{{ $paginator->links('view.name') }}

// ビューに追加データを渡す
{{ $paginator->links('view.name', ['foo' => 'bar']) }}

ただし、ペジネーションビューをカスタマイズする最も簡単な方法は、vendor:publishコマンドを使用してresources/views/vendorディレクトリにエクスポートすることです。

php artisan vendor:publish --tag=laravel-pagination

このコマンドは、ビューをアプリケーションのresources/views/vendor/paginationディレクトリに配置します。このディレクトリ内のtailwind.blade.phpファイルが、デフォルトのペジネーションビューに対応しています。このファイルを編集して、ペジネーションHTMLを変更できます。

別のファイルをデフォルトのペジネーションビューとして指定する場合は、App\Providers\AppServiceProviderクラスのbootメソッド内でペジネーションのdefaultViewメソッドとdefaultSimpleViewメソッドを呼び出すことができます。

<?php

namespace App\Providers;

use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * 全アプリケーションサービスの初期起動処理
     *
     * @return void
     */
    public function boot()
    {
        Paginator::defaultView('view-name');

        Paginator::defaultSimpleView('view-name');
    }
}

Bootstrapの使用

Laravelは、Bootstrap CSSを使用して構築したペジネーションビューも用意しています。デフォルトのTailwindビューの代わりにこれらのビューを使用するには、App\Providers\AppServiceProviderクラスのbootメソッド内でペジネータのuseBootstrapメソッドを呼び出してください。

use Illuminate\Pagination\Paginator;

/**
 * 全アプリケーションサービスの初期起動処理
 *
 * @return void
 */
public function boot()
{
    Paginator::useBootstrap();
}

Paginator/LengthAwarePaginatorインスタンスのメソッド

各ペジネーションインスタンスは、以下のメソッドで追加のペジネーション情報を提供します。

メソッド 説明
$paginator->count() 現在のページのアイテム数を取得
$paginator->currentPage() 現在のページ番号を取得
$paginator->firstItem() 結果の最初の項目の結果番号を取得
$paginator->getOptions() ペジネータオプションを取得
$paginator->getUrlRange($start, $end) ペジネーションURLを範囲内で生成
$paginator->hasPages() 複数のページに分割するのに十分なアイテムがあるかどうかを判定
$paginator->hasMorePages() データストアにさらにアイテムがあるかどうかを判定
$paginator->items() 現在のページのアイテムを取得
$paginator->lastItem() 結果の最後のアイテムの結果番号を取得
$paginator->lastPage() 最後に利用可能なページのページ番号を取得(simplePaginate使用時は使用不可能)
$paginator->nextPageUrl() 次のページのURLを取得
$paginator->onFirstPage() ペジネータが最初のページにあるかを判定
$paginator->perPage() 1ページ中に表示するアイテムの数
$paginator->previousPageUrl() 前のページのURLを取得
$paginator->total() データストア内の一致するアイテムの総数を判定(simplePaginate使用時は使用不可能)
$paginator->url($page) 指定するページ番号のURLを取得
$paginator->getPageName() ページの保存に使用するクエリ文字列変数を取得
$paginator->setPageName($name) ページの保存に使用するクエリ文字列変数を設定

カーソルPaginatorインスタンスのメソッド

各カーソルペジネータインスタンスは、以降のメソッドで追加のペジネーション情報を提供します。

Method Description
$paginator->count() 現在のページのアイテム数を取得
$paginator->cursor() 現在のカーソルインスタンスを取得
$paginator->getOptions() ペジネータオプションを取得
$paginator->hasPages() 複数のページに分割するのに十分なアイテムがあるかどうかを判定
$paginator->hasMorePages() データストアにさらにアイテムがあるかどうかを判定
$paginator->getCursorName() カーソルの保存で使用するクエリ文字列変数を取得
$paginator->items() 現在のページのアイテムを取得
$paginator->nextCursor() 次のアイテムセットのカーソルインスタンスを取得
$paginator->nextPageUrl() 次のページのURLを取得
$paginator->onFirstPage() ペジネータが最初のページにあるかを判定
$paginator->perPage() 1ページ中に表示するアイテムの数
$paginator->previousCursor() 前のアイテムセットのカーソルインスタンスを取得
$paginator->previousPageUrl() 前のページのURLを取得
$paginator->setCursorName() カーソルの保存に使用するクエリ文字列変数を設定
$paginator->url($cursor) 指定するカーソルインスタンスのURLを取得

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる