Zend_Paginatorを使ってみた

使用バージョン:Ver1.7.6

比較的最近加わったライブラリであるZend_Paginatorを使用してみた。
http://framework.zend.com/manual/ja/zend.paginator.html 公式マニュアル

フレームワーク側の準備をする

まずはインスタンス作成。他ライブラリと同様、直接インスタンス生成する方法と、Factoryパターンを利用する静的メソッドが用意されている。
引数に渡すのは、ページネーションを行う元ネタの取得方法。
これをデータソースアダプタと言う。種類は以下。

アダプタ 説明
Array PHPの配列を使用します。
DbSelect Zend_Db_Select のインスタンスを使用し、配列を返します。
DbTableSelect Zend_Db_Table_Select のインスタンスを使用し、 Zend_Db_Table_Rowset_Abstract のインスタンスを返します。 これは、結果セットについての追加情報 (カラム名など) を提供します。
Iterator Iteratorインスタンスを使用します。
Null データのページ処理を管理する際に Zend_Paginator を使用しません。その場合でもページ処理コントロールの機能を使うことはできます。

とりあえず今回は配列を渡す事にした。
配列の中身は以下とする。

<?php

$array = (
           [0] => array(
                         ['title'] => 'hoge'
                         ['body']  => 'ほげほげほげ'
                  )
           [1] => array(
                         ['title'] => 'piyo'
                         ['body']  => 'ぴよぴよぴよ'
                  )
           [2] => array(
                         ['title'] => 'fuga'
                         ['body']  => 'ふがふがふが'
                  )
〜〜〜〜20ほど続く…
        );
直接アダプターにデータソースを渡してインスタンス生成する
<?php

$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Array($array));
FactoryMethodパターンで生成する
<?php

$paginator = Zend_Paginator::factory($array);

お好きな方で。


次に必要であればオプションの設定を行う。

メソッド 説明
setCurrentPageNumber 現在のページ番号を設定します (デフォルトは 1)。
setItemCountPerPage 1 ページに表示する項目の最大数を設定します (デフォルトは 10)。
setPageRange ページ処理コントロールに表示する項目の数を設定します (デフォルトは 10)。 注意: ほとんどの場合はこの値が正確に守られますが、 スクロール形式の場合はこの値を単なる指針あるいは開始値 (例: Elastic) としてしか使わないこともあります。
setView レンダリングを支援するために、ビューのインスタンスを設定します。

とりあえず、「ユーザが要求したページ番号をコントローラのアクション内で教えてやる必要がある」ので、setCurrentPageNumberメソッドを使用して設定する。

例えば、

http://exsample.com/info/drink/

といったURLにアクセスして、そこのページに用意されている検索フォームから検索した結果でページングを始めると仮定する。
イメージ的には、

http://exsample.com/info/drink/page/1
http://exsample.com/info/drink/page/2
…

といった具合に進んでくれるようにしてみる。

この場合、Zend_Controller_Router_Interfaceを使ってルーティングの設定を行う必要がある。
ルーターのセッティングはiniファイルから行ってみる。

router.ini

routes.info.type                     = "Zend_Controller_Router_Route"
routes.info.route                    = "info/drink/:articleName/:page"
routes.info.defaults.module          = "default"
routes.info.defaults.controller      = "info"
routes.info.defaults.action          = "drink"
routes.info.reqs.articleName         = "page"
routes.info.reqs.page                = \d+

iniファイル設定したら、index.phpで以下のような感じでルーターの設定を行う。

<?php

