7.8. 动作助手

7.8.1. 介绍

动作助手可以向任何Zend_Controller_Action的衍生动作控制器中,即时的加入功能(runtime and/or on-demand functionality),以使得增加公共的动作控制器功能时,尽量减少衍生动作控制器类的必要。

动作助手有多种使用方式。动作助手使用了一套经纪系统(brokerage system),与Zend_View_Helpers中使用的,也就是Zend_Controller_Plugin的经纪系统类似。动作助手在需要调用时加载,可以在请求的时候(bootstrap)或者动作控制器创建的时候(init())实例化。要充分了解这些细节,请阅读下面的章节。

7.8.2. 初始化助手

根据需求以及助手的功能,可有几种不同的初始化方式。

助手经纪人(broker)存储在Zend_Controller_Action$_helper成员中,可以使用经纪人来获取或者调用助手。以下是操作方法:

  • 显式的调用getHelper()方法。简单的传入助手名字,就可以返回助手对象。

    
    <?php
    $flashMessenger 
    $this->_helper->getHelper('FlashMessenger');
    $flashMessenger->addMessage('We did something in the last request');
  • 使用助手经纪人的__get()方法,就像获取经纪人的成员属性一样获取助手。

    
    <?php
    $flashMessenger 
    $this->_helper->FlashMessenger;
    $flashMessenger->addMessage('We did something in the last request');
  • 最后,大部分动作助手实现了direct()方法,它将调用助手的一个特定的,默认的方法。以FlashMessenger为例,它调用了方法addMessage()

    
    <?php
    $this
    ->_helper->FlashMessenger('We did something in the last request');
[注意] 注意

上面的例子在功能上是等价的。

也可以显式的实例化助手。如果你要在动作控制器之外使用助手,或者给助手经纪人传入一个助手供所有的动作使用,你可能希望直接这么做。实例化助手和实例化其他PHP类的方法一样。

7.8.3. 助手经纪人

Zend_Controller_Action_HelperBroker处理注册助手对象和助手路径,即时的获取助手等细节。

使用addHelper来注册助手:


<?php
Zend_Controller_Action_HelperBroker
::addHelper($helper);

实例化助手并传入经纪人有点耗费时间和资源,不过addPrefix()addPath()两个方法能够很容易的自动完成这些工作:

  • addPrefix()方法带有一个类前缀参数,用来加入自定义助手类的路径。它假定前缀遵循Zend Framework的类命名惯例。

    
    <?php
    // Add helpers prefixed with My_Action_Helpers in My/Action/Helpers/
    Zend_Controller_Action_HelperBroker::addPrefix('My_Action_Helpers');
  • addPath()方法第一个参数为一个目录,第二个为类前缀(默认为'Zend_Controller_Action_Helper')。用来将自己的类前缀映射到指定的目录。

    
    <?php
    // Add helpers prefixed with Helper in Plugins/Helpers/
    Zend_Controller_Action_HelperBroker::addPath('./Plugins/Helpers''Helper');

这些方法是静态的,因而可以根据需要在控制器链中的任何位置调用动态的加载助手。

使用hasHelper($name)方法来判定助手经纪人中是否存在某助手,$name是助手的短名称(去掉前缀的):


<?php
// Check if 'redirector' helper is registered with the broker:
if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
    echo 
'Redirector helper registered';
}

最后,使用removeHelper($name)来删除助手经纪人中的某个助手,$name是助手的短名称。


<?php
// Conditionally remove the 'redirector' helper from the broker:
if (Zend_Controller_Action_HelperBroker::hasHelper('redirector')) {
    
Zend_Controller_Action_HelperBroker::removeHelper('redirector')
}

7.8.4. 内建的动作助手

Zend Framework默认包含三个动作助手:FlashMessenger用来处理Flash Messenger会话; Redirector提供另一种实现方式,帮助程序重定向到内部或者外部页面;ViewRenderer自动的完成在控制器内建立视图对象并渲染视图的过程。

7.8.4.1. FlashMessenger

