PHPTALのカスタムモディファイア if, eq を作ってみた
PHPTALと格闘すること数日。PHPTALにはif文っぽい表現をするにはPHPモディファイアを使わざるをえないことに悩みました。
condとeqがあればいいのに。なぜだろう。これが TAL-way なのか。でも欲しい。PHPモディファイアは使いたくない。でも。でも。。。
んが作った。
if, eq モディファイア
function phptal_tales_if( $src, $nothrow ) { list($if_part, $right) = explode('?', $src, 3); if (strpos($right,'|')) { list($then_part, $else_part) = explode('|', $right, 2); } else { $then_part = $right; $else_part = 'null'; } return '('.phptal_tales($if_part, $nothrow).') ? '.phptal_tales($then_part, $nothrow).' : '.phptal_tales($else_part, $nothrow).''; } function phptal_tales_eq( $src, $nothrow ) { list($left, $right) = explode(' ', $src, 2); return '('.phptal_tales($left, $nothrow).' == '.phptal_tales($right, $nothrow).' )'; }
condでなくifにした。
使い方
コントローラー
$people = array(); $people[] = (object)array("name"=>"foo", "phone"=>"01-344-121-021"); $people[] = (object)array("name"=>"bar", "phone"=>"05-999-165-541"); $people[] = (object)array("name"=>"baz", "phone"=>"01-389-321-024"); $people[] = (object)array("name"=>"quz", "phone"=>"05-321-378-654"); $template->people = $people; echo $template->execute();
テンプレート
<span tal:replace="if: eq:people/0/name people/0/name ? string:then " >default</span> :then <br/> <span tal:replace="if: eq:people/0/name people/1/name ? string:then " >default</span> :null <br/> <span tal:replace="if: eq:people/0/name people/0/name ? string:then | string:else" /> :then <br/> <span tal:replace="if: eq:people/0/name people/1/name ? string:then | string:else"/> :else <br/> <span tal:replace="if: exists:people/1 ? string: people/1 exists | string: people/1 not exists " >default</span> :people/1 exists <br/> <span tal:replace="if: exists:people/100 ? string: people/100 exists | string: people/100 not exists " >default</span> :people/100 not exists <br/>
というわけで
PHPTALの道から外れるかもしれないが作ってすっきりした。これならいろいろ表現できそう。もとからあるexistsも活かせるし、neもすぐ作れるね。
YiiFrameworkでPHPTALしてみた
PHPTALやってみようかと思ったので、YiiFrameworkで動くPHPTALViewRenderer作ってみた。
インストール
PHPTAL
phptalとかgithubからzipをダウンロードし解凍し、classes ディレクトリ下の PHPTALディレクトリと PHPTAL.phpを prorected/vendor/PHPTAL へコピーする。
PHPTALViewRenderer
次をコピペする。ETwigViewRenderer を参考に作成しました。
prorected/extension/PHPTALViewRenderer.php
<?php class PHPTALViewRenderer extends CApplicationComponent implements IViewRenderer { /** * @var string Path alias to PHPTAL.php */ public $PHPTALPathAlias = 'application.vendors.PHPTAL'; /** * @var string Template files extension */ public $fileExtension = '.html'; private $_basePath; private $_basePathLength; function init() { require_once Yii::getPathOfAlias($this->PHPTALPathAlias).'/PHPTAL.php'; Yii::registerAutoloader(array('PHPTAL', 'autoloadRegister'), true); $app = Yii::app(); /** @var $theme CTheme */ $theme = $app->getTheme(); if ($theme === null) { $this->_basePath = $app->getBasePath(); } else { $this->_basePath = $theme->getBasePath(); } $this->_basePathLength = strlen($this->_basePath) ; return parent::init(); } public function renderFile($context, $sourceFile, $data, $return) { $sourceFile = "protected/".substr($sourceFile, $this->_basePathLength); $phptal = new PHPTAL($sourceFile); $phptal->this = $context; foreach($data as $key => $val) { $phptal->$key = $val; } $result = $phptal->execute(); if ($return) { return $result; } echo $result; } }
設定
PHPTALViewRenderer を設定
prorected/config/main.php
'components'=>array( 'viewRenderer'=>array( 'class'=>'ext.PHPTALViewRenderer', 'fileExtension' => '.html', ),
PHPTALのサンプルを試す
コントローラー
PHPTALのサンプルのパクリ。Personクラス作るのが面倒なので(object)で代用。
protected/controllers/TestController.php
<?php class TestController extends Controller { public $layout='column1'; public function actionIndex() { $title = 'The title value'; $people = array(); $people[] = (object)array("name"=>"foo", "phone"=>"01-344-121-021"); $people[] = (object)array("name"=>"bar", "phone"=>"05-999-165-541"); $people[] = (object)array("name"=>"baz", "phone"=>"01-389-321-024"); $people[] = (object)array("name"=>"quz", "phone"=>"05-321-378-654"); $this->render('index', compact('title', 'people')); } }
ビュー
PHPTALのサンプルそのまんま。
protected/views/test/index.html
<?xml version="1.0"?> <html> <head> <title tal:content="title"> Place for the page title </title> </head> <body> <h1 tal:content="title">sample title</h1> <table> <thead> <tr> <th>Name</th> <th>Phone</th> </tr> </thead> <tbody> <tr tal:repeat="person people"> <td tal:content="person/name">person's name</td> <td tal:content="person/phone">person's phone</td> </tr> <tr tal:replace=""> <td>sample name</td> <td>sample phone</td> </tr> <tr tal:replace=""> <td>sample name</td> <td>sample phone</td> </tr> </tbody> </table> </body> </html>
結果
得られたhtmlの一部
layouts/main.php, layouts/column1.php の内部に↓が出力される。
<?xml version="1.0"?> <html> <head> <title>The title value</title> </head> <body> <h1>The title value</h1> <table> <thead> <tr> <th>Name</th> <th>Phone</th> </tr> </thead> <tbody> <tr> <td>foo</td> <td>01-344-121-021</td> </tr><tr> <td>bar</td> <td>05-999-165-541</td> </tr><tr> <td>baz</td> <td>01-389-321-024</td> </tr><tr> <td>quz</td> <td>05-321-378-654</td> </tr> </tbody> </table> </body> </html>
課題
- もっとPHPTALを学ばなきゃ
- CWebUserへのアクセスは $template->user = Yii::app()->user; とすれば可能
- layouts/main.php, layouts/column1.php をどうにかする
- renderPartialは macroを使うのかな
- formatterはモディファイアに組み込むのかな
- yii::t()は PHPTAL_TranslationService に組み込むのかな
- フラグメントキャッシュは PHPTAL_Trigger を使って実現するのかな
次は TAL-way じゃないのでサポートしなくていいよね
- widget
- CHTML