[ZF3] TableGatewayを使った改ページ機能の作り方

zend-dbがバージョン2.9.3になりました。2.9.2まではTableGatewayに自作Featureを設定しても、TableGatewayから独自メソッドは呼び出せなかったのですが、呼び出せる様になりました。これで機能の幅が広がって更に便利になりました。

さて、今回はそんな便利になったTableGatewayを使って改ページ機能の作り方を紹介します。

基本的な改ページ機能

ZendFramework3で改ページ機能をつくるにはzend-paginatorを使用します。zend-paginatorのAdapter\DbTableGatewayを使用してPaginatorを作成します。

use Zend\Paginator\Paginator;
use Zend\Paginator\Adapter\DbTableGateway;
use Zend\Db\TableGateway\TableGateway;

// TableGatewayを作成
$userTable = new TableGateway('users', $adapter);
// Paginater用のアダプター作成
$dbTableGateway = new DbTableGateway($userTable);
// Paginaterを作成
$paginator = new Paginator($dbTableGateway);

上記の例ではusersテーブルの改ページ機能を作成しました。作成した$paginatorをテンプレートファイルに渡し、テンプレートファイル内では下記の様に使います。

<?php if (count($paginator)) : ?>
    <?php foreach ($paginator as $user) : ?>
        <!-- ここに一覧用の記載をします -->
    <?php endforeach ; ?>
<?php endif ; ?>

<?= $this->paginationControl( // ビューヘルパを使用して改ページリンクを表示
    $paginator, // 作成した$paginator
    'Sliding',  // スクロールスタイルを指定
    'application/paginator' // テンプレートファイルを指定
) ?>

改ページリンクを表示する際はビューヘルパを使用しますので、/config/modules.config.phpにZend\Viewを追加しておく必要が有ります。

スクロールスタイルはAll・Elastic・Jumping・Slidingが指定できます。

テンプレートファイルは自作して、好きデザインで作成することが出来ますが、今回こちらのSearch paginationをそのまま使ってみます。

<!--
See http://developer.yahoo.com/ypatterns/pattern.php?pattern=searchpagination
-->

<?php if ($this->pageCount): ?>
<div class="paginationControl">
<!-- Previous page link -->
<?php if (isset($this->previous)): ?>
  <a href="<?= $this->url($this->route, ['page' => $this->previous]); ?>">
    &lt; Previous
  </a> |
<?php else: ?>
  <span class="disabled">&lt; Previous</span> |
<?php endif; ?>

<!-- Numbered page links -->
<?php foreach ($this->pagesInRange as $page): ?>
  <?php if ($page != $this->current): ?>
    <a href="<?= $this->url($this->route, ['page' => $page]); ?>">
        <?= $page; ?>
    </a> |
  <?php else: ?>
    <?= $page; ?> |
  <?php endif; ?>
<?php endforeach; ?>

<!-- Next page link -->
<?php if (isset($this->next)): ?>
  <a href="<?= $this->url($this->route, ['page' => $this->next]); ?>">
    Next &gt;
  </a>
<?php else: ?>
  <span class="disabled">Next &gt;</span>
<?php endif; ?>
</div>
<?php endif; ?>

引用元: zend-paginator Usage

以上で下記の様に改ページリンクが表示されます。

改ページリンクのURLにページ番号を挿入

しかし、このままだと各改ページのリンクURLにページ番号が挿入されておらず、ページ移動が出来ないと思います。

各改ページリンクのURLにページ番号を挿入するには、ルータの設定を行う必要が有ります。下記の例の様にpageのパラメーターを記載したルータの設定を追加します。

return [
    'routes' => [
        'paginator' => [
            'type' => 'segment',
            'options' => [
                'route' => '/list/[page/:page]',
                'defaults' => [
                    'page' => 1,
                ],
            ],
        ],
    ],
];

引用元: zend-paginator Usage

これで各改ページのURLにページ番号が付与されます。ページ番号をPaginatorに設定するにはsetCurrentPageNumberメソッドを使用します。

下記はコントローラでページ番号を取得してPaginatorに設定する例です。

use Zend\Paginator\Paginator;

$paginator = new Paginator($dbTableGateway);
$paginator->setCurrentPageNumber($this->params('page'));

ルーターの設定を行わなくても、GETパラメータにページ番号を指定するという方法もあります。

GETパラメーターでページ番号を指定するには、テンプレートファイルの$this->url()の第三引数で指定します。

<a href="<?= $this->url($this->route, [], ['query' => ['page' => $page]]); ?>">
    <?= $page; ?>
</a>

コントローラー内では下記の様にしてページ番号を取得します。

