6.6視圖指令碼的變數轉義輸出(escaping output)
視圖指令碼得到變數以後,需要通過轉義進行輸出,變成頁面可以顯示的Html代碼。
輸出語句的格式:
echo $this->escape($this->variable);
$variable變數是在視圖指令碼裡用render方法傳遞過來的。
一般情況下,傳遞的變數是通過PHP的 htmlspecialchars()函數轉義的。而我們也可以實現我們自己的轉義函數。請參考以上“使用回呼函數”樣本。
6.7視圖指令碼的模板系統—操作PHPLib類型的模板
模板系統進一步完美的實現了視圖與程式邏輯的分離。視圖指令碼可以完美的操作PHPLib等類型的模板。
6.7.1PHPlib的安裝和調用
為了測試下面的樣本,我們必須安裝PHPLib模板系統到我們的環境中。從網上下載到phplib-7.4.ZIP安裝壓縮包,解壓到安裝ZEND的library檔案夾下,就完成了安裝。
為了在ZF的視圖指令碼裡調用得到模板類檔案,必須在引導檔案Index.php的set_include_path部分添加PHPLib模板類庫檔案夾phplib-7.4/php到搜尋路徑中。以下樣本同時包含了Smarty模板引擎的類庫檔案的搜尋路徑:
set_include_path('.' .
PATH_SEPARATOR . '../library/'.
PATH_SEPARATOR . '../library/phplib-7.4/php/'.
PATH_SEPARATOR . '../library/Smarty-2.6.19/libs/'.
PATH_SEPARATOR . 'models/'.
PATH_SEPARATOR . get_include_path()
);
注意,所有路徑都是以引導檔案所在檔案夾作為參照的。儘管視圖檔案裡所在檔案夾不是引導檔案所在根目錄,但在視圖檔案裡包含PHPLib類庫檔案的語句include_once 'template.inc';仍然是以引導檔案所在目錄作為參照的。
6.7.2在視圖檔案裡調用PHPLib模板
首先包含PHPLib類庫檔案,然後聲明模板類的一個執行個體。使用模板類,首先需要指定一些屬性,比如指定模板所在路徑,指定模板檔案等,然後用set_var傳遞模板變數,最後用parse方法調用模板檔案。PHPLib模板系統的詳細用法請參考其協助文檔。
樣本:
<?php
include_once 'template.inc';
$tpl = new Template();
$tpl->set_root('views');
if ($this->books)
{
$tpl->set_file(array(
"booklist" => "booklist.tpl",
"eachbook" => "eachbook.tpl",
));
foreach ($this->books as $key => $val)
{
$tpl->set_var('author', $this->escape($val['author']));
$tpl->set_var('title', $this->escape($val['title']));
$tpl->parse("books", "eachbook", true);
}
$tpl->pparse("output", "booklist");
}
else
{
$tpl->setFile("nobooks", "nobooks.tpl");
$tpl->pparse("output", "nobooks");
}
?>
booklist.tpl檔案內容:
<?php
if ($this->books):
?>
<table border=1>
<tr>
<th>作者</th>
<th>書名</th>
</tr>
<?php
foreach ($this->books as $key => $val):
?>
<tr>
<td><?php echo $this->escape($val['author']) ?></td>
<td><?php echo $this->escape($val['title']) ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php
else:
?>
<p>There are no books to display.</p>
<?php
endif;
eachbook.tpl檔案內容:
<!-- eachbook.tpl -->
<tr>
<td>{author}</td>
<td>{title}</td>
</tr>
6.8視圖指令碼的模板系統—使用 Zend_View_Interface調用第三方模板引擎
我們還可以通過實現Zend_View_Interface介面,來得到一個可用的模板系統。
ZF對Zend_View_Interface介面的原始定義:
/** Return the actual template engine object */
public function getEngine();
/* Set the path to view scripts/templates */
public function setScriptPath($path);
/* Set a base path to all view resources */
public function setBasePath($path, $prefix = 'Zend_View');
/* Add an additional base path to view resources */
public function addBasePath($path, $prefix = 'Zend_View');
/* Retrieve the current script paths */
public function getScriptPaths();
/* Overloading methods for assigning template variables as object properties */
public function __set($key, $value);
public function __get($key);
public function __isset($key);
public function __unset($key);
/* Manual assignment of template variables, or ability to assign multiple
variables en masse.*/
public function assign($spec, $value = null);
/* Unset all assigned template variables */
public function clearVars();
/* Render the template named $name */
public function render($name);
使用該介面,我們可以很容易的把第三方的模板引擎,比如Smarty,封裝成Zend_View相容的模板類。
6.8.1Smarty的安裝
下載Smarty軟體包,解壓到ZEND的library檔案夾下,就完成了安裝。
為了在ZF的視圖指令碼裡調用得到模板類檔案,必須在引導檔案Index.php的set_include_path部分添加Smarty模板類庫檔案夾Smarty-2.6.19/libs到搜尋路徑中,參看前面PHPlib的安裝說明部分。
Smarty模板引擎需要建立template_dir和compile_dir檔案夾才能工作。ZF手冊裡的樣本因為缺少這些設定而無法運行,正確的程式碼片段如下:
public function setScriptPath($path)
{
if (is_readable($path))
{
$this->_smarty->template_dir = $path;
$this->_smarty->compile_dir = $path; //必須加語句:設定編譯路徑
$this->_smarty->cache_dir = $path; //設定緩衝路徑
return;
}
……
我們把對Zend_View_Interface介面的實現的類,放在models檔案夾下的ZendViewSmarty.php檔案中,該檔案的內容如下:
<?php
require_once 'Zend/View/Interface.php';
require_once 'Smarty.class.php';
class ZendViewSmarty implements Zend_View_Interface
{
/**
* Smarty object
* @var Smarty
*/
protected $_smarty;
/**
* Constructor
* @param string $tmplPath
* @param array $extraParams
* @return void
*/
public function __construct($tmplPath = null, $extraParams = array())
{
$this->_smarty = new Smarty;
if (null !== $tmplPath) {
$this->setScriptPath($tmplPath);
}
foreach ($extraParams as $key => $value) {
$this->_smarty->$key = $value;
}
}
/**
* Return the template engine object
* @return Smarty
*/
public function getEngine()
{
return $this->_smarty;
}
/**
* Set the path to the templates
* @param string $path The directory to set as the path.
* @return void
*/
public function setScriptPath($path)
{
if (is_readable($path)) {
$this->_smarty->template_dir = $path;
$this->_smarty->compile_dir = $path;
$this->_smarty->cache_dir = $path;
return;
}
throw new Exception('Invalid path provided');
}
/**
* Retrieve the current template directory
* @return string
*/
public function getScriptPaths()
{
return array($this->_smarty->template_dir);
}
/**
* Alias for setScriptPath
* @param string $path
* @param string $prefix Unused
* @return void
*/
public function setBasePath($path, $prefix = 'Zend_View')
{
return $this->setScriptPath($path);
}
/**
* Alias for setScriptPath
* @param string $path
* @param string $prefix Unused
* @return void
*/
public function addBasePath($path, $prefix = 'Zend_View')
{
return $this->setScriptPath($path);
}
/**
* Assign a variable to the template
* @param string $key The variable name.
* @param mixed $val The variable value.
* @return void
*/
public function __set($key, $val)
{
$this->_smarty->assign($key, $val);
}
/**
* Retrieve an assigned variable
* @param string $key The variable name.
* @return mixed The variable value.
*/
public function __get($key)
{
return $this->_smarty->get_template_vars($key);
}
/**
* Allows testing with empty() and isset() to work
* @param string $key
* @return boolean
*/
public function __isset($key)
{
return (null !== $this->_smarty->get_template_vars($key));
}
/**
* Allows unset() on object properties to work
* @param string $key
* @return void
*/
public function __unset($key)
{
$this->_smarty->clear_assign($key);
}
/**
* Assign variables to the template
* Allows setting a specific key to the specified value, OR passing an array
* of key => value pairs to set en masse.
* @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)
{
if (is_array($spec)) {
$this->_smarty->assign($spec);
return;
}
$this->_smarty->assign($spec, $value);
}
/**
* 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->_smarty->clear_all_assign();
}
/**
* Processes a template and returns the output.
* @param string $name The template to process.
* @return string The output.
*/
public function render($name)
{
return $this->_smarty->fetch($name);
}
}
?>
控制指令碼中對我們我的模板類的調用代碼:
function smartyAction()
{
$view = new ZendViewSmarty(); //執行個體化新的模板類
$view->setScriptPath('views'); //設定模板檔案路徑
$view->book = 'Enter Zend Framework Programme'; //傳遞變數給模板引擎
$view->author = '張慶(網眼)';
echo $view->render('bookinfo.tpl'); //視圖呈現
}
我們看到,由於Smarty模板引擎的良好特性,除過實現上述介面的代碼比較複雜以外,我們這裡的控制碼要比應用PHPLib模板簡單得多。我們的資料不必像PHPLib引擎那樣,要把資料傳給視圖指令碼,再由視圖指令碼聲明PHPLib類,再把資料發送給模板去呈現。這裡是在控制指令碼裡把資料直接傳遞給Smarty模板去呈現的。這是因為ZendViewSmarty實現的是Zend_View介面,它和Zend_View的用法是一樣的。
注意:本例只是使用Smarty引擎的其中一種方法。在ZF中還可以用別的形式來使用Smarty模板引擎,我們會在別的章節裡介紹。