Zend Framework 整合 Smarty 模板引擎(ZF Study)
<文章大部分内容取自《PHP Web 2.0 》这本书>,最近在学习这本书 ^ ^
在使用 Zend Framework(以下简称 ZF) 框架的时候,其中的 Zend_Controller 会自动加载一个名为 ViewRenderer 的插件,它会根据所请求的控制器和动作名来显示一个视图脚本(即模板),也就是说,使用 Smarty 的时候,不用实例化 Smarty 类或者调用 display() 方法来输出模板,因为 ViewRenderer 会为我们做这些工作。
要想让 Zend 与 Smarty 交互,我们必须扩展 Zend_View_Abstract 类从而达到我们的目的,可以创建一个 Templater 的类,之后就要在 index.php 引导文件中告诉 Zend_Controller 这个类的信息。
先来看看应用的文件目录信息:
来简要的介绍一下:
data:用来存放应用相关的数据文件:
htdocs:这个是应用的根目录,里面暂时只有一个 index.php 文件。(截图舍去)
include:这里存放主要的库文件:ZF,Smarty…等一些需要“包含”的文件:(PHP 的 include_path 项已经包含了此目录)
templates:这里存放模板文件:(暂时只有一个 index 控制器模板目录)
httpd.conf:Apache 的子配置文件。(已经包含进了 Apache 的主文件里,这里不做介绍了)
settings.ini:站点配置文件:
-----------------------应用文件目录信息结束,来看看如何创建 Templater 类呢?
我们将把这个类放入应用的 include/ 文件夹中,看一下第三个截图中的 Templater.php,这就是我们将要创建的类文件。另外呢,我们还要在 include/Templater/ 文件夹中创建一个 plugins/ 的目录,就像这样:include/Templater/plugins/ ,这个目录可以用来存放所有定制 Smarty 插件,通过将我们自己的所有扩展插件存放在一个单独的目录中,可以很容易地升级到 Smarty 的最新版本,而不必总是跟踪我们的哪些文件需要移动。
现在可以着手创建 Templater.php 了,在其中指定 Smarty 的 template_dir(模板路径)和 compile_dir(编译路径),还要告诉 Smarty ,除去自己的 plugins 目录外,还可以在 include/Templater/plugins/ 中寻找插件。
要实现这个类,必须实现一些关键的方法,使得 ViewRenderer 能够与 Smarty 交互,其中最重要的方法如下:
> getEngine()。此方法必须返回 Smarty 的一个实例。由于这个方法可能被调用多次,所以应当将 Smarty 实例缓存起来,这样就只需创建一次实例。为此,将在构造函数中创建 Smarty 对象; > __set()。此方法将一个变量赋给模板。实际上,这意味着可以在任何控制器动作中将 $smarty->assign('foo', 'bar') 替换为 $this->view->foo = 'bar'。 > __get()。此方法返回一个先前赋给模板的变量。 > render()。此方法显示一个模板。它的效果与调用 $smarty->display 类似,只不过这个方法要返回输出(而不会直接显示),故必须在 Smarty 对象上使用 fetch() 而不是 display()。
下面的代码则展示了 Templater.php 的代码,注意要与 Zend 框架的类命名结构相一致,这也意味着必须将这个类放在 include/ 目录中。
Templater.php:
<?php class Templater extends Zend_View_Abstract { protected $_path; protected $_engine; public function __construct() { $config = Zend_Registry::get('config'); require_once('Smarty/Smarty.class.php'); $this->_engine = new Smarty(); $this->_engine->template_dir = $config->paths->templates; $this->_engine->compile_dir = sprintf('%s/tmp/templates_c', $config->paths->data); $this->_engine->plugins_dir = array($config->paths->base . '/include/Templater/plugins', 'plugins'); } public function getEngine() { return $this->_engine; } public function __set($key, $val) { $this->_engine->assign($key, $val); } public function __get($key) { return $this->_engine->get_template_vars($key); } public function __isset($key) { return $this->_engine->get_template_vars($key) !== null; } public function __unset($key) { $this->_engine->clear_assign($key); } public function assign($spec, $value = null) { if (is_array($spec)) { $this->_engine->assign($spec); return; } $this->_engine->assign($spec, $value); } public function clearVars() { $this->_engine->clear_all_assign(); } public function render($name) { return $this->_engine->fetch(strtolower($name)); } public function _run() { } } ?>
好了,我们的 Templater 类已经完成了,怎样来使用呢?我们需要让 Zend_Controller 使用 Templater 类,而不是默认的 Zend_View 类。为此,我们必须要将下面的代码加入到应用的引导文件(index.php)中:
// setup the view renderer $vr = new Zend_Controller_Action_Helper_ViewRenderer(); $vr->setView(new Templater()); $vr->setViewSuffix('tpl'); Zend_Controller_Action_HelperBroker::addHelper($vr);
(关于这里的 ZF 知识,请看文章最下方的 ViewRenderer 介绍)
注意,必须要调用 setViewSuffix() 来指示模板以文件扩展名 .tpl (或者 .htm …)结尾,默认地,Zend_View 使用 .phtml ,来看看我们现在的 bootstrap(引导文件 htdocs/index.php,即应用的引导文件):
index.php:
<?php /*Old: require_once('Zend/Loader.php'); Zend_Loader::registerAutoload(); */
/*ZF 的自动加载机制*/ require_once('Zend/Loader/Autoloader.php'); $autoloader = Zend_Loader_Autoloader::getInstance(); $autoloader->setFallbackAutoloader(true); // load the application configuration(导入应用的配置文件) $config = new Zend_Config_Ini('../settings.ini', 'development'); Zend_Registry::set('config', $config); // create the application logger(加载 ZF 的日志机制) $logger = new Zend_Log(new Zend_Log_Writer_Stream($config->logging->file)); Zend_Registry::set('logger', $logger); // connect to the database(数据库配置及连接) $params = array('host' => $config->database->hostname, 'username' => $config->database->username, 'password' => $config->database->password, 'dbname' => $config->database->database); $db = Zend_Db::factory($config->database->type, $params); Zend_Registry::set('db', $db); // handle the user request(处理用户请求) $controller = Zend_Controller_Front::getInstance(); $controller->setControllerDirectory($config->paths->base . '/include/Controllers'); // setup the view renderer(这里是我们新加的,用来处理 ViewRenderer) $vr = new Zend_Controller_Action_Helper_ViewRenderer(); $vr->setView(new Templater()); $vr->setViewSuffix('tpl'); Zend_Controller_Action_HelperBroker::addHelper($vr); $controller->dispatch(); ?>
现在,一旦执行一个控制器动作,Zend_Controller 就会根据控制器名和动作名自动查找模板。下面使用 index 控制器的 index 动作作为一个简单的测试例子:
在我们的 include/Controllers/ (用来存放各种控制器)目录中的:IndexController.php:
IndexController.php:
<?php class IndexController extends CustomControllerAction { public function indexAction() { } } ?>
注意:CustomControllerAction 类:
CustomControllerAction.php:
<?php class CustomControllerAction extends Zend_Controller_Action { public $db; function init() { $this->db = Zend_Registry::get('db'); } } ?>
相应的 index 控制器的 index 动作的模板:templates/index/index.tpl:
index.tpl:
{include file='header.tpl'} Web site home {include file='footer.tpl'}
至此呢,所有的整合工作都已完成,进入应用站点看看是不是显示:
是的话,就整合成功了!
--------------------------------------------------------------------------以下为附录部分:
ViewRenderer 介绍:
视图解析 (ViewRenderer
) 助手为实现下列目标设计:
-
不需要在控制器内创建视图对象实例;视图对象将在控制器内自动注册。
-
根据当前的模块自动地设置视图脚本、助手、过滤器路径。指派当前的模块名为助手和过滤器类的类名前缀。
-
为所有分发的控制器和动作创建全局有效的视图对象。
-
允许开发人员为所有控制器设置默认的视图解析选项。
-
加入无需干预自动解析试图脚本的功能。
-
允许开发人员为视图基路径和视图脚本路径创建自己的规范。
注意
如果手动执行_forward()
、redirect
、或者render
时,不会发生自动解析。因为执行这些动作时,等于告诉 ViewRenderer
,你要自己确定输出结果。
ViewRenderer
助手默认启用。你可以通过前端控制器的 noViewRenderer
方法、设定参数 ($front->setParam('noViewRenderer', true)
) 或者从助手经纪人栈 (helper broker stack) 中移除助手 (Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer')
) 等方式禁用该助手。
创建实例并注册自己的 ViewRenderer
对象,然后传入到助手经纪人:
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer(); $viewRenderer->setView($view) ->setViewSuffix('php'); Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
通过助手经纪人即时的初始化并/或获取ViewRenderer
对象:
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); $viewRenderer->setView($view) ->setViewSuffix('php');
更多相关的资料可以查看 ZF 的在线 Manual(手册):http://framework.zend.com/manual/zh/zend.controller.html