2007年12月27日木曜日

PHPTALの使い方 PHPスクリプトの記述

●PHPスクリプト上での使い方
   ・定数
    PHPTAL_VERSION
        利用されているPHPTALのバージョン
        
    PHPTAL_PHP_CODE_DESTINATION
        PHPTALの一時ファイル置き場、PHPTAL.phpを読み込む前に設定すれば変更可能。
        デフォルトでは [ /tmp ] になる。
    
    PHPTAL_FORCE_REPARSE
        一時ファイルを無視して強制的にテンプレートファイルをパースするかどうかの設定。
       PHPTAL.phpを読み込む前に true にすれば、設定可能。デフォルトは false
    
    PHPTAL_TEMPLATE_REPOSITORY
        テンプレートファイル置き場のデフォルト指定。標準では指定なし。
    
    ・フィルター
        prefilterとpostfilterの二種類がある。
        
        -prefilter  : テンプレートファイルをパースする前に操作するフィルタ。
                      直後にパースすることになるため、XML整形式でなくなるような操作をするとエラーになる。
                      登録の仕方 $phptal->setPreFilter(new Prefilter());
                     
        -postfilter : テンプレートファイルをパースし、TAL式などすべて実行後に操作するフィルタ。
                      prefilterと違いパースエラーの心配はない。
                      登録の仕方 $phptal->setPostFilter(new Postfilter());
        
        なお、共通する制限として、setPre(Post)Filterで設定できるものはひとつのみになるため、
        複数のフィルターを使いたい場合は同一のフィルターに複数の処理を記載するか、以下のような
        クラスを用意するなどの対応が必要
        
                require_once 'PHPTAL_Filter.php';
        
        /**
         * PHPTALにてフィルターを複数使えるようにするフィルター
         */
        class FilterChain implements PHPTAL_Filter {
            private $_filters = array();
        
            public function add(PHPTAL_Filter $filter){
                $this->_filters[] = $filter;
            }
        
            public function filter($source){
                foreach ($this->_filters as $filter){
                    $source = $filter->filter($source);
                }
                return $source;
            }
        }
        
        
    ・トリガー
        登録しているトリガーのID を phptal:id に設定すると、そのIDに対して、トリガーを呼び出す。
        トリガーは start() → end()の順で呼び出され、start() で return される値により、タグの動作が変わる。
        -return self::SKIPTAG  :  そのタグ自身、要素などは出力せずに end() を実行する。
        -return self::PROCEED  :  そのタグ自身、要素などを出力した後に end() を実行する。
        return しなかった場合は SKIPTAG と同等の動きをする。
        
        
    ・TranslationService
        標準の PHPTAL_GetTextTranslator とは別に独自の文字列置換用クラスを実装することが可能。
        以下の4つのメソッドを実装しなくてはならない。
        
        - method setLanguage(...)
        使用言語を設定するメソッド。
        func_get_args() で 引数を取得するようにし、最初に設定されている言語が標準で利用される。
        
        - method useDomain($domain)
        ドメインを指定するメソッド。アプリケーションごとの言語設定の保存先を決定していれば、その中で
        開くドメインが決定される。
        
        - method setVar($key,$value)
        このメソッドは i18:name をコールした際に、最後に呼ばれるので、文章に反映される。
        
        - method translate($key)
        実際に文字列を置き換えるメソッド。 
        

                require_once 'PHPTAL/TranslationService.php';
        
        class MyTranslator implements PHPTAL_TranslationService {
        
            private $_currentDomain;
            private $_domains = array();
            private $_currentLang;
            private $_context = array();
            
            public function setLanguage(){
                $langs = func_get_args();
                foreach ($langs as $lang){
                    // if $lang known use it and stop the loop
                    $this->_currentLang = $lang;
                    return;
                }
            }

            public function useDomain($domain){
                if (!array_key_exists($domain, $this->_domains)){
                    $file = "domains/$this->_currentLang/$domain.php";
                    $this->_domains[$domain] = include($file);
                }
                $this->_currentDomain = $this->_domains[$domain];
            }
            
            public function setVar($key, $value){
                $this->_context[$key] = $value;
            }
            
            public function translate($key){
                $value = $this->_currentDomain[$key];
                
                // interpolate ${myvar} using context associative array
                while (preg_match('/\${(.*?)\}/sm', $value, $m)){
                    list($src,$var) = $m;
                    if (!array_key_exists($var, $this->_context)){
                        $err = sprintf('Interpolation error, var "%s" not set', 
                                       $var);
                        throw new Exception($err);
                    }
                    $value = str_replace($src, $this->_context[$var], $value);
                }
                
                return $value;
            }
        }
        ?>
       
    ・PHPTAL_GetTextTranslator
    gettextはPHPでGNU Gettextをサポートさせているときに利用可能な、標準のGNU国際化/翻訳システム。
    簡単に利用できるが、gettext関連の関数ををインストールしないといけないのが難点。
    
    http://php.mirror.camelnetwork.com/manual/ja/function.gettext.php

        - gettext のインストール
        - 「--with-gettext[=DIR]」をつけてPHPを再インストール
        - gettext が利用できるかは以下で確認可能
        if (function_exists("gettext")){
            echo "gettext is supported\n";
        } else {
            echo "gettext is not installed\n";
        }
        
        -ディレクトリ構成
       こんな感じの予定。translationsじゃなくてlocalのほうがいいか・・・?
        views
        `-- translations
            |-- en_US
            |   `-- LC_MESSAGES
            |       |-- zfs.mo
            |       `-- zfs.po
            |-- ja_JP
            |   `-- LC_MESSAGES
            |       |-- messages.mo
            |       |-- zfs.mo
            |       `-- zfs.po
            `-- zfs.pot
        
        - pot ファイルの作成
        多言語対応するための基本となるファイル。phpに直接記載していれば、xgettext コマンドでとってこれる。
        今回はPHPTALに記述されるので自動抽出ができない為、手動で作成。以下のような感じ。
        !!!このファイルを言語関連の基本ファイルとし、msgid の追記はこのファイルのみに行う。!!!
        ※"Content-Transfer-Encoding: 8bit\n"までの部分は xgettext に --force-po オプションで自動生成
        
        # SOME DESCRIPTIVE TITLE.
        # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
        # This file is distributed under the same license as the PACKAGE package.
        # FIRST AUTHOR , YEAR.
        #
        #, fuzzy
        msgid ""
        msgstr ""
        "Project-Id-Version: PACKAGE VERSION\n"
        "Report-Msgid-Bugs-To: \n"
        "POT-Creation-Date: 2007-12-27 01:00+0900\n"
        "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
        "Last-Translator: FULL NAME \n"
        "Language-Team: LANGUAGE \n"
        "MIME-Version: 1.0\n"
        "Content-Type: text/plain; charset=CHARSET\n"
        "Content-Transfer-Encoding: 8bit\n"
        
        msgid "Hello World"
        msgstr ""
        
        msgid "Welcome"
        msgstr ""
        
        msgid "null"
        msgstr ""
        
        
        
        TODO:TAL形式から何らかの形式に変換して、自動で pot ファイルを作成できるようにする。
        
        - po ファイルの作成 & マージ
        一番最初は差分などないので、zfs.pot を 翻訳したい言語のディレクトリにコピーする。
        
        % cp zfs.pot ./ja_JP/LC_MESSAGES/zfs.po
        
        コピーしたら、そのファイルを編集する。こんな感じ>>> msgstr "ここに翻訳を書く"
        
        zfs.pot に文章を追加したら、差分が発生してしまい、コピーして対応するには手間が
        かかりすぎるので、マージを行う。※ 第一引数と第二引数の順番に注意!
        
        % msgmerge ja_JP/LC_MESSAGES/zfs.po zfs.pot -o ja_JP/LC_MESSAGES/zfs.po
        
        これで、差分を反映してくれる。差分は msgid に値が入っているもののみ反映。
        また、pot 側で削除した場合、翻訳済みのものはコメントアウト、未翻訳の場合は削除される。
        
        # SOME DESCRIPTIVE TITLE.
        # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
        # This file is distributed under the same license as the PACKAGE package.
        # FIRST AUTHOR , YEAR.
        #
        #, fuzzy
        msgid ""
        msgstr ""
        "Project-Id-Version: PACKAGE VERSION\n"
        "Report-Msgid-Bugs-To: \n"
        "POT-Creation-Date: 2007-12-27 01:00+0900\n"
        "PO-Revision-Date: 2007-12-26 22:05+0900\n"
        "Last-Translator: FULL NAME \n"
        "Language-Team: LANGUAGE \n"
        "MIME-Version: 1.0\n"
        "Content-Type: text/plain; charset=t=UTF-8\n"
        "Content-Transfer-Encoding: 8bit\n"
        
        #, fuzzy
        msgid "Hello World"
        msgstr "はろーわーるど"
        
        msgid "Welcome"
        msgstr "ようこそ"
        
        msgid "null"
        msgstr ""
        
        また、差分を反映した際、幾つ未翻訳や変更点があるかなどを確認したいときには、
        以下のコマンドで確認できる
        
        % msgfmt --verbose ja_JP/LC_MESSAGES/zfs.po
        1 個の翻訳メッセージ, 1 個の翻訳があいまいです, 1 個の未訳のメッセージ.
        
        結果の説明
        ・翻訳メッセージ -> そのまま文字通り。
        ・翻訳があいまい -> pot ファイル側で変更があった場合、po 側に変更があったことを通知するために
                            変更があった msgid の前の行に #, fuzzy と追記される。これの数が表示される。
                            つまり、翻訳済みだが変更があったため要確認 な状態。
        ・未訳のメッセージ -> 新規に追加された msgid の分 msgstr が空の状態。
        
        - mo ファイルの作成
        プログラム側で扱うバイナリ形式に変換する
        
        % cd ./ja_JP/LC_MESSAGES/
        % msgfmt zfs.po [-f] -o zfs.mo
        ※ -f オプションはfuzzyを含むかどうかの指定
        
        - View への組み込み
        
        $tr = new PHPTAL_GetTextTranslator();
        $tr->setLanguage('ja_JP.UTF-8', 'ja_JP');
        $tr->addDomain('zfs', '/path/to/app/views/translations/');
        $tr->useDomain('zfs');
        
        $view = new ZFS_View();
        $view->setTranslator($tr); 
        

