アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

Piece_Unity_Component_Paginationを使ってみた

こんにちは。最近新型iPod nano(16GB)を購入した小川です。薄くて大画面で容量が多くてかっこいいなんて素晴らしいですよね。

さて、本日はPiece Frameworkの話題です。9月に入ってからPiece_Unityを筆頭に様々なコンポーネントなどがリリースされているのですが、今回はその中で気になった「Piece_Unity_Component_Pagination」を試してみたいと思います。

ページネーションをするにあたって、公式のサンプルであるPiece_Examples_CRUDアプリケーションをベースにしました。

途中、インストールしていたMDB2がなぜかベータ版で過去のバグが残っておりハマったりしましたが、それ以外は特に問題なく配置できました。
(参考までに: Bug #8124 Datatype mapNativeDatatype reports TEXT as BLOB

それではいよいよPiece_Unity_Component_Paginationを試していきたいと思います。
Piece_Unity_Component_Paginationは

□Piece/Unity/Plugin/HTMLComponent/Pagination.php
 ... PaginationオブジェクトをViewへ渡す
□Piece/Unity/Service/Pagination.php
 ... Paginatorオブジェクトを用いてページャーレンダリング
□Piece/Unity/Service/Paginator.php
 ... ページネーションに必要なデータをまとめたオブジェクト

の3ファイルの実装となっています。

まずはHTMLComponent_Paginationプラグインをロードします。piece-unity-config.yamlで定義する方法がよくわからなかったので、コントローラー内でロードするようにしました。(設定方法についての追記しました)
なので今回実際に変更するファイルは
・webapp/actions/Entry/ListAction.php
・webapp/templates/Entry/List/List.html
の2ファイルになります。



<?php

class Entry_ListAction extends Piece_Unity_Service_FlowAction
{

    function doActivityOnDisplayList()
    {
        Piece_Unity_Plugin_Factory::factory('HTMLComponent_Pagination')->invoke();
        ...
    


これでViewで__paginationという名前でService_Paginationオブジェクトが使えるようになりました。

次にService_Paginatorオブジェクトに必要な情報を設定していきます。この時点ではService_Paginatorオブジェクトはロードされてないので読み込みましょう。



<?php

require_once 'Piece/Unity/Service/Paginator.php'

class Entry_ListAction extends Piece_Unity_Service_FlowAction
{



これで準備はできました。では設定していきましょう。doActivityOnDisplayListアクションを以下のようにします。



<?php

class Entry_ListAction extends Piece_Unity_Service_FlowAction
{

    function doActivityOnDisplayList()
    {
        Piece_Unity_Plugin_Factory::factory('HTMLComponent_Pagination')->invoke();

        $viewElement =  &$this->_context->getViewElement();

        $paginator =  &new Piece_Unity_Service_Paginator();
        // 1ページの最大表示数を指定
        $paginator->limit = 3;
        // 総オブジェクト数の指定
        $paginator->count = count($this->_entries);
        // ページの指定がある場合はページを指定
        if ($this->_context->getRequest()->hasParameter($paginator->pageNumberKey)) {
            $paginator->currentPageNumber = $this->_context->getRequest()->getParameter($paginator->pageNumberKey);
        }

        // DBから取得済みのオブジェクトの絞込み
        $viewEntries = null;
        if (isset($this->_entries)) {
            $viewEntries = array_slice(array_values($this->_entries), $paginator->getOffset(), $paginator->limit);
        }

        $viewElement->setElementByRef('__paginator', $paginator);
        $viewElement->setElementByRef('entries', $viewEntries);
    }


あとはViewの一番最後にページャを読み込む命令を追加します。



<h4 class="date-header">List</h4>
<table>
<tr flexy:foreach="entries,entry">
  <td><a href="{__basePath}/edit.php?id={entry.id}">{entry.title}</a></td>
</tr>
</table>

{__pagination.paginate(__paginator):h}


これでデータを4件以上入れるとページャが表示されると思います。

 


一段落つきましたが、オブジェクト配列の範囲絞込みとページネーションは結構絡んでいるので、そのあたりをまとめてオブジェクトを作ってしまいましょう。



<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */

require_once 'Piece/Unity/Service/Paginator.php';

/**
 * Piece_Unity_Service_Paginator_ORM
 *
 * @author OGAWA Katsuhiro <katsuhiro@asial.co.jp>
 */
class Piece_Unity_Service_Paginator_ORM extends Piece_Unity_Service_Paginator
{

    var $objects;

    function Piece_Unity_Service_Paginator_ORM( &$objects, $limit = null)
    {
        $this->setObjects($objects);
        $this->limit = $limit;
    }

    function setObjects( &$objects)
    {
        $this->objects =  &$objects;
        $this->count = count($objects);
    }

    function  & getObjects()
    {
        return $this->objects;
    }

    function getResults()
    {
        if (is_null($this->objects)) {
            $return = null;
            return $return;
        }

        return array_slice(array_values($this->objects), $this->getOffset(), $this->limit);
    }

}


ついでにコンストラクタにlimitも渡せるようにしてみました。今回はとりあえずなので、Entry_ListActionと同じディレクトリにPaginator_ORM.phpという名前で保存しました。使い方は以下のようになります。




<?php

require_once dirname(__FILE__) . '/Paginator_ORM.php'

class Entry_ListAction extends Piece_Unity_Service_FlowAction
{

    function doActivityOnDisplayList()
    {
        Piece_Unity_Plugin_Factory::factory('HTMLComponent_Pagination')->invoke();

        $viewElement =  &$this->_context->getViewElement();

        $paginator =  &new Piece_Unity_Service_Paginator_ORM($this->_entries, 3);
        if ($this->_context->getRequest()->hasParameter($paginator->pageNumberKey)) {
            $paginator->currentPageNumber = $this->_context->getRequest()->getParameter($paginator->pageNumberKey);
        }
        $viewEntries = $paginator->getResults();

        $viewElement->setElementByRef('__paginator', $paginator);
        $viewElement->setElementByRef('entries', $viewEntries);
    }


これでさっきより使いやすくなったのではないかと思います。

ざーっと作りながらやってきましたが、まだバージョン0.1.0ながら基本的なところはしっかり作られているなと思いました。
現在テンプレート表示部分のテンプレートが固定となっていますが、今後はそのあたりがもっと柔軟になってくるのかと思います。

今後も積極的にPiece Frameworkの動向は追っかけていこうと思いますので、皆さんも是非Piece FrameworkでセキュアなWebアプリケーションを作ってみてください。


9月25日 追記

作者の久保様よりコメントにて、コンポーネントをpiece-unity-config.yamlファイルでロードする方法をご教示していただきました。



- name: Renderer_Flexy
  point:
    ...
    - name: components
      type: extension
      value:
        - HTMLComponent_Pagination


Renderer_Flexyの項目内に上記のcomponentsの定義を行うことで、自動で読み込まれるようになります。

また、Paginatorオブジェクトはコンストラクタ内で生成し、アクションのプロパティとして保持しステートフルに扱うほうがアクションが簡潔にすむとのアドバイスも頂きました。ぜひ参考にしてみてください。