7.8.4.1.1. 简介

FlashMessenger助手允许你传递用户可能需要在下个请求看到的消息。为实现它,FlashMessenger使用Zend_Session_Namespace来存储消息以备将来或下个请求来读取。如果你计划使用Zend_Session或者Zend_Session_Namespace,在引导文件里用Zend_Session::start()初始化,的确是个好主意。(参见Zend_Session文档有更多的关于它的用法的细节。)

7.8.4.1.2. Basic Usage Example

下面的例子展示flash messenger最基本的用法。当动作/some/my 被调用,它添加flash message "Record Saved!",随后的对动作/some/my-next-request的请求将读取它(并也这样删除它)。


<?php
class SomeController extends Zend_Controller_Action
{
    
/**
     * FlashMessenger
     *
     * @var Zend_Controller_Action_Helper_FlashMessenger
     */
    
protected $_flashMessenger null;

    public function 
init()
    {
        
$this->_flashMessenger $this->_helper->getHelper('FlashMessenger');
        
$this->initView();
    }

    public function 
myAction()
    {
        
/**
         * default method of getting Zend_Controller_Action_Helper_FlashMessenger
         * instance on-demand
         */
        
$this->_flashMessenger->addMessage('Record Saved!');
    }

    public function 
myNextRequestAction()
    {
        
$this->view->messages $this->_flashMessenger->getMessages();
        
$this->render();
    }
}

7.8.4.2. 转向器(Redirector)

7.8.4.2.1. 介绍

转向器(Redirector)助手允许使用一个转向器对象帮助程序重定向到新的URL。与_redirect()方法相比,它具有多项优势。例如能够在转向器对象中预先配置整个站点的行为,或者使用与Zend_Controller_Action::_forward()相似的goto($action, $controller, $module, $params)接口。

转向器拥有影响重定向行为的大量方法:

  • setCode() 设置重定向过程中使用的HTTP响应码。

  • setExit() 在重定向后强制执行exit()方法。默认已设定。

  • setGoto()设置默认的URL,当没有提供参数给goto()方法时转向该URL。可以使用类似Zend_Controller_Action::_forward()的API:setgoto($action, $controller = null, $module = null, array $params = array());

  • setGotoRoute()设置基于一个注册路由器的URL。通过传入一个键/值数组和一个路由器名,它将根据路由器的类型和定义来组织URL。

  • setGotoUrl()设置默认的URL,当没有参数传入gotoUrl(),将使用该URL。接受单个URL字符串。

  • setPrependBase()setGotoUrl()gotoUrl()或者gotoUrlAndExit()指定的URL前面,加入请求对象的基地址(base URL)。

  • setUseAbsoluteUri()强制转向器在重定向时使用绝对的URI。当该选项设定后,将使用$_SERVER['HTTP_HOST']$_SERVER['SERVER_PORT']$_SERVER['HTTPS']以及重定向方法指定的URL,来形成一个完整的URI。该选项目前默认关闭,将来的版本可能会默认开启。

此外,转向器中还有大量方法来执行实际的重定向。

  • goto()使用setGoto()(类似_forward()的API)来构建URL并执行重定向。

  • gotoRoute()使用setGotoRoute()(路由组装route-assembly)来构建URL并执行重定向。

  • gotoUrl()使用setGotoUrl() URL字符串)来构造URL并执行重定向。

最后,你可以在任何时刻使用getRedirectUrl()确定当前的重定向URL。

7.8.4.2.2. 基础用例

例 7.2. 设定选项

这个例子改变了几个选项,包括设定重定向时使用的HTTP状态码为303,重定向时不默认退出,以及定义了默认的URL供重定向使用。


<?php
class SomeController extends Zend_Controller_Action
{
    
/**
     * Redirector - defined for code completion
     *
     * @var Zend_Controller_Action_Helper_Redirector
     */
    
protected $_redirector null;