2007年12月16日日曜日

PHPTAL ZendFrameworkへの組み込み

1.View クラスの作成

Zend/View/Interface.php を 実装し動作するようにする。
機能はとりあえず最低限

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//一時(中間)ファイル置き場を設定する。
define('PHPTAL_PHP_CODE_DESTINATION','/tmp/phptal/');

//強制的にキャッシュを上書きする
define('PHPTAL_FORCE_REPARSE',true);

//テンプレートファイル置き場
//define('PHPTAL_TEMPLATE_REPOSITORY','')

//文字コード設定、標準はUTF-8
//define('PHPTAL_DEFAULT_ENCODING','')

require_once 'Zend/View/Interface.php';
require_once 'Zend/Loader.php';

require_once 'PHPTAL.php';
require_once 'PHPTAL/GetTextTranslator.php';

/**
* PHPTALをZend_View 同様に使うためのクラス。
*/
class ZFS_View implements Zend_View_Interface
{
/**
* 各スクリプト配置ディレクトリへのパス.
* Zend_View にあわせておく
*
* @var array
*/
private $_path = array(
'script' => array()
,'helper' => array()
,'filter' => array()
);
/**
* エンコードの指定、標準は UTF-8
* require_once 'PHPTAL.php' の前に定数の設定をする必要がある。
*
* @var string
*/
private $_encoding = PHPTAL_DEFAULT_ENCODING;

/**
* PHPTAL のインスタンスを格納する
* @var mixed
*/
protected $_phptal;

/**
* アサインした変数を格納する配列
* @var array
*/
protected $_context;

/**
* i18n対応 PHPTAL_GetTextTranslator のコンストラクタ
* @var mixed
*/
protected $_gettext;

/**
* Constructor.
*
* @param array $config Configuration key-value pairs.
* @todo helper/filterを実装した際追加すること、helperはあるのか?
*/
public function __construct($config = array()){

$this->_phptal = new PHPTAL();

// set inital paths and properties
$this->setScriptPath(null);

// base path
if (array_key_exists('basePath', $config)) {
$prefix = 'Zend_View_Phptal';
if (array_key_exists('basePathPrefix', $config)) {
$prefix = $config['basePathPrefix'];
}
$this->setBasePath($config['basePath'], $prefix);
}

// user-defined view script path
if (array_key_exists('scriptPath', $config)) {
$this->addScriptPath($config['scriptPath']);
}
}

/**
* 各スクリプトのパスを返す、Zend_View にあわせる
*
* @param string $type The path type ('helper', 'filter', 'script')
* @return array
*/
private function _getPaths($type)
{
return $this->_path[$type];
}


/**
* PHPTAL オブジェクトを返す
*
* @return mixed
*/
public function getEngine(){
return $this->_phptal;
}

/**
* テンプレート設置パスを初期化し設定する。
*
* @param string|array The directory (-ies) to set as the path. Note that
* the concrete view implentation may not necessarily support multiple
* directories.
* @return void
*/
public function setScriptPath($path){
$this->_path['script'] = array();
$this->_addPath('script', $path);
return $this;
}

/**
* テンプレート設置パスを追加する
*
* @param string|array The directory (-ies) to set as the path. Note that
* the concrete view implentation may not necessarily support multiple
* directories.
* @return void
*/
public function addScriptPath($path){
$this->_addPath('script', $path);
return $this;
}

/**
* テンプレート設置パスを返す。
*
* @return array
*/
public function getScriptPaths()
{
return $this->_path['script'];
}


/**
* view 用の各リソース設置のパスを設定する。
*
* @param string $path
* @param string $classPrefix
* @return void
* @todo helper/filterを実装した際追加すること、helperはあるのか?
*/
public function setBasePath($path, $classPrefix = 'Zend_View_Phptal'){
$path = rtrim($path, '/');
$path = rtrim($path, '\\');
$path .= DIRECTORY_SEPARATOR;
$classPrefix = rtrim($classPrefix, '_') . '_';
$this->setScriptPath($path . 'templates/');
return $this;
}

/**
* Add an additional path to view resources
*
* @param string $path
* @param string $classPrefix
* @return void
* @todo helper/filterを実装した際追加すること、helperはあるのか?
*/
public function addBasePath($path, $classPrefix = 'Zend_View_Phptal'){
$path = rtrim($path, '/');
$path = rtrim($path, '\\');
$path .= DIRECTORY_SEPARATOR;
$classPrefix = rtrim($classPrefix, '_') . '_';
$this->addScriptPath($path . 'templates/');
return $this;
}

/**
* __setをオーバーロード。テンプレート変数へのアサインをする。
*
* @param string $key The variable name.
* @param mixed $val The variable value.
* @return void
*/
public function __set($key, $val){
if ('_' != substr($key, 0, 1)) {
$this->assign($key, $val);
return;
}
require_once 'Zend/View/Exception.php';
throw new Zend_View_Exception('Setting private or protected class members is not allowed', $this);
}

/**
* __issetをオーバーロード、テンプレート変数へのアサイン状況を確認
*
* @param string $key
* @return boolean
*/
public function __isset($key){
return isset($this->_context[$key]);
}


/**
* __unset をオーバーロード、テンプレート変数から変数を削除する。
*
* @param string $key
* @return void
*/
public function __unset($key){
unnset($this->_context[$key]);
}

/**
* テンプレート変数へ値をアサインする。
*
* @see __set()
* @param string|array $spec The assignment strategy to use (key or array of key
* => value pairs)
* @param mixed $value (Optional) If assigning a named variable, use this
* as the value.
* @return void
*/
public function assign($spec, $value = null){
// which strategy to use?
if (is_string($spec)) {
// assign by name and value
if ('_' == substr($spec, 0, 1)) {
require_once 'Zend/View/Exception.php';
throw new Zend_View_Exception('Setting private or protected class members is not allowed', $this);
}
$this->_context[$spec] = $value;
} elseif (is_array($spec)) {
// assign from associative array
$error = false;
foreach ($spec as $key => $val) {
if ('_' == substr($key, 0, 1)) {
$error = true;
break;
}
$this->_context[$key] = $val;
}
if ($error) {
require_once 'Zend/View/Exception.php';
throw new Zend_View_Exception('Setting private or protected class members is not allowed', $this);
}
} else {
require_once 'Zend/View/Exception.php';
throw new Zend_View_Exception('assign() expects a string or array, received ' . gettype($spec), $this);
}
return $this;
}

/**
* Clear all assigned variables
*
* Clears all variables assigned to Zend_View either via {@link assign()} or
* property overloading ({@link __get()}/{@link __set()}).
*
* @return void
*/
public function clearVars(){
$this->_phptal->_context = null;
}

/**
* 設定してきた値を PHPTAL のインスタンスににセットし、レンダリングを行う。
*
* @param string $name The script script name to process.
* @return string The script output.
*/
public function render($name){
$this->_setContext();
$this->_phptal->setEncoding($this->_encoding);
if(!empty($this->_gettext)){
$this->_phptal->setTranslator($this->_gettext);
}
$this->_phptal->setTemplateRepository($this->_path['script']);

$this->_phptal->setTemplate($name);
return $this->_phptal->execute();
}

/**
* 後から追加した物を優先的に使用する為に先頭に追加する。
*
* Zend_View_Phptal::_addPath($type, 'dirname') adds one directory
* to the path stack.
*
* Zend_View_Phptal::_addPath($type, $array) adds one directory for
* each array element value.
*
* In the case of filter and helper paths, $prefix should be used to
* specify what class prefix to use with the given path.
*
* @param string $type The path type ('script', 'helper', or 'filter').
* @param string|array $path The path specification.
* @param string $prefix Class prefix to use with path (helpers and filters
* only)
* @return void
* @todo helper/filterを実装した際追加すること、helperはあるのか?
*/
private function _addPath($type, $path, $prefix = null)
{
foreach ((array) $path as $dir) {
// attempt to strip any possible separator and
// append the system directory separator
$dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $dir);
$dir = rtrim($dir, DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);

switch ($type) {
case 'script':
// add to the top of the stack.
array_unshift($this->_path[$type], $dir);
break;
default:
// add as array with prefix and dir keys
array_unshift($this->_path[$type], array('prefix' => $prefix, 'dir' => $dir));
break;
}
}
}