use Zend\Paginator\Paginator;

$query = $this->params()->fromQuery();
$paginator = new Paginator($dbTableGateway);
$paginator->setCurrentPageNumber($query['page']);

検索条件をGETパラメーターで指定している場合は、検索条件を上書きしないような工夫が必要です。

1ページあたりの表示件数を設定

zend-paginatorのデフォルトの1ページ辺りの表示件数は10件ですが、変更したい場合はsetItemCountPerPageで変更できます。

use Zend\Paginator\Paginator;

$paginator = new Paginator($dbTableGateway);
$paginator->setItemCountPerPage('50'); // 1ページ当たり50件に設定

改ページリンクの表示件数を設定

改ページリンクの表示件数を設定するにはsetPageRangeメソッドを使用します。

use Zend\Paginator\Paginator;

$paginator = new Paginator($dbTableGateway);
$paginator->setPageRange('5'); // 改ページリンクの表示件数を5件に設定

この様に表示されます。

検索条件を指定

改ページ機能で検索条件を指定するには、DbTableGatewayの第二引数にWhereオブジェクト・クロージャ・文字列・配列の何れかを渡します。

例えばdeleted_atがnullのレコードのみを取得する場合は、下記の様にします。

use Zend\Paginator\Adapter\DbTableGateway;
use Zend\Db\TableGateway\TableGateway;

$userTable = new TableGateway('users', $adapter);

// Whereオブジェクトで指定
$select = $userTable->getSql()->select();
$select->where->isNull('deleted_at');
$dbTableGateway = new DbTableGateway($userTable, $select->where);
use Zend\Paginator\Adapter\DbTableGateway;
use Zend\Db\TableGateway\TableGateway;

$userTable = new TableGateway('users', $adapter);

// クロージャで指定
$tableGateway = new DbTableGateway($userTable, function ($where) {
    $where->isNull('deleted_at');
});
use Zend\Paginator\Adapter\DbTableGateway;
use Zend\Db\TableGateway\TableGateway;

$userTable = new TableGateway('users', $adapter);

// 文字列で指定
$tableGateway = new DbTableGateway($userTable, 'deleted_at IS NULL');
use Zend\Paginator\Adapter\DbTableGateway;
use Zend\Db\TableGateway\TableGateway;

$userTable = new TableGateway('users', $adapter);

// 配列で指定
$tableGateway = new DbTableGateway($userTable, ['deleted_at' => null]);

全件カウント取得処理を変更する

zend-paginatorを使用すると、全件数をカウントするSQL、1ページあたりのリストを取得するSQLの2つのSQLが自動で作成され実行されます。

-- 全件数をカウントするSQL
SELECT COUNT(1) AS `C` FROM (SELECT `users`.* FROM `users` WHERE `deleted_at` IS NULL) AS `original_select`;

-- 1ページあたりのリストを取得するSQL
SELECT `users`.* FROM `users` WHERE `deleted_at` IS NULL LIMIT 10 OFFSET 0;

自動で作成される全件数をカウントするSQLを使用せずに、独自でカウント処理を実装する場合は、PaginatorのアダプターにDbTableGatewayではなくDbSelectを使用することで対応可能です。

以下の例はcountsテーブルのuser_countフィールドより全件数カウントを取得する例です。

use Zend\Paginator\Paginator;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Db\Sql\Select;
use Zend\Db\TableGateway\TableGateway;

// TableGatewayを作成
$userTable = new TableGateway('users', $adapter);

// リスト取得用select作成
$sql = $this->userTable->getSql();
$select = $sql->select();
$resultSetPrototype = $this->userTable->getResultSetPrototype();

// 総件数カウント用select作成
$countSelect = new Select();
$countSelect->from('counts')->columns([DbSelect::ROW_COUNT_COLUMN_NAME => 'user_count']);

// DbSelectでアダプター作成
$dbSelect = new DbSelect($select, $sql, $resultSetPrototype, $countSelect);

// Paginaterを作成
$paginator = new Paginator($dbSelect);

テンプレートファイルをカスタマイズ

テンプレートファイルではこちらのプロパティを使用することができます。

Bootstrap3を使ったテンプレートファイルを自作してみました。Gistで公開しています。

こんな感じで使用します。

<?= $this->paginationControl($paginator, 'Sliding', 'application/bootstrap.phtml', ['query' => $query]) ?>

ビューヘルパのpaginationControlの第四引数に’query’を指定してGETパラメーターを引き継げる様にしています。

以下の様に表示されます。

この様にテンプレートファイルを使って好きなデザインに改ページリンクをカスタマイズすることができます。

コメントを残す