    public function 
init()
    {
        
$this->_redirector $this->_helper->getHelper('Redirector');

        
// Set the default options for the redirector
        // Since the object is registered in the helper broker, these become
        // relevant for all actions from this point forward
        
$this->_redirector->setCode('303')
                          ->
setExit(false)
                          ->
setGoto("this-action""some-controller");
    }

    public function 
myAction()
    {
        
/* do some stuff */

        // Redirect to a previously registered URL, and force an exit to occur
        // when done:
        
$this->_redirector->redirectAndExit();
        return; 
// never reached
    
}
}

例 7.3. 使用默认设定

这个例子假定使用默认设定,也就意味着任何重定向将导致立即退出。


<?php
// ALTERNATIVE EXAMPLE
class AlternativeController extends Zend_Controller_Action
{
    
/**
     * Redirector - defined for code completion
     *
     * @var Zend_Controller_Action_Helper_Redirector
     */
    
protected $_redirector null;

    public function 
init()
    {
        
$this->_redirector $this->_helper->getHelper('Redirector');
    }

    public function 
myAction()
    {
        
/* do some stuff */

        
$this->_redirector->gotoUrl('/my-controller/my-action/param1/test/param2/test2');
        return; 
// never reached since default is to goto and exit
    
}
}

例 7.4. 使用goto()_forward()API

goto()'s API 模拟了Zend_Controller_Action::_forward()。主要的不同在于它通过传入的参数构造URL,使用默认路由器的默认格式:module/:controller/:action/*。然后重定向而不是继续动作链循环。


<?php
class ForwardController extends Zend_Controller_Action
{
    
/**
     * Redirector - defined for code completion
     *
     * @var Zend_Controller_Action_Helper_Redirector
     */
    
protected $_redirector null;

    public function 
init()
    {
        
$this->_redirector $this->_helper->getHelper('Redirector');
    }

    public function 
myAction()
    {
        
/* do some stuff */

        // Redirect to 'my-action' of 'my-controller' in the current module,
        // using the params param1 => test and param2 => test2
        
$this->_redirector->goto('my-action''my-controller'null, array('param1' => 'test''param2' => 'test2'));
    }
}

例 7.5. 通过gotoRout()使用路由组装(route assembly)

下面的例子使用了路由器assemble()方法,基于传入参数的关联数组来创建URL。假定下面的路由已经注册:


<?php
$route 
= new Zend_Controller_Router_Route(
    
'blog/:year/:month/:day/:id',
    array(
'controller' => 'archive''module' => 'blog''action' => 'view')
);
$router->addRoute('blogArchive'$route);

给定一个数组,其中年份为2006,月份为4,日期为24,id为42,据此可以组装URL/blog/2006/4/24/42


<?php
class BlogAdminController extends Zend_Controller_Action
{
    
/**
     * Redirector - defined for code completion
     *
     * @var Zend_Controller_Action_Helper_Redirector
     */
    
protected $_redirector null;

    public function 
init()
    {
        
$this->_redirector $this->_helper->getHelper('Redirector');
    }

    public function 
returnAction()
    {
        
/* do some stuff */

        // Redirect to blog archive. Builds the following URL:
        // /blog/2006/4/24/42
        
$this->_redirector->gotoRoute(
            array(
'year' => 2006'month' => 4'day' => 24'id' => 42),
            
'blogArchive'
        
);
    }
}

7.8.4.3. ViewRenderer

7.8.4.3.1. 介绍

视图渲染(ViewRenderer)助手为实现下列目标设计:

  • 不需要在控制器内创建视图对象实例;视图对象将在控制器内自动注册。

  • 根据当前的模块自动地设置视图脚本、助手、过滤器路径。指派当前的模块名为助手和过滤器类的类名前缀。

  • 为所有分发的控制器和动作创建全局有效的视图对象。

  • 允许开发人员为所有控制器设置默认的视图渲染选项。

  • 加入无需干预自动渲染试图脚本的功能。

  • 允许开发人员为视图基路径和视图脚本路径创建自己的规范。

[注意] 注意

如果手动执行_forward()redirect、或者render时,不会发生自动渲染。因为执行这些动作时,等于告诉ViewRenderer,你要自己确定输出结果。

