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:用来存放应用相关的数据文件:

data

htdocs:这个是应用的根目录,里面暂时只有一个 index.php 文件。(截图舍去)

include:这里存放主要的库文件:ZF,Smarty…等一些需要“包含”的文件:(PHP 的 include_path 项已经包含了此目录)

include

templates:这里存放模板文件:(暂时只有一个 index 控制器模板目录)

templates

httpd.conf:Apache 的子配置文件。(已经包含进了 Apache 的主文件里,这里不做介绍了)

settings.ini:站点配置文件:

settings

-----------------------应用文件目录信息结束,来看看如何创建 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'}

至此呢,所有的整合工作都已完成,进入应用站点看看是不是显示:

succeed

是的话,就整合成功了!

--------------------------------------------------------------------------以下为附录部分:

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

posted @ 2010-11-01 00:32  无墨来点睛  Views(3361)  Comments(0Edit  收藏  举报