Home > Tags > PHPTAL

PHPTAL

Zend Framework のViewにPHPTALを使う

(少なくとも日本においては)PHPのテンプレートエンジンと言えばSmartyが知名度・普及度共に圧倒的だが、Smartyで定義されたテンプレートファイルはプレビューしたときにデザインが崩れるという欠点がある。これはSmartyを知らないデザイナーさんとの協業をする場合に大きな問題になるし、自分でデザインをするとしてもロジック側が完成しないと出来上がりのイメージを目で見ることができないのがつらい。

ところで最近のPHP製フレームワークはViewとして素のPHPファイルを使うのがモダンスタイルということになっている。確かにテンプレートエンジンを使わずとも記述を工夫すればテンプレート風に書くことはできるしなによりその方が速度の面で有利だ。 そこで目を付けたのがPHPTALだ。日本語のマニュアルも整備されている。 以下のエントリを見ると PHPテンプレートベンチマーク —- PHPTALに注目 – なんたらノート 第二期 速度的にはSmartyとそん色ない。 なによりも大きな特徴はこのエントリが述べているように

* タグ構造を維持したまま、属性に制御コードを書く(デザイナフレンドリ)

* 元ページのDOMノードをラップするマクロを定義できる

という二点だ。2番目の特徴はさておき最初の部分だけでもPHPTALを使う価値が十分にあると思う。

PHPTALとZend Frameworkとの組み合わせについては次の情報が有力と思われる。 TAAT — Zend Framework Tutorial Step 2

※著者はポーランド人のようである。Zend Framework関連の海外情報を見ているとポーランド人が発信した情報が多いのに気づく。

今回PHPTALの調査を兼ねてこのソースをダウンロードして動かしてみた。なお、著者の説明によると

${structure helper:layout().content}

のような記述でビューに変数を書けるとあるのだが、これではPHPTALの美点が失われてしまうのでいただけない。PHPTAL本来の記述を試してみることにする。 コントローラ側で

$this->view->name = 'name';
$this->view->defaulttext = 'hoge@example.com';
$this->view->attributes = array('id'=>'anotherID','size'=>22);

と書きビュー側で

<li tal:content="structure helper:formText(name, defaulttext, attributes)">この部分は置き換えられる</li>

としたところ出力されるHTML が

 <li><input type="text" name="name" id="anotherID" value="hoge@example.com" size="22" /></li>

だったのでこのPHPTAL式記述で問題ないようだ。 なお、PHPTALの仕様として

tal:content=”$value”

と書いた場合に$valueは第2引数にENT_QUOTESを、第3引数に文字エンコーディング(デフォルト値はUTF8)を伴ったhtmlspecialchars関数で自動的にエスケープされる。セキュリティの観点から見てこれらのパラメータは指定する必要があるので、PHPTALのこの仕様は正しい。(参照:htmlspecialchars/htmlentitiesの正しい使い方 )もしエスケープさせたくない場合は

tal:content=”structure $value”

と”structure”を付加すれば良い。

さてまずレイアウトを定義したファイルだが

application/modules/default/views/layouts/main.tpl.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
		<title>Main layout</title>
	</head>

	<body id="index">
		<div id="page-container">
		<h1 id="title">Main layout</h1>

			<?php echo $this->layout()->content ?>      ⇐1

			${structure helper:layout().content}           ⇐ 2

		    <span tal:content="structure helper:layout().content">contents</span>    ⇐ 3

		</div>
	</body>
</html>

1. がZF標準の書き方、2.が変数の中身だけを書く方法、3.がPHPTALの美点を生かした書き方である。3つのうちどれを使っても全く同じHTMLを吐き出す。(ZFSyntax.phpというプレフィルターがあるので1.のように書いてもちゃんとPHPTALが理解できるように内部で書き換えてくれるのだ。)ここではもちろん3.を採用する。 レイアウトの中に含めるビューは

application/modules/default/views/templates/index/index.tpl.html
<div >
 <ul>
    <li tal:content="structure helper:formatCurrency(price1)">price1(JPY)</li>
    <li tal:content="price2">price(with no helper)</li>
    <li tal:content="structure helper:formatCurrency(price2, '&euro;')">price2(EURO)</li>
    <li tal:content="structure helper:formText(name, defaulttext, array('size'=>35, 'id'=>'myID'))">this is email</li>
    <li tal:content="structure helper:formText(name, defaulttext, attributes)">this is email</li>
    <li tal:content="name">this is email</li>
  </ul>
</div>

コントローラではテスト用に意地悪な値をセットする。