[注意] 注意

ViewRenderer助手默认启用。你可以通过前端控制器的noViewRenderer方法、设定参数($front->setParam('noViewRenderer', true))或者从助手经纪人栈(helper broker stack)中移除助手(Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer'))等方式禁用该助手。

如希望在分发前端控制器前修改ViewRenderer设定,可采用下面的两种方法:

  • 创建实例并注册自己的ViewRenderer对象,然后传入到助手经纪人。

    
    <?php
    $viewRenderer 
    = new Zend_Controller_Action_Helper_ViewRenderer();
    $viewRenderer->setView($view)
                 ->
    setViewSuffix('php');
    Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
  • 通过助手经纪人即时的初始化并/或获取ViewRenderer对象。

    
    <?php
    $viewRenderer 
    Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    $viewRenderer->setView($view)
                 ->
    setViewSuffix('php');
7.8.4.3.2. API

大多数使用中,只需要简单的创建 ViewRenderer对象,然后传入到动作助手经纪人。创建实例并注册的最简单方式是使用助手经纪人的getStaticHelper()方法:


<?php
Zend_Controller_Action_HelperBroker
::getStaticHelper('viewRenderer');

动作控制器第一次实例化时,会触发ViewRenderer创建一个视图对象。动作控制器每次实例化都会调用ViewRendererinit()方法,设定动作控制器的视图属性,并以相对于当前模块的路径为参数调用addScriptPath()方法;调用时带有以当前模块命名的类前缀参数,该参数对为该模块定义的所有助手和过滤器类都有效。(this will be called with a class prefix named after the current module, effectively namespacing all helper and filter classes you define for the module. )

每次执行postDispatch()方法,它将为当前动作执行render()方法。

例如这个类:


<?php
// A controller class, foo module:
class Foo_BarController extends Zend_Controller_Action
{
    
// Render bar/index.phtml by default; no action required
    
public function indexAction()
    {
    }

    
// Render bar/populate.phtml with variable 'foo' set to 'bar'.
    // Since view object defined at preDispatch(), it's already available.
    
public function populateAction()
    {
        
$this->view->foo 'bar';
    }
}

...

// in one of your view scripts:
<?php $this->foo(); // call Foo_View_Helper_Foo::foo()

ViewRenderer也定义了大量的访问器用来设定和获取视图选项。

  • setView($view)可以为ViewRenderer设定视图对象。以公共类属性$view获取设定值。

  • setNeverRender($flag = true)可以全局的启用或禁用自动渲染,也就是对所有控制器都有效。如果设定为true,在所有控制器器内,postDispatch()将不会自动调用render()getNeverRender()返回当前的设定值。

  • setNoRender($flag = true) 用来启用或禁用自动渲染,如果设置为true,在当前控制器内,postDispatch()不会调用render()方法。这个设定在preDispatch()每次执行时会被重置。getNoRender()返回当前的设定值。

  • setNoController($flag = true)通知render()不要再到以控制器命名的子目录中寻找视图脚本。getNoController()返回当前值。

  • setNeverController($flag = true)setNoController($flag = true)相似,但是其在全局范围内有效——也就是说,它不会在每次分发动作时重置。getNeverController()返回当前值。

  • setScriptAction($name)用来指定渲染的视图脚本。$name是脚本的名字去掉后缀(不带控制器子目录,除非noController已开启)。如果没有指定,它将寻找以请求对象中的动作命名的视图脚本。getScriptAction()返回当前值。

  • setResponseSegment($name)用来指定渲染到响应对象中的哪个命名片段。如果没有指定,渲染到默认片断。getResponseSegment()返回当前值。

  • initView($path, $prefix, $options可以指定视图的基路径,为助手和过滤器脚本设置类前缀,设定ViewRenderer选项。可以传入以下任意的标志:neverRendernoRendernoControllerscriptAction,和responseSegment

  • setRender($action = null, $name = null, $noController = false)可以一次设定scriptActionresponseSegmentnoControllerdirect()是它的别名,使得控制器中可以方便的调用。

    
    // Render 'foo' instead of current action script
    $this->_helper->viewRenderer('foo');

    // render form.phtml to the 'html' response segment, without using a
    // controller view script subdirectory:
    $this->_helper->viewRenderer('form', 'html', true);
    [注意] 注意

    setRender()direct()并不会实际渲染视图脚本,而是提示postDispatch()postDispatch()渲染视图。

构造函数允许可选的传入参数视图对象和ViewRenderer选项,接受与initView()一样的标志(flags):


$view    = new Zend_View(array('encoding' => 'UTF-8'));
$options = array('noController' => true, 'neverRender' => true);
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view, $options);

还有几个额外的方法用来定制路径规则,供确定视图基路径来增加视图对象,确定视图脚本路径查找并渲染视图脚本时使用。这些方法每个都带有下面一个或更多的占位符(placehodlers)。

  • :moduleDir 引用当前模块的基目录(常规的是模块的控制器目录的父目录)。

  • :module 引用当前的模块名。

  • :controller 引用当前的控制器名。

  • :action引用当前的模块名。

  • :suffix 引用当前的视图脚本后缀(可以通过setViewSuffix()来设置)。

控制器路径规则有关的方法:

  • setViewBasePathSpec($spec)可以改变确定加入到视图对象的基路径的路径规则。默认规则是:moduleDir/views。任何时候都可以使用getViewBasePathSpec()获取当前的规则。

  • setViewScriptPathSpec($spec)允许改变确定到达单独的视图脚本路径(去除试图脚本基路径)的路径规则。默认的路径规则是 :controller/:action.:suffix。任何时候都可以通过getViewScriptPathSpec()获取当前规则。

  • setViewScriptPathNoControllerSpec($spec)允许改变 noController有效时确定到达单独的视图脚本路径(去除试图脚本基路径)的路径规则。默认的规则是:action.:suffix,任何时候都可以通过getViewScriptPathNoControllerSpec()获取当前规则。

ViewRenderer API中的最后一项是关于实际确定视图脚本路径和渲染视图的。包括:

  • renderScript($script, $name)允许渲染指定路径的脚本,可选的命名的路径片段。(renderScript($script, $name) allows you to render a script with a path you specify, optionally to a named path segment. )使用该方法时,ViewRenderer不会自动的确定脚本名称,而是直接的向视图对象的render()传入$script参数。

    [注意] 注意

    当视图已经被渲染到响应对象,将会设置noRender阻止相同的脚本被多次渲染。

    [注意] 注意

    默认的,Zend_Controller_Action::renderScript()代理ViewRendererrenderScript()方法。

  • getViewScript($action, $vars)基于传入的动作和/或$vars中的变量创建到视图脚本的路径。该数组中的键可以包含所有的路径指定键('moduleDir','module', 'controller', 'action', and 'suffix')。传入的任何变量都会优先使用,否则利用基于当前请求的值。

    getViewScript()根据noController标志的设定值使用viewScriptPathSpec或者viewScriptPathNoControllerSpec

    模块、控制器以及动作中的单词定界符将后替换成短线('-')。因此,控制器名称'foo.bar'和动作'baz:bat'按照默认的路径规则将会得到视图脚本路径'foo-bar/baz-bat.phtml'。

    [注意] 注意

    默认的,Zend_Controller_Action::getViewScript()代理ViewRenderergetViewScript()方法。

  • render($action, $name, $noController)首先检查$name$noController参数是否传入,如果传入,则在ViewRenderer中设定相应的标志(分别是响应片段和noController)。然后传入$action参数到getViewScript(),最后传入计算的试图脚本路径到renderScript()

    [注意] 注意

    注意使用render()的边际效应:传入的响应片段名称和noController标志在视图对象中存留。此外渲染结束后noRender会被设置。

    [注意] 注意

    默认的,Zend_Controller_Action::render()代理 ViewRendererrender()方法。

  • renderBySpec($action, $vars, $name)允许传入路径规则变量以确定创建的视图脚本路径。它把$action$vars传入到getScriptPath(),将脚本路径结果和$name传入到renderScript()

7.8.4.3.3. 基础用法示例

例 7.6. 基本用法

大多数基础使用中,只需在bootstrap中使用助手经纪人简单的初始化和注册ViewRenderer 助手,然后在动作方法中设置变量。


<?php
// In your bootstrap:
Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

...

<?
php
// 'foo' module, 'bar' controller:
class Foo_BarController extends Zend_Controller_Action
{
    
// Render bar/index.phtml by default; no action required
    
public function indexAction()
    {
    }

    
// Render bar/populate.phtml with variable 'foo' set to 'bar'.
    // Since view object defined at preDispatch(), it's already available.
    
public function populateAction()
    {
        
$this->view->foo 'bar';
    }

    
// Renders nothing as it forwards to another action; the new action
    // will perform any rendering
    
public function bazAction()
    {
        
$this->_forward('index');
    }

    
// Renders nothing as it redirects to another location
    
public function batAction()
    {
        
$this->_redirect('/index');
    }
}

[注意] 命名规则:控制器和动作名中的单词定界符

如果控制器或者动作名称由几个单词组成,分发器要求在URL中使用特定的路径和单词定界符分隔。ViewRenderer创建路径时将控制器名称中的任何路径定界符替换成实际的路径定界符('/'),任何单词定界符替换成短线('-')。对动作/foo.bar/baz.bat的调用将分发到FooBarController.php中的FooBarController::bazBatAction(),然后渲染foo-bar/baz-bat.phtml;对动作/bar_baz/baz-bat的调用将分发到Bar/BazController.php中的Bar_BazController::bazBatAction(),并渲染bar/baz/baz-bat.phtml

注意到在第二个例子中,模块依然是默认的模块,但由于路径分隔符的存在,控制器的接收到的名字为Bar_BazController,该类在文件Bar/BazController.php中。ViewRenderer模拟了控制器的目录分层。

例 7.7. 禁用自动渲染

对于某些动作和控制器,可能希望关闭自动渲染——例如,如果想发送其他类型的输出(XML,JSON等),或者更简单的不想发送任何东西。有两个选项:关闭所有的自动渲染(setNeverRender()),或者仅仅关闭当前动作的自动渲染(setNoRender())。


<?php
// Baz controller class, bar module:
class Bar_BazController extends Zend_Controller_Action
{
    public function 
fooAction()
    {
        
// Don't auto render this action
        
$this->_helper->viewRenderer->setNoRender();
    }
}

// Bat controller class, bar module:
class Bar_BatController extends Zend_Controller_Action
{
    public function 
preDispatch()
    {
        
// Never auto render this controller's actions
        
$this->_helper->viewRenderer->setNoRender();
    }
}

[注意] 注意

大多数情况下,全局的关闭自动渲染(setNeverRender())没有意义,因为这样ViewRenderer做的唯一件事只是自动设置了视图对象。

例 7.8. 选择另外的视图脚本

有些情况下需要渲染另一个脚本而非以动作命名的脚本。例如,如果你有一个控制器包含增加和编辑两个动作,它们可能都显示相同的'form'视图,尽管拥有不同的值集合(value set)。只需要使用setScriptAction()或者setRender()简单的改变脚本的名称,或者以成员方法的形式调用助手,它将调用setRender()


<?php
// Bar controller class, foo module:
class Foo_BarController extends Zend_Controller_Action
{
    public function 
addAction()
    {
        
// Render 'bar/form.phtml' instead of 'bar/add.phtml'
        
$this->_helper->viewRenderer('form');
    }

    public function 
editAction()
    {
        
// Render 'bar/form.phtml' instead of 'bar/edit.phtml'
        
$this->_helper->viewRenderer->setScriptAction('form');
    }

    public function 
processAction()
    {
        
// do some validation...
        
if (!$valid) {
            
// Render 'bar/form.phtml' instead of 'bar/process.phtml'
            
$this->_helper->viewRenderer->setRender('form');
            return;
        }

        
// otherwise continue processing...
    
}

}

例 7.9. 修改注册的视图Modifying the registered view

如果需要修改视图对象怎么办——例如改变助手路径或者编码?可以在控制器中修改视图对象设定,或者从ViewRenderer中抓取视图对象;两种方式引用的是同一个对象。


<?php
// Bar controller class, foo module:
class Foo_BarController extends Zend_Controller_Action
{
    public function 
preDispatch()
    {
        
// change view encoding
        
$this->view->setEncoding('UTF-8');
    }

    public function 
bazAction()
    {
        
// Get view object and set escape callback to 'htmlspecialchars'
        
$view $this->_helper->viewRenderer->view;
        
$view->setEscape('htmlspecialchars');
    }
}

7.8.4.3.4. 高级用法示例

例 7.10. 修改路径规则

有些情况下,默认的路径规则可能并不适合站点的需要。比如,希望拥有一个单独的模板树供设计人员访问(例如,如果你使用Smarty,这是很典型的情形)。这种情况下,你可能想硬编码视图的基路径规则,为动作视图脚本路径自身创建一套规则。

假定视图的基路径(base path)为'/opt/vendor/templates',希望通过':moduleDir/:controller/:action.:suffix'引用视图脚本;如果设定了noController标志,想在顶级而不是在子目录中渲染(':action.:suffix')。最终希望使用'tpl'作为视图脚本文件的后缀。


<?php
/**
 * In your bootstrap:
 */

// Different view implementation
$view = new ZF_Smarty();

$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
$viewRenderer->setViewBasePathSpec('/opt/vendor/templates')
             ->
setViewScriptPathSpec(':module/:controller/:action.:suffix')
             ->
setViewScriptPathNoControllerSpec(':action.:suffix')
             ->
setViewSuffix('tpl');
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

例 7.11. 一个动作中渲染多个视图脚本

有时可能需要在一个动作中渲染多个视图脚本。这个非常简单,多次调用render()就行了:


<?php
class SearchController extends Zend_Controller_Action
{
    public function 
resultsAction()
    {
        
// Assume $this->model is the current model
        
$this->view->results $this->model->find($this->_getParam('query''');

        
// render() by default proxies to the ViewRenderer
        // Render first the search form and then the results
        
$this->render('form');
        
$this->render('results');
    }

    public function 
formAction()
    {
        
// do nothing; ViewRenderer autorenders the view script
    
}
}

7.8.5. 编写自己的助手

动作助手继承抽象类Zend_Controller_Action_Helper_Abstract,该类提供了助手经纪人要求的基本接口和功能,包含下列方法:

  • setActionController() 用来设置当前的动作控制器。

  • init(),该方法在实例化时由助手经纪人触发,可用来触发助手的初始化过程;动作链中多个控制器使用相同的助手时,如要恢复状态时将十分有用。

  • preDispatch()分发动作之前触发。

  • postDispatch()分发过程结束时触发——即使preDispatch()插件已经跳过了该动作。清理时大量使用。

  • getRequest() 获取当前的请求对象。

  • getResponse() 获取当前的响应对象。

  • getName() 获取助手名。获取了下划线后面的类名部分,没有下划线则获取类的全名。例如,如果类名为Zend_Controller_Action_Helper_Redirector,他将返回 Redirector,如果类名为FooMessage,将会返回全名。

助手类中还可以包含一个direct()方法,如果定义了该方法,就可以将助手视作助手经纪人的一个方法,以便简单的、一次性的使用助手。例如redirector 定义direct() 作为goto()的别名,就可以这样使用:


<?php
// Redirect to /blog/view/item/id/42
$this->_helper->redirector('item''view''blog', array('id' => 42));

在内部,助手经纪人的__call()方法先寻找名叫redirector的助手,然后检查该助手的direct方法是否定义,然后使用所提供的参数来调用该方法。

如果创建了自己的助手,可以按照前面章节所述的提供相应的访问方法。