CakePHP4で一覧ページのページネーションを実装する

CakePHP4で一覧ページ(ビュー)のページネーションを実装してみました。

CakePHP4のページネーションについては以下公式ページをご覧ください。
https://book.cakephp.org/4/ja/controllers/components/pagination.html

ビューのページネーションについては、上記ページの最下部に以下の記述があります。

ページネーションナビゲーションのリンクの作り方は、 View\HelperPaginatorHelper のドキュメントを確認してください。

しかし、「View\HelperPaginatorHelper」のドキュメントへのリンクが張ってなく、ドキュメントを検索してみると、以下のようにバージョン2.xしか見つかりませんでした。
https://book.cakephp.org/2/ja/core-libraries/helpers/paginator.html

CakePHP4ではバージョン2時点からは、かなり変わっていて、上記ドキュメントが役に立たなかったので、直接ソースを見て実装しました。

ページネーションの表示

以下のようなページネーションを実装します。
デザインはAdminLTEに合わせています。

ページネーション

ビューのコード

ビューは以下のように実装します。

<ul class="pagination">
<?= $this->Paginator->prev('< ' . __('Previous'), [
    'templates' => [
        'prevActive' => '<li class="paginate_button page-item previous"><a class="page-link" href="{{url}}">{{text}}</a></li>',
        'prevDisabled' => '<li class="paginate_button page-item previous disabled"><a class="page-link" href="" onclick="return false;">{{text}}</a></li>'
]]) ?>
<?= $this->Paginator->numbers([
    'templates' => [
        'number' => '<li class="paginate_button page-item"><a class="page-link" href="{{url}}">{{text}}</a></li>',
        'current' => '<li class="paginate_button page-item active"><a class="page-link" href="{{url}}">{{text}}</a></li>'
]]) ?>
<?= $this->Paginator->next(__('Next') . ' >', [
    'templates' => [
        'nextActive' => '<li class="paginate_button page-item next"><a class="page-link" href="{{url}}">{{text}}</a></li>',
        'nextDisabled' => '<li class="paginate_button page-item next disabled"><a class="page-link" href="" onclick="return false;">{{text}}</a></li>'
]]) ?>
</ul>

前ページへのリンク

前ページへのリンクを作成するには、ヘルパーのprevメソッドを使用します。
prevメソッドを使用すると、liタグが生成されます。

<?= $this->Paginator->prev('< ' . __('Previous'), [
    'templates' => [
        'prevActive' => '<li class="paginate_button page-item previous"><a class="page-link" href="{{url}}">{{text}}</a></li>',
        'prevDisabled' => '<li class="paginate_button page-item previous disabled"><a class="page-link" href="" onclick="return false;">{{text}}</a></li>'
]]) ?>

第2引数でオプションを指定できます。
本記事ではテンプレートを指定して、liタグの内容を変更する形で記載しています。

PaginatorHelperクラスのソースを見てみると、テンプレートのデフォルトは以下のようになっていました。

protected $_defaultConfig = [
    'options' => [],
    'templates' => [
        'nextActive' => '<li class="next"><a rel="next" href="{{url}}">{{text}}</a></li>',
        'nextDisabled' => '<li class="next disabled"><a href="" onclick="return false;">{{text}}</a></li>',
        'prevActive' => '<li class="prev"><a rel="prev" href="{{url}}">{{text}}</a></li>',
        'prevDisabled' => '<li class="prev disabled"><a href="" onclick="return false;">{{text}}</a></li>',
        'counterRange' => '{{start}} - {{end}} of {{count}}',
        'counterPages' => '{{page}} of {{pages}}',
        'first' => '<li class="first"><a href="{{url}}">{{text}}</a></li>',
        'last' => '<li class="last"><a href="{{url}}">{{text}}</a></li>',
        'number' => '<li><a href="{{url}}">{{text}}</a></li>',
        'current' => '<li class="active"><a href="">{{text}}</a></li>',
        'ellipsis' => '<li class="ellipsis">…</li>',
        'sort' => '<a href="{{url}}">{{text}}</a>',
        'sortAsc' => '<a class="asc" href="{{url}}">{{text}}</a>',
        'sortDesc' => '<a class="desc" href="{{url}}">{{text}}</a>',
        'sortAscLocked' => '<a class="asc locked" href="{{url}}">{{text}}</a>',
        'sortDescLocked' => '<a class="desc locked" href="{{url}}">{{text}}</a>',
    ],
];

prevメソッドでは
「prevActive」を指定することで、前ページへのリンクが有効な場合(2ページ目以降を表示している場合)のテンプレート
「prevDisabled」を指定することで、前ページへのリンクが無効な場合(1ページ目を表示している場合)のテンプレート
を、それぞれ指定できます。

次ページへのリンク

次ページへのリンクを作成するには、ヘルパーのnextメソッドを使用します。
nextメソッドを使用すると、前ページの時と同様にliタグが生成されます。

<?= $this->Paginator->next(__('Next') . ' >', [
    'templates' => [
        'nextActive' => '<li class="paginate_button page-item next"><a class="page-link" href="{{url}}">{{text}}</a></li>',
        'nextDisabled' => '<li class="paginate_button page-item next disabled"><a class="page-link" href="" onclick="return false;">{{text}}</a></li>'
]]) ?>

nextメソッドでは
「nextActive」を指定することで、次ページへのリンクが有効な場合(最終ページ以前を表示している場合)のテンプレート
「nextDisabled」を指定することで、次ページへのリンクが無効な場合(最終ページを表示している場合)のテンプレート
を、それぞれ指定できます。

各ページへのリンク

次ページへのリンクを作成するには、ヘルパーのnumbersメソッドを使用します。
numbersメソッドを使用すると、前ページ、次ページの時と同様にliタグが生成されます。

<?= $this->Paginator->numbers([
    'templates' => [
        'number' => '<li class="paginate_button page-item"><a class="page-link" href="{{url}}">{{text}}</a></li>',
        'current' => '<li class="paginate_button page-item active"><a class="page-link" href="{{url}}">{{text}}</a></li>'
]]) ?>

nextメソッドでは
「number」を指定することで、現在表示中以外のページのリンクのテンプレート
「current」を指定することで、現在表示中のページのリンクのテンプレート
を、それぞれ指定できます。

まとめ

CakePHPだとドキュメントが実装に追いついていないケースというのが結構ありますね。
CakePHPに限らず、ライブラリやフレームワークなどは、こういったケースが多いのかもしれません。

フレームワークのソースが読める人は良いと思いますが、全ての開発者がそうではないので、やはり公開しているライブラリやフレームワークはドキュメントが大事だと感じました。

フレームワークとかに限らず、開発には何らかのドキュメントが大事だとは思いますが、こういったことを自分が体験すると、ちゃんと他の人にも分かるように作らないといけないな、と感じるきっかけになりました。