application/modules/default/controllers/IndexControllers.php
<?php
class IndexController extends Zend_Controller_Action
{
    public function indexAction ()
    {
        $this->view->price1 = 'ABC';
        $this->view->price2 = '12800';
        $this->view->name = "'&<>";
        $this->view->defaulttext = "hoge@example.com'&<>";
        $this->view->attributes = array('size'=>22, 'id'=>'"anotherID"');

    }
}

通貨表示用のフォーマットを行うビューヘルパーを作る。

application/modules/default/views/helpers/FormatCurrency.php
<?php

class My_View_Helper_FormatCurrency extends Zend_View_Helper_Abstract {

    public function formatCurrency($value, $symbol='&yen;')
    {
        $output = $value;
        $value = trim($value);
        if (is_numeric($value)) {
            if ($value >= 0) {
                $output = $symbol . number_format($value, 2);
            } else {
                $output = '-' . $symbol . number_format(abs($value), 2);
            }
        } else {
        		$output = '###値が無効です###';

        }
        return $output;
    }
}

表示結果は

090624 0001 300x187 Zend Framework のViewにPHPTALを使う

となる。はきだされたHTMLソースを見ると

Main layout
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
		<title>Main layout</title>
	</head>

	<body id="index">
		<div id="page-container">
		<h1 id="title">Main layout</h1>

		    <span><div>

  <ul>

    <li>###値が無効です###</li>
    <li>12800</li>
    <li>&euro;12,800.00</li>
    <li><input type="text" name="'&amp;&lt;&gt;" id="myID" value="hoge@example.com'&amp;&lt;&gt;" size="35" /></li>
    <li><input type="text" name="'&amp;&lt;&gt;" id="&quot;anotherID&quot;" value="hoge@example.com'&amp;&lt;&gt;" size="22" /></li>
    <li>&#039;&amp;&lt;&gt;</li>

  </ul>
</div></span>

		</div>
	</body>
</html>

である。formTextに入れた値のシングルクォートがエスケープされていない。

調べてみると

<li tal:content="name">this is email</li>

というPHPTALの記述はコンパイルされて

<li><?php echo phptal_escape($ctx->name, ENT_QUOTES, 'UTF-8') ?></li>

と展開され、

<li tal:content="structure helper:formText(name, defaulttext, attributes)">this is email</li>

<li><?php echo $ctx->this->formText($ctx->name, $ctx->defaulttext, $ctx->attributes) ?></li>

となっていた。formTextはZF純正のビューヘルパーで、エスケープ処理には内部的にhtmlspecialcharsを使っているのだが、第2と第3パラメータは明示的に指定する必要があるのである。そこで

library/My/PHPTAL/Escape.php
<?php

class My_PHPTAL_Escape {

    public static function safeEscape ($var) {
        return htmlspecialchars($var, ENT_QUOTES, mb_internal_encoding());

    }

}

というクラスを作り、ZFでのエスケープ処理の際は常にこれを呼ぶようにする。

library/My/Controller/Plugin/ViewSetup.php
           ~~~
$view = new My_PHPTAL_ZFView();
//set 2nd and 3rd parameters to escape method
 $view->setEscape(array('My_PHPTAL_Escape', 'safeEscape'));    // <== Added
          ~~~
$phptal = new PHPTAL;
 $view->setEngine($phptal);
 $phptal->setPhpCodeDestination($root . '/temp')
 ->setEncoding(mb_internal_encoding())        // <== Added
 ->setForceReparse(true)
 ->setPreFilter(new My_PHPTAL_Filter_ZFSyntax());

改めて出力してみると

    <li>###値が無効です###</li>
    <li>12800</li>
    <li>&euro;12,800.00</li>
    <li><input type="text" name="&#039;&amp;&lt;&gt;" id="myID" value="hoge@example.com&#039;&amp;&lt;&gt;" size="35" /></li>
    <li><input type="text" name="&#039;&amp;&lt;&gt;" id="&quot;anotherID&quot;" value="hoge@example.com&#039;&amp;&lt;&gt;" size="22" /></li>
    <li>&#039;&amp;&lt;&gt;</li>

となりinput中のシングルクォートもエスケープされるようになった。 ということでPHPTALの機能のごく一部を触っただけだがこれはなかなかいけそうな雰囲気である。PHPアプリケーション構築でテンプレートエンジンを利用してデザイン部分を分離する必要がある場合、PHPTALはSmartyに代わる有力な候補になるのではないだろうか。

Home > Tags > PHPTAL

アーカイブ

Return to page top