$router = $front->getRouter();
$router->addConfig(new Zend_Config_Ini('../application/config/router.ini', 'routes');

パスは適宜変更。


先ほどのpaginatorのインスタンスを作成した箇所に戻って、ユーザーが要求したページ番号をpaginatorに設定するオプションを記述する。

<?php

$paginator->setCurrentPageNumber($this->_getParam('page'));

これで、URLでいうと、

/page/1

の部分のページ数パラメータを取得して、paginatorに与える事ができる。


続けてオプションの設定を行う。

<?php

Zend_Paginator::setDefaultScrollingStyle('Sliding');
Zend_View_Helper_PaginationControl::setDefaultViewPartial('my_pagination_control.phtml');
$paginator->setView($this->view);

一行目で、ページネーターが表示する「現在位置」の表示方法を設定している。以下設定できる項目。

スクロール形式 説明
All すべてのページを返します。 総ページ数が比較的少なめのときなど、 ドロップダウンメニュー形式でページ選択をさせる際に便利です。 そのような場合は、利用できるすべてのページを 一度にユーザに見せることになるでしょう。
Elastic Google 風のスクロール形式で、 ユーザがページを移動するのにあわせて拡大・縮小します。
Jumping ユーザがページを進めるにつれて、 ページ番号が表示範囲の最後に向けて進んでいきます。 表示範囲を超えると、新しい範囲の最初の位置に移動します。
Sliding Yahoo! 風のスクロール形式で、 現在表示されているページが常にページ範囲の中央 (あるいは可能な限りそれに近い場所) にあるようにします。これがデフォルトの形式です。

一通り見てみたけど、とりあえずデフォルトのSlidingが感覚的に合ったのでそのまま使用。
二行目で設定しているのが、ページネーターのコントロール部分(prev 1 2 3 … next)のテンプレート。
とりあえず適当な名前で設定しておく。後でファイル作る。
三行目でViewオブジェクトへ表示する内容をまとめてセットしてるようである。
(※これでビューオブジェクトの設定はいらないのかと思ったら、下のように別で設定しないと動かなかった。)

<?php

$this->view->paginator = $paginator;

さらに、この状態で3行目の $paginator->setView($this->view); をコメントアウトしてみても別に問題無く動いた。
ソース追ってみないとよく分からんところなので、とりあえずどちらも記述しておく。

ビュー側の準備をする

次に、ページネーターのコントロール部分のテンプレートを作る。

<?php if ($this->pageCount): ?>
<div class="paginationControl">
<!-- 前のページへのリンク -->
<?php if (isset($this->previous)): ?>
  <a href="<?php echo $this->url(array('page' => $this->previous)); ?>">
    &lt; Previous
  </a> |
<?php else: ?>
  <span class="disabled">&lt; Previous</span> |
<?php endif; ?>

<!-- ページ番号へのリンク -->
<?php foreach ($this->pagesInRange as $page): ?>
  <?php if ($page != $this->current): ?>
    <a href="<?php echo $this->url(array('page' => $page)); ?>">
        <?= $page; ?>
    </a> |
  <?php else: ?>
    <?php echo $page; ?> |
  <?php endif; ?>
<?php endforeach; ?>

<!-- 次のページへのリンク -->
<?php if (isset($this->next)): ?>
  <a href="<?php echo $this->url(array('page' => $this->next)); ?>">
    Next &gt;
  </a>
<?php else: ?>
  <span class="disabled">Next &gt;</span>
<?php endif; ?>
</div>
<?php endif; ?>

以上、ドキュメントより丸パクリ。

これを、

views/scripts/my_pagination_control.phtml

として、scriptsディレクトリ直下に保存する。デフォルトではこの階層に探しにいくみたい。他にディレクトリ切って入れときたい場合は適宜 setDefaultViewPartial の設定パスを書き変えてあげれば良い。

次に、本体となるテンプレートに、表示内容の設定を行う。

<?php if (count($this->paginator)): ?>
    <ul>
    <?php foreach ($this->paginator as $key => $item): ?>

        <li><?php echo $item['title']; ?></li>
        <li><?php echo $item['body']; ?></li>

    <?php endforeach; ?>
    </ul>
<?php endif; ?>

<?php echo $this->paginator ?>

内容は書いてある通りで、配列を回して中身表示。
最後の一行の echo $this->paginator で、ページネーターコントロール部分を表示している。

後は、検索formタグのactionに、

<form action="/info/drink/page/1">

みたいに設定しておけばOK。

表示!

hoge
ほげほげほげ
piyo
ぴよぴよぴよ
fuga
ふがふがふが
< Previous | 1 | 2 | 3 | 4 | 5 | Next > 

みたいに表示されたらOK。後はページ遷移してきちんとURLと表示内容が整合性取れてるか確認!

他のデータソースアダプタに関してはまた次の機会に。