読者です 読者をやめる 読者になる 読者になる

Piece Frameworkで独自レンダラを使う

PHP

Webアプリケーションを開発していると、同じデータを異なる形式で出力したいということが多々あります。例えば、通常はブラウザで閲覧しているけれども、その内容をExcel、 PDFでダウンロードしたい、という様な状況です。
エントリポイント内でレンダラを独自レンダラに切り替えれば、この様な状況にスマートに対処できます。
レンダラを動的に切り替えるには、次のような記述を追加します。

...
$config =& new Piece_Unity_Config();
$config->setExtension('View', 'renderer', 'Renderer_XXXX');
$unity =& new Piece_Unity($confirDir, $cacheDir, $config);
...

独自レンダラは昨日のエントリで紹介したように、KernelConfiguratorで設定したプラグインディレクトリに配置します。


次のような、アクションクラスを考えてみましょう。

class SomeAction {
...
    function someEvent() {
        // 入力値を取得
        $req =& $this->_payload->getRequest();
        $id = $req->getParameter('id');

        // データを取得
        $data = $this->_getSomeData($id);

        // ビューにデータを渡す
        $el = $this->_payload->getViewElement();
        $el->setElement('data', $data);
    }
...
}

このアクションクラスは、リクエストからパラメタを受け取り、それに基づいてデータを取得します。アクションクラスは、ビューが何であるかを全く知りません。ビューへのアクセスは、ViewElementクラスによって抽象化されています。出力形式は通常のHTMLかもしれませんし、XMLやPDFかもしれません。
ここでは、jsonで出力することを考え、次のような独自レンダラを作成しました。

<?php
include_once 'Piece/Unity/Plugin/Common.php';

class Piece_Unity_Plugin_Renderer_Json extends Piece_Unity_Plugin_Common
{
	function invoke() {
		$viewElement =& $this->_context->getViewElement();
		$elements = $viewElement->getElements();
		
		$userData = array();
		foreach($elements as $k => $v) {
			if (substr($k, 0, 1) != '_') {
				$userData[$k] = $v;
			}
		}
		
		$json = json_encode($userData);
		print $json;
	}
}
?>

このレンダラはアクション内でViewElementに設定したデータをjson形式で出力します。
実際には、json_encodeを呼び出す前に、文字列をutf-8に変換したり、循環参照を除去したり、jsonに合わせたContent-Typeヘッダーを出力したり、さらに、Piece Frameworkの有限状態機械向けのチケットを付与したりと、もっと複雑な処理を行わなくてはなりません。しかし、ここでは議論を進めるための疑似コードのようなものと考えてください。


このようなカスタムレンダラを用意した上で、複数のエントリポイントを準備します。

- public_html
    - index.php (ビューにSmartyやFlexyを設定した通常のエントリポイント)
    - ajax.php (XMLHttpRequestオブジェクト向けのエントリポイント)

ajax.phpの中で動的にビューを設定します。

// ajax.php
...
$config =& new Piece_Unity_Config();
$config->setExtension('View', 'renderer', 'Renderer_Json');
$unity =& new Piece_Unity($confirDir, $cacheDir, $config);
...

これだけで、index.phpにアクセスした場合はHTMLを返し、ajax.phpにアクセスした場合はjsonを返すことができます。
あとはJavascriptをバリバリ書けば、Piece Frameworkを使って、今風のリッチクライアントが作成できます。
重要なことは、特別なインターフェイスを実装したりせずに、データ取得のロジックには全く手を加えることなく、出力結果を変えることができてしまうということです。独自レンダラを作成すれば、このような調子で、RESTやSerialized PHPによるWebサービスにも対応できるでしょう。
プラグイン機構による、柔軟な拡張性。Piece Frameworkの魅力は、まさにこの点にあると思います。