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に変えたものでテンプレートにアクセスするので、各アクション毎に
テンプレートファイルを用意し設置する。