/**
* PHPTALに設定済みの変数をアサインする。
*
* @return void
*/
protected function _setContext(){
if(empty($this->_context)){
return false;
}
foreach($this->_context as $key => $item){
$this->_phptal->set($key, $item);
}
}

/**
* アサインされた変数を返す
*
* @return array
*/
public function getContexts(){
return $this->_context;
}

/**
* エンコードを設定する。
*/
public function setEncoding($encode){
$this->_encoding = $encode;
}

public function setTranslator($tr){
$this->_phptal->setTranslator($tr);
}

public function setPreFilter($filter){
$this->_phptal->setPreFilter($filter);
}

public function setPostFilter($filter){
$this->_phptal->setPostFilter($filter);
}

/**
* Register a trigger for specified phptal:id.
* @param $id string phptal:id to look for
*/
public function addTrigger($id, $trigger)
{
$this->_phptal->addTrigger($id, $trigger);
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

2.ViewRenderer への組み込み

「Zend_Controller_Front::run('/path/to/app/controllers');」の前に以下を記載、
setViewで上記Viewを設定し、テンプレートの拡張子を「.tpl.html」に変更。


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
$view = new Zend_View_Phptal();
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
$viewRenderer->setView($view,$param);
$viewRenderer->setViewSuffix('tpl.html');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ZendFrameworkの標準だと、「/path/to/app/views/scripts/」以下にコントローラー名と
アクション名を使って「controller_name/action_name.phtml」になる、これと同様に
phtmlだけtpl.htmlに変えたものでテンプレートにアクセスするので、各アクション毎に
テンプレートファイルを用意し設置する。

2007年12月7日金曜日

PHPTAL 残っているTAL関連の記述に関して。

残っているTAL関連の記述方法

マニュアルだけだと何を行っているのかわからないので、次からは実際に使ってみる。
英語力がないだけなのか・・・

●I18N namespace(国際化) について
I18N?:InternationalizatioN I と N の間には18文字あるから

こんな感じで呼び出すみたい。すぐにつかわないから設定ファイルについて
調べるのは保留。

$gettext = new PHPTAL_GetTextTranslator();
$gettext->addDomain($domain,$path);
$gettext->setEncoding($this->_encoding);
$phptal = new PHPTAL();
$phptal->setTranslator($gettext);

1.i18n:translate
2.i18n:name
3.i18n:attributes
4.i18n:domain
5.i18n:target


●PHPTAL namespace
TAL仕様の拡張。PHPTAL専用
1.phptal:debug

2.phptal:tales
この属性をもつタグに囲まれた部分は、TALES 方式ではなく 指定の方式で属性、要素
の内容を設定するように変更される。
指定できる方式は、tales と php のみで、デフォルトは talesになる。

<table phptal:tales="php">
<tr tal:repeat="myobject document.getChildren()">
<td
tal:content="myobject.mymethod()[10].otherMethod()['hashkey']"></td>
</tr>
</table>

3.phptal:cache
指定時間HTML要素をキャッシュする。時間は数字に以下の4つのどれかをつけ'd', 'h', 'm' or 's'
指定する。
基本的にそのページの共有キャッシュになるが、対象変数を指定することによりその変数の値により
キャッシュを切り替えることが可能。変数には、tal:define など、テンプレート内でで定義したものを
利用できない。

Examples:
三時間キャッシュされる
<div phptal:cache="3h">...</div>

$object->idの値にが同一の場合1日キャッシュされたものが表示される。
<ul phptal:cache="1d per object/id">...</ul>

●*:block
出力しないタグ、繰り返しのために記述するタグにおいて、同一のネームスペースを大量に使う
場合に利用すると記述量が少なくてすむ。以下のどちらも同じ内容を表示する。
タグの省略とともに、出力しないタグを存在するタグで記載しなくて済むメリットもある

<tal:block condition="someCondition" repeat="item someRepeat">
<div macro="x">
</tal:block>

<div tag="" condition="someCondition" repeat="item someRepeat">
<div macro="x">
</div>


●PHPTALES
TAL、METAL、PHPTAL にて使われる式構文。1つの属性が複数のPHPTALESを含む場合は、
「;」で区切って記述する。

1.path:
基本修飾語、何も指定されなければ先頭にこれがついているものと同等のものとして動作する。
なお、変数をテキストノードやほかのTALESの中で変数を使用したい場合には
「${path/to/my/variable}」と記述する。

2.Conditional statements
比較演算子、XML属性には<や>を記載するのを避けたほうがいいので、以下のようにテキストで代替する、
tal:condition や php:で利用する。
< : LT (less than) > : GT (greater than)
<= : LE (less or equal) >= : GE (greater or equal)

string:
文字列をあらわす。ただし、「;」は式のセパレータとして働き、「$」はPATHの開始を示すので、
そのままでは利用できない。それぞれ「;」=>「;;」、「$」=>「$$」と記述する。

php:
この後に続いてPHPの構文を記述することで式を評価する。「->」は「.」で記述すること。また
変数名の$は記述する必要はない。スペースを挟んで「.」を記載した場合には、結合演算子として
扱われる。

この属性は慎重に使用すべきであるとマニュアルにはある。どうしてもメソッドが必要な場合以外は
使わないようにする。

not:
真偽を表現するものに対して、真偽値を逆転させる。

exists:
PATH存在を確認し、存在すれば真、存在しなければ偽を返す。存在するかしないかわからないPATHを
指定する場合は、これで確認してからそのPATHを使用する。

default
式ではなく、キーワードとして利用する。要素や属性として標準で設定されているものを利用することを
宣言する。以下のように「|」で連結することで、path/to/possible/varが存在しない場合は、defineで
myVarは「default my var value」になる。

<span define="myVar path/to/possible/var | default">
default my var value
</span>

structure
default と同様式ではなく、キーワード。エスケープを抑止する。変数の出力は標準でエスケープされるので、
エスケープされたくない場合には、このキーワードを設定する。

Expression chains
default の例のように、「|」を使って式を連鎖的に記述することが可能。左側から式を評価し、偽で
あるときのみ次の式を実行する。Stringは必ず真になる。


メーリングリストメモ
http://lists.motion-twin.com/pipermail/phptal/

2007年12月2日日曜日

PHPTAL

PHPTAL

●インストール

PHPTAL の最新版は以下の PEAR コマンドを使ってインストール/アップグレード可能

pear install http://phptal.motion-twin.com/latest.tar.gz
pear upgrade http://phptal.motion-twin.com/latest.tar.gz

バージョンを指定してインストールしたい場合は以下のように行える

pear install http://phptal.motion-twin.com/files/PHPTAL-1.1.9.tar.gz
pear upgrade http://phptal.motion-twin.com/files/PHPTAL-1.1.9.tar.gz

自分は ZendFramework に組み込むことを目的としているので、PEAR でのインストールは使い
ませんでした。最新版ののファイルをDL・解凍し、PATH の通ったところに設置するだけでOKです。

*Example
tar zxvf PHPTAL-1.1.9.tar.gz
cp -r PHPTAL-1.1.9/PHPTAL* /path/to/php/incluede/folder

●TAL(Template Attribute Language)の記述方法
・属性の優先順位
どの順番で属性を宣言しても問題ない。TALの仕様と同様以下のような優先度になる。
1.define
2.condition
3.repeat
4.content or replacea
5.attributes
6.omit-tag

・TAL namespace での各属性の使い方。
1.tal:define
・変数の定義をする。
tal:define="[local | global] name expression [; define-expression...]"

local : 宣言したタグとそのタグの内側にあるタグでのみ有効な変数になる。
global : 宣言以降そのテンプレート内で有効な変数になる。
name : 変数名
expression : 変数の値

2.tal:condition
・条件命令
tal:condition="expression"
expression : expressionが偽の場合、記述されたタグとその内側のタグを出力しません。

3.tal:repeat
・繰り返し構文
tal:repeat="name expression"
expression : シーケンス型を渡した場合、記述されたタグとその子要素をシーケンスの
各要素ごとに一度ずつ繰り返する。
name : 現在繰り返し処理している要素の値が設定される。

TAL Path式 を使って repeat/name という名前で繰り返し変数の名前にアクセスできる。
また、繰り返し変数には以下のプロパティがあり、 repeat/name/Property でアクセスできる。
index : 繰り返しの回数を 0 から数えた値
number : 繰り返しの回数を 1 から数えた値
even : 繰り返しが偶数回目の場合に真
odd : 繰り返しが奇数回目の場合に真
start : 現在の要素がシーケンスの最初の要素である場合に真
end : 現在の要素がシーケンスの最後の要素である場合に真シーケンスがイテレータ型の場合には必ず偽.
length : シーケンスの長さです.シーケンスがイテレータ型の場合,長さが分からないので,値は maxint になる.
key : シーケンスのキーを返す。

4.tal:content
・記述したタグで囲まれた部分を expression で置き換える
tal:content="[text | structure] expression"
text : 必要に応じてエスケープして出力される
structure : エスケープせずに出力

5.tal:replace
・記述したタグで囲まれた部分をタグも含め expression で置き換える
tal:content="[text | structure] expression"
text : 必要に応じてエスケープして出力される
structure : エスケープせずに出力

6.tal:attributes
・記述したタグの属性を設定する。nothing の場合はその属性を削除する。
default の場合は記述されている属性をそのまま出力する。
「;」区切りで複数記述することができる。属性に「;」が必要な場合「;;」と記述する必要がある。
tal:attributes="name expression[;attributes-expression]"
name : 属性名
expression : 属性の値

7.tal:omit-tag
・タグの消去
tal:omit-tag="expression"
expression : 値が真の場合、記述されたタグのみを除去する。空でも真になる。


8.tal:on-error
・エラー、例外処理
tal:on-error="expression"
パスエラーが発生した場合や、例外を受け取った場合には、タグの中身をexpressionに置き換える。


●METAL(Macro Extension for TAL) namespace について
1.metal:define-macro
・マクロの宣言
metal:define-macro="name"
name : マクロの名

2.metal:use-macro
・マクロの呼び出し
metal:use-macro="expression"
expression : マクロの名 もしくは 「ファイル名/マクロ名」

3.metal:define-slot="name"
・マクロ内の動的内容の指定、fill-slotで指定された要素内を置き換える。
define-macroを持つ要素の中のみ存在可能
metal:define-slot="name"
name : スロット名

4.metal:fill-slot="name"
・マクロ内の動的変更可能要素の指定、define-slotで指定した値に置き換える。
define-macroを持つ要素の中のみ存在可能
metal:fill-slot="name"
name : スロット名


●I18N namespace(国際化) について
1.i18n:translate
2.i18n:name

●PHPTAL namespace
TAL仕様の拡張。PHPTAL専用
1.phptal:debug
2.phptal:tales

●*:block
たくさんのTAL属性を含んでたり、繰り返し使う場合にいいみたい。


●PHPTALES
path:
Conditional statements
string:
php:
not:
exists:
default
structure
Expression chains


●TALES(TAL Expression Syntax)について

TALESの型
path - パスで値を指定する
exists - パスが存在するかテストする
nocall - パスでオブジェクトを指定する
not - 式の否定です
string - 文字列を整形する
組み込みの名前



●Zend Frameworkへの組み込み


TODO
Zend_View_Phptal的なものの作成
テンプレートの拡張子って何がいいんだろ考える
I18N namespace以下のテンプレート側の機能の調査
テンプレート側の機能のExampleを作成。


参考にしたサイト
TAL ガイド
PHPTAL マニュアル