Zend Framework教程之Zend_Helpers動(dòng)作助手ViewRenderer用法詳解

字號(hào):


    本文實(shí)例講述了Zend Framework教程之Zend_Helpers動(dòng)作助手ViewRenderer用法。分享給大家供大家參考,具體如下:
    MVC結(jié)構(gòu)中視圖層和控制器的解耦,以及渲染。往往是重復(fù)或者冗余的工作。如果一個(gè)完善的框架,對(duì)MVC的使用,必定會(huì)對(duì)這些操作進(jìn)行合理的設(shè)計(jì)。讓開發(fā)者更專注內(nèi)容而不是控制邏輯結(jié)構(gòu)本身。在ZendFramework中,主要是通過(guò)動(dòng)作助手ViewRenderer來(lái)完成這個(gè)操作的。ViewRenderer 自動(dòng)的完成在控制器內(nèi)建立視圖對(duì)象并渲染視圖的過(guò)程;
    ViewRenderer
    介紹
    視圖解析(ViewRenderer)助手為實(shí)現(xiàn)下列目標(biāo)設(shè)計(jì):
    不需要在控制器內(nèi)創(chuàng)建視圖對(duì)象實(shí)例;視圖對(duì)象將在控制器內(nèi)自動(dòng)注冊(cè)。
    根據(jù)當(dāng)前的模塊自動(dòng)地設(shè)置視圖腳本、助手、過(guò)濾器路徑。指派當(dāng)前的模塊名為助手和過(guò)濾器類的類名前綴。
    為所有分發(fā)的控制器和動(dòng)作創(chuàng)建全局有效的視圖對(duì)象。
    允許開發(fā)人員為所有控制器設(shè)置默認(rèn)的視圖解析選項(xiàng)。
    加入無(wú)需干預(yù)自動(dòng)解析試圖腳本的功能。
    允許開發(fā)人員為視圖基路徑和視圖腳本路徑創(chuàng)建自己的規(guī)范。
    Note: 如果手動(dòng)執(zhí)行_forward()、redirect、或者render時(shí),不會(huì)發(fā)生自動(dòng)解析。因?yàn)閳?zhí)行這些動(dòng)作時(shí),等于告訴ViewRenderer,你要自己確定輸出結(jié)果。
    Note: ViewRenderer助手默認(rèn)啟用。
    你可以通過(guò)前端控制器的noViewRenderer方法、設(shè)定參數(shù)($front->setParam('noViewRenderer', true))或者從助手經(jīng)紀(jì)人棧(helper broker stack)中移除助手(Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer'))等方式禁用該助手。
    如希望在分發(fā)前端控制器前修改ViewRenderer設(shè)定,可采用下面的兩種方法:
    創(chuàng)建實(shí)例并注冊(cè)自己的ViewRenderer對(duì)象,然后傳入到助手經(jīng)紀(jì)人。
    $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
    $viewRenderer->setView($view)
           ->setViewSuffix('php');
    Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
    通過(guò)助手經(jīng)紀(jì)人即時(shí)的初始化并/或獲取ViewRenderer對(duì)象。
    $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    $viewRenderer->setView($view)
           ->setViewSuffix('php');
    API
    大多數(shù)使用中,只需要簡(jiǎn)單的創(chuàng)建 ViewRenderer對(duì)象,然后傳入到動(dòng)作助手經(jīng)紀(jì)人。創(chuàng)建實(shí)例并注冊(cè)的最簡(jiǎn)單方式是使用助手經(jīng)紀(jì)人的getStaticHelper()方法:
    Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    動(dòng)作控制器第一次實(shí)例化時(shí),會(huì)觸發(fā)ViewRenderer創(chuàng)建一個(gè)視圖對(duì)象。動(dòng)作控制器每次實(shí)例化都會(huì)調(diào)用ViewRenderer的init()方法,設(shè)定動(dòng)作控制器的視圖屬性,并以相對(duì)于當(dāng)前模塊的路徑為參數(shù)調(diào)用addScriptPath()方法;調(diào)用時(shí)帶有以當(dāng)前模塊命名的類前綴參數(shù),該參數(shù)對(duì)為該模塊定義的所有助手和過(guò)濾器類都有效。(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. )
    每次執(zhí)行postDispatch()方法,它將為當(dāng)前動(dòng)作執(zhí)行render()方法。
    例如這個(gè)類:
    // 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:
    $this->foo(); // call Foo_View_Helper_Foo::foo()
    ViewRenderer也定義了大量的訪問(wèn)器用來(lái)設(shè)定和獲取視圖選項(xiàng)。
    setView($view)可以為ViewRenderer設(shè)定視圖對(duì)象。以公共類屬性$view獲取設(shè)定值。
    setNeverRender($flag = true)可以全局的啟用或禁用自動(dòng)解析,也就是對(duì)所有控制器都有效。如果設(shè)定為true,在所有控制器器內(nèi),postDispatch()將不會(huì)自動(dòng)調(diào)用render()。getNeverRender()返回當(dāng)前的設(shè)定值。
    setNoRender($flag = true) 用來(lái)啟用或禁用自動(dòng)解析,如果設(shè)置為true,在當(dāng)前控制器內(nèi),postDispatch()不會(huì)調(diào)用render()方法。這個(gè)設(shè)定在preDispatch()每次執(zhí)行時(shí)會(huì)被重置。getNoRender()返回當(dāng)前的設(shè)定值。
    setNoController($flag = true)通知render()不要再到以控制器命名的子目錄中尋找視圖腳本。getNoController()返回當(dāng)前值。
    setNeverController($flag = true)與setNoController($flag = true)相似,但是其在全局范圍內(nèi)有效——也就是說(shuō),它不會(huì)在每次分發(fā)動(dòng)作時(shí)重置。getNeverController()返回當(dāng)前值。
    setScriptAction($name)用來(lái)指定解析的視圖腳本。$name是腳本的名字去掉后綴(不帶控制器子目錄,除非noController已開啟)。如果沒(méi)有指定,它將尋找以請(qǐng)求對(duì)象中的動(dòng)作命名的視圖腳本。getScriptAction()返回當(dāng)前值。
    setResponseSegment($name)用來(lái)指定解析到響應(yīng)對(duì)象中的哪個(gè)命名片段。如果沒(méi)有指定,解析到默認(rèn)片斷。getResponseSegment()返回當(dāng)前值。
    initView($path, $prefix, $options)可以指定視圖的基路徑,為助手和過(guò)濾器腳本設(shè)置類前綴,設(shè)定ViewRenderer選項(xiàng)??梢詡魅胍韵氯我獾臉?biāo)志:neverRender,noRender,noController, scriptAction,和responseSegment。
    setRender($action = null, $name = null, $noController = false)可以一次設(shè)定scriptAction、responseSegment和noController。 direct()是它的別名,使得控制器中可以方便的調(diào)用。
    // 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);
    Note: setRender() 和 direct()并不會(huì)實(shí)際解析視圖腳本,而是提示postDispatch()和postDispatch()解析視圖。
    構(gòu)造函數(shù)允許可選的傳入?yún)?shù)視圖對(duì)象和ViewRenderer選項(xiàng),接受與initView()一樣的標(biāo)志(flags):
    $view  = new Zend_View(array('encoding' => 'UTF-8'));
    $options = array('noController' => true, 'neverRender' => true);
    $viewRenderer =
      new Zend_Controller_Action_Helper_ViewRenderer($view, $options);
    還有幾個(gè)額外的方法用來(lái)定制路徑規(guī)則,供確定視圖基路徑來(lái)增加視圖對(duì)象,確定視圖腳本路徑查找并解析視圖腳本時(shí)使用。這些方法每個(gè)都帶有下面一個(gè)或更多的占位符(placehodlers)。
    :moduleDir 引用當(dāng)前模塊的基目錄(常規(guī)的是模塊的控制器目錄的父目錄)。
    :module 引用當(dāng)前的模塊名。
    :controller 引用當(dāng)前的控制器名。
    :action引用當(dāng)前的模塊名。
    :suffix 引用當(dāng)前的視圖腳本后綴(可以通過(guò)setViewSuffix()來(lái)設(shè)置)。
    控制器路徑規(guī)則有關(guān)的方法:
    setViewBasePathSpec($spec)可以改變確定加入到視圖對(duì)象的基路徑的路徑規(guī)則。默認(rèn)規(guī)則是:moduleDir/views。任何時(shí)候都可以使用getViewBasePathSpec()獲取當(dāng)前的規(guī)則。
    setViewScriptPathSpec($spec)允許改變確定到達(dá)單獨(dú)的視圖腳本路徑(去除試圖腳本基路徑)的路徑規(guī)則。默認(rèn)的路徑規(guī)則是 :controller/:action.:suffix。任何時(shí)候都可以通過(guò)getViewScriptPathSpec()獲取當(dāng)前規(guī)則。
    setViewScriptPathNoControllerSpec($spec)允許改變 noController有效時(shí)確定到達(dá)單獨(dú)的視圖腳本路徑(去除試圖腳本基路徑)的路徑規(guī)則。默認(rèn)的規(guī)則是:action.:suffix,任何時(shí)候都可以通過(guò)getViewScriptPathNoControllerSpec()獲取當(dāng)前規(guī)則。
    為在路徑規(guī)范之上精心設(shè)計(jì)的控制,可以使用Zend_Filter_Inflector。深入地,視圖解析器(ViewRenderer)已經(jīng)使用inflector來(lái)執(zhí)行路徑映射。為和inflector互動(dòng) - 或者設(shè)置你自己的或者修改缺省的inflector,下面的方法可以被使用:
    getInflector() 將獲取inflector。如果在視圖解析器中不存在, 它用缺省的規(guī)則創(chuàng)建一個(gè)。
    缺省地,它用靜態(tài)規(guī)則引用和靜態(tài)目標(biāo)做為后綴和模塊目錄;這允許不同的視圖解析器具備動(dòng)態(tài)修改inflector能力的屬性。
    setInflector($inflector, $reference) 允許設(shè)置定制的inflector和視圖解析器一起使用。如果$reference 是true,它將設(shè)置后綴和模塊目錄作為靜態(tài)引用和目標(biāo)給視圖解析器 屬性。
    Note: 缺省查找約定(Conventions)
    視圖解析器做了一些路徑標(biāo)準(zhǔn)化使視圖腳本查找更容易。缺省規(guī)則如下:
    :module: 混合詞和駝峰詞被短橫線分開,并整個(gè)串變成小寫。例如:"FooBarBaz" 變成 "foo-bar-baz"。
    在內(nèi)部,變形器(inflector) 使用過(guò)濾器Zend_Filter_Word_CamelCaseToDash 和 Zend_Filter_StringToLower。
    :controller: 混合詞和駝峰詞被短橫線分開;下劃線轉(zhuǎn)換成目錄分隔符,并且整個(gè)串變小寫。例如:"FooBar" becomes "foo-bar"; "FooBar_Admin" 變成 "foo-bar/admin".
    在內(nèi)部,inflector 使用過(guò)濾器Zend_Filter_Word_CamelCaseToDash、Zend_Filter_Word_UnderscoreToSeparator 和 Zend_Filter_StringToLower。
    :action: 混合詞和駝峰詞被短橫線分開;非字母數(shù)字字符翻譯成短橫線,并且整個(gè)串變成小寫。 例如 "fooBar" 變成 "foo-bar"; "foo-barBaz" 變成 "foo-bar-baz"。
    在內(nèi)部,inflector 使用過(guò)濾器 Zend_Filter_Word_CamelCaseToDash、Zend_Filter_PregReplace 和 Zend_Filter_StringToLower。
    視圖解析器 API中的最后一項(xiàng)是關(guān)于實(shí)際確定視圖腳本路徑和解析視圖的。包括:
    renderScript($script, $name)允許解析指定路徑的腳本,可選的命名的路徑片段。(renderScript($script, $name) allows you to render a script with a path you specify, optionally to a named path segment. )使用該方法時(shí),ViewRenderer不會(huì)自動(dòng)的確定腳本名稱,而是直接的向視圖對(duì)象的render()傳入$script參數(shù)。
    Note: 當(dāng)視圖已經(jīng)被解析到響應(yīng)對(duì)象,將會(huì)設(shè)置noRender阻止相同的腳本被多次解析。
    Note: 默認(rèn)的,Zend_Controller_Action::renderScript()代理ViewRenderer的renderScript()方法。
    getViewScript($action, $vars)基于傳入的動(dòng)作和/或$vars中的變量創(chuàng)建到視圖腳本的路徑。該數(shù)組中的鍵可以包含所有的路徑指定鍵('moduleDir','module', 'controller', 'action', and 'suffix')。傳入的任何變量都會(huì)優(yōu)先使用,否則利用基于當(dāng)前請(qǐng)求的值。
    getViewScript()根據(jù)noController標(biāo)志的設(shè)定值使用viewScriptPathSpec或者viewScriptPathNoControllerSpec。
    模塊、控制器以及動(dòng)作中的單詞定界符將后替換成短線('-')。因此,控制器名稱'foo.bar'和動(dòng)作'baz:bat'按照默認(rèn)的路徑規(guī)則將會(huì)得到視圖腳本路徑'foo-bar/baz-bat.phtml'。
    Note: 默認(rèn)的,Zend_Controller_Action::getViewScript()代理ViewRenderer的getViewScript()方法。
    render($action, $name, $noController)首先檢查$name或 $noController參數(shù)是否傳入,如果傳入,則在ViewRenderer中設(shè)定相應(yīng)的標(biāo)志(分別是響應(yīng)片段和noController)。然后傳入$action參數(shù)到getViewScript(),最后傳入計(jì)算的試圖腳本路徑到renderScript()。
    Note: 注意使用render()的邊際效應(yīng):傳入的響應(yīng)片段名稱和noController標(biāo)志在視圖對(duì)象中存留。此外解析結(jié)束后noRender會(huì)被設(shè)置。
    Note: 默認(rèn)的,Zend_Controller_Action::render()代理 ViewRenderer的render()方法。
    renderBySpec($action, $vars, $name)允許傳入路徑規(guī)則變量以確定創(chuàng)建的視圖腳本路徑。它把$action和$vars傳入到getScriptPath(),將腳本路徑結(jié)果和$name傳入到renderScript()。
    基礎(chǔ)用法示例
    Example #9 基本用法
    大多數(shù)基礎(chǔ)使用中,只需在bootstrap中使用助手經(jīng)紀(jì)人簡(jiǎn)單的初始化和注冊(cè)ViewRenderer 助手,然后在動(dòng)作方法中設(shè)置變量。
    // In your bootstrap:
    Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
    ...
    // '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');
      }
    }
    Note: 命名規(guī)則:控制器和動(dòng)作名中的單詞定界符
    如果控制器或者動(dòng)作名稱由幾個(gè)單詞組成,分發(fā)器要求在URL中使用特定的路徑和單詞定界符分隔。ViewRenderer創(chuàng)建路徑時(shí)將控制器名稱中的任何路徑定界符替換成實(shí)際的路徑定界符('/'),任何單詞定界符替換成短線('-')。對(duì)動(dòng)作/foo.bar/baz.bat的調(diào)用將分發(fā)到FooBarController.php中的FooBarController::bazBatAction(),然后解析foo-bar/baz-bat.phtml;對(duì)動(dòng)作/bar_baz/baz-bat的調(diào)用將分發(fā)到Bar/BazController.php中的Bar_BazController::bazBatAction(),并解析bar/baz/baz-bat.phtml。
    注意到在第二個(gè)例子中,模塊依然是默認(rèn)的模塊,但由于路徑分隔符的存在,控制器的接收到的名字為Bar_BazController,該類在文件Bar/BazController.php中。ViewRenderer模擬了控制器的目錄分層。
    Example #10 禁用自動(dòng)解析
    對(duì)于某些動(dòng)作和控制器,可能希望關(guān)閉自動(dòng)解析——例如,如果想發(fā)送其他類型的輸出(XML,JSON等),或者更簡(jiǎn)單的不想發(fā)送任何東西。有兩個(gè)選項(xiàng):關(guān)閉所有的自動(dòng)解析(setNeverRender()),或者僅僅關(guān)閉當(dāng)前動(dòng)作的自動(dòng)解析(setNoRender())。
    // Baz controller class, bar module:
    class Bar_BazController extends Zend_Controller_Action
    {
      public function fooAction()
      {
        // Don't auto render this action
        <strong>$this->_helper->viewRenderer->setNoRender();</strong>
      }
    }
    // 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();
      }
    }
    Note: 大多數(shù)情況下,全局的關(guān)閉自動(dòng)解析(setNeverRender())沒(méi)有意義,因?yàn)檫@樣ViewRenderer做的唯一件事只是自動(dòng)設(shè)置了視圖對(duì)象。
    Example #11 選擇另外的視圖腳本
    有些情況下需要解析另一個(gè)腳本而非以動(dòng)作命名的腳本。例如,如果你有一個(gè)控制器包含增加和編輯兩個(gè)動(dòng)作,它們可能都顯示相同的'form'視圖,盡管擁有不同的值集合(value set)。只需要使用setScriptAction()或者setRender()簡(jiǎn)單的改變腳本的名稱,或者以成員方法的形式調(diào)用助手,它將調(diào)用setRender()。
    // 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...
      }
    }
    Example #12 修改注冊(cè)的視圖Modifying the registered view
    如果需要修改視圖對(duì)象怎么辦——例如改變助手路徑或者編碼?可以在控制器中修改視圖對(duì)象設(shè)定,或者從ViewRenderer中抓取視圖對(duì)象;兩種方式引用的是同一個(gè)對(duì)象。
    // 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');
      }
    }
    高級(jí)用法示例
    Example #13 修改路徑規(guī)則
    有些情況下,默認(rèn)的路徑規(guī)則可能并不適合站點(diǎn)的需要。比如,希望擁有一個(gè)單獨(dú)的模板樹供設(shè)計(jì)人員訪問(wèn)(例如,如果你使用» Smarty,這是很典型的情形)。這種情況下,你可能想硬編碼視圖的基路徑規(guī)則,為動(dòng)作視圖腳本路徑自身創(chuàng)建一套規(guī)則。
    假定視圖的基路徑(base path)為'/opt/vendor/templates',希望通過(guò)':moduleDir/:controller/:action.:suffix'引用視圖腳本;如果設(shè)定了noController標(biāo)志,想在頂級(jí)而不是在子目錄中解析(':action.:suffix')。最終希望使用'tpl'作為視圖腳本文件的后綴。
    /**
     * 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);
    Example #14 一個(gè)動(dòng)作中解析多個(gè)視圖腳本
    有時(shí)可能需要在一個(gè)動(dòng)作中解析多個(gè)視圖腳本。這個(gè)非常簡(jiǎn)單,多次調(diào)用render()就行了:
    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
      }
    }
    ViewRenderer的相關(guān)源碼如下,仔細(xì)分析,并不難看出實(shí)現(xiàn)方法:
    <?php
    /**
     * @see Zend_Controller_Action_Helper_Abstract
     */
    require_once 'Zend/Controller/Action/Helper/Abstract.php';
    /**
     * @see Zend_View
     */
    require_once 'Zend/View.php';
    /**
     * View script integration
     *
     * Zend_Controller_Action_Helper_ViewRenderer provides transparent view
     * integration for action controllers. It allows you to create a view object
     * once, and populate it throughout all actions. Several global options may be
     * set:
     *
     * - noController: if set true, render() will not look for view scripts in
     *  subdirectories named after the controller
     * - viewSuffix: what view script filename suffix to use
     *
     * The helper autoinitializes the action controller view preDispatch(). It
     * determines the path to the class file, and then determines the view base
     * directory from there. It also uses the module name as a class prefix for
     * helpers and views such that if your module name is 'Search', it will set the
     * helper class prefix to 'Search_View_Helper' and the filter class prefix to ;
     * 'Search_View_Filter'.
     *
     * Usage:
     * <code>
     * // In your bootstrap:
     * Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer());
     *
     * // In your action controller methods:
     * $viewHelper = $this->_helper->getHelper('view');
     *
     * // Don't use controller subdirectories
     * $viewHelper->setNoController(true);
     *
     * // Specify a different script to render:
     * $this->_helper->viewRenderer('form');
     *
     * </code>
     *
     * @uses    Zend_Controller_Action_Helper_Abstract
     * @package  Zend_Controller
     * @subpackage Zend_Controller_Action_Helper
     * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
     * @license  http://framework.zend.com/license/new-bsd   New BSD License
     */
    class Zend_Controller_Action_Helper_ViewRenderer extends Zend_Controller_Action_Helper_Abstract
    {
      /**
       * @var Zend_View_Interface
       */
      public $view;
      /**
       * Word delimiters
       * @var array
       */
      protected $_delimiters;
      /**
       * @var Zend_Filter_Inflector
       */
      protected $_inflector;
      /**
       * Inflector target
       * @var string
       */
      protected $_inflectorTarget = '';
      /**
       * Current module directory
       * @var string
       */
      protected $_moduleDir = '';
      /**
       * Whether or not to autorender using controller name as subdirectory;
       * global setting (not reset at next invocation)
       * @var boolean
       */
      protected $_neverController = false;
      /**
       * Whether or not to autorender postDispatch; global setting (not reset at
       * next invocation)
       * @var boolean
       */
      protected $_neverRender   = false;
      /**
       * Whether or not to use a controller name as a subdirectory when rendering
       * @var boolean
       */
      protected $_noController  = false;
      /**
       * Whether or not to autorender postDispatch; per controller/action setting (reset
       * at next invocation)
       * @var boolean
       */
      protected $_noRender    = false;
      /**
       * Characters representing path delimiters in the controller
       * @var string|array
       */
      protected $_pathDelimiters;
      /**
       * Which named segment of the response to utilize
       * @var string
       */
      protected $_responseSegment = null;
      /**
       * Which action view script to render
       * @var string
       */
      protected $_scriptAction  = null;
      /**
       * View object basePath
       * @var string
       */
      protected $_viewBasePathSpec = ':moduleDir/views';
      /**
       * View script path specification string
       * @var string
       */
      protected $_viewScriptPathSpec = ':controller/:action.:suffix';
      /**
       * View script path specification string, minus controller segment
       * @var string
       */
      protected $_viewScriptPathNoControllerSpec = ':action.:suffix';
      /**
       * View script suffix
       * @var string
       */
      protected $_viewSuffix   = 'phtml';
      /**
       * Constructor
       *
       * Optionally set view object and options.
       *
       * @param Zend_View_Interface $view
       * @param array        $options
       * @return void
       */
      public function __construct(Zend_View_Interface $view = null, array $options = array())
      {
        if (null !== $view) {
          $this->setView($view);
        }
        if (!empty($options)) {
          $this->_setOptions($options);
        }
      }
      /**
       * Clone - also make sure the view is cloned.
       *
       * @return void
       */
      public function __clone()
      {
        if (isset($this->view) && $this->view instanceof Zend_View_Interface) {
          $this->view = clone $this->view;
        }
      }
      /**
       * Set the view object
       *
       * @param Zend_View_Interface $view
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setView(Zend_View_Interface $view)
      {
        $this->view = $view;
        return $this;
      }
      /**
       * Get current module name
       *
       * @return string
       */
      public function getModule()
      {
        $request = $this->getRequest();
        $module = $request->getModuleName();
        if (null === $module) {
          $module = $this->getFrontController()->getDispatcher()->getDefaultModule();
        }
        return $module;
      }
      /**
       * Get module directory
       *
       * @throws Zend_Controller_Action_Exception
       * @return string
       */
      public function getModuleDirectory()
      {
        $module  = $this->getModule();
        $moduleDir = $this->getFrontController()->getControllerDirectory($module);
        if ((null === $moduleDir) || is_array($moduleDir)) {
          /**
           * @see Zend_Controller_Action_Exception
           */
          require_once 'Zend/Controller/Action/Exception.php';
          throw new Zend_Controller_Action_Exception('ViewRenderer cannot locate module directory for module "' . $module . '"');
        }
        $this->_moduleDir = dirname($moduleDir);
        return $this->_moduleDir;
      }
      /**
       * Get inflector
       *
       * @return Zend_Filter_Inflector
       */
      public function getInflector()
      {
        if (null === $this->_inflector) {
          /**
           * @see Zend_Filter_Inflector
           */
          require_once 'Zend/Filter/Inflector.php';
          /**
           * @see Zend_Filter_PregReplace
           */
          require_once 'Zend/Filter/PregReplace.php';
          /**
           * @see Zend_Filter_Word_UnderscoreToSeparator
           */
          require_once 'Zend/Filter/Word/UnderscoreToSeparator.php';
          $this->_inflector = new Zend_Filter_Inflector();
          $this->_inflector->setStaticRuleReference('moduleDir', $this->_moduleDir) // moduleDir must be specified before the less specific 'module'
             ->addRules(array(
               ':module'   => array('Word_CamelCaseToDash', 'StringToLower'),
               ':controller' => array('Word_CamelCaseToDash', new Zend_Filter_Word_UnderscoreToSeparator('/'), 'StringToLower', new Zend_Filter_PregReplace('/\./', '-')),
               ':action'   => array('Word_CamelCaseToDash', new Zend_Filter_PregReplace('#[^a-z0-9' . preg_quote('/', '#') . ']+#i', '-'), 'StringToLower'),
             ))
             ->setStaticRuleReference('suffix', $this->_viewSuffix)
             ->setTargetReference($this->_inflectorTarget);
        }
        // Ensure that module directory is current
        $this->getModuleDirectory();
        return $this->_inflector;
      }
      /**
       * Set inflector
       *
       * @param Zend_Filter_Inflector $inflector
       * @param boolean        $reference Whether the moduleDir, target, and suffix should be set as references to ViewRenderer properties
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setInflector(Zend_Filter_Inflector $inflector, $reference = false)
      {
        $this->_inflector = $inflector;
        if ($reference) {
          $this->_inflector->setStaticRuleReference('suffix', $this->_viewSuffix)
             ->setStaticRuleReference('moduleDir', $this->_moduleDir)
             ->setTargetReference($this->_inflectorTarget);
        }
        return $this;
      }
      /**
       * Set inflector target
       *
       * @param string $target
       * @return void
       */
      protected function _setInflectorTarget($target)
      {
        $this->_inflectorTarget = (string) $target;
      }
      /**
       * Set internal module directory representation
       *
       * @param string $dir
       * @return void
       */
      protected function _setModuleDir($dir)
      {
        $this->_moduleDir = (string) $dir;
      }
      /**
       * Get internal module directory representation
       *
       * @return string
       */
      protected function _getModuleDir()
      {
        return $this->_moduleDir;
      }
      /**
       * Generate a class prefix for helper and filter classes
       *
       * @return string
       */
      protected function _generateDefaultPrefix()
      {
        $default = 'Zend_View';
        if (null === $this->_actionController) {
          return $default;
        }
        $class = get_class($this->_actionController);
        if (!strstr($class, '_')) {
          return $default;
        }
        $module = $this->getModule();
        if ('default' == $module) {
          return $default;
        }
        $prefix = substr($class, 0, strpos($class, '_')) . '_View';
        return $prefix;
      }
      /**
       * Retrieve base path based on location of current action controller
       *
       * @return string
       */
      protected function _getBasePath()
      {
        if (null === $this->_actionController) {
          return './views';
        }
        $inflector = $this->getInflector();
        $this->_setInflectorTarget($this->getViewBasePathSpec());
        $dispatcher = $this->getFrontController()->getDispatcher();
        $request = $this->getRequest();
        $parts = array(
          'module'   => (($moduleName = $request->getModuleName()) != '') ? $dispatcher->formatModuleName($moduleName) : $moduleName,
          'controller' => $request->getControllerName(),
          'action'   => $dispatcher->formatActionName($request->getActionName())
          );
        $path = $inflector->filter($parts);
        return $path;
      }
      /**
       * Set options
       *
       * @param array $options
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      protected function _setOptions(array $options)
      {
        foreach ($options as $key => $value)
        {
          switch ($key) {
            case 'neverRender':
            case 'neverController':
            case 'noController':
            case 'noRender':
              $property = '_' . $key;
              $this->{$property} = ($value) ? true : false;
              break;
            case 'responseSegment':
            case 'scriptAction':
            case 'viewBasePathSpec':
            case 'viewScriptPathSpec':
            case 'viewScriptPathNoControllerSpec':
            case 'viewSuffix':
              $property = '_' . $key;
              $this->{$property} = (string) $value;
              break;
            default:
              break;
          }
        }
        return $this;
      }
      /**
       * Initialize the view object
       *
       * $options may contain the following keys:
       * - neverRender - flag dis/enabling postDispatch() autorender (affects all subsequent calls)
       * - noController - flag indicating whether or not to look for view scripts in subdirectories named after the controller
       * - noRender - flag indicating whether or not to autorender postDispatch()
       * - responseSegment - which named response segment to render a view script to
       * - scriptAction - what action script to render
       * - viewBasePathSpec - specification to use for determining view base path
       * - viewScriptPathSpec - specification to use for determining view script paths
       * - viewScriptPathNoControllerSpec - specification to use for determining view script paths when noController flag is set
       * - viewSuffix - what view script filename suffix to use
       *
       * @param string $path
       * @param string $prefix
       * @param array $options
       * @throws Zend_Controller_Action_Exception
       * @return void
       */
      public function initView($path = null, $prefix = null, array $options = array())
      {
        if (null === $this->view) {
          $this->setView(new Zend_View());
        }
        // Reset some flags every time
        $options['noController'] = (isset($options['noController'])) ? $options['noController'] : false;
        $options['noRender']   = (isset($options['noRender'])) ? $options['noRender'] : false;
        $this->_scriptAction   = null;
        $this->_responseSegment = null;
        // Set options first; may be used to determine other initializations
        $this->_setOptions($options);
        // Get base view path
        if (empty($path)) {
          $path = $this->_getBasePath();
          if (empty($path)) {
            /**
             * @see Zend_Controller_Action_Exception
             */
            require_once 'Zend/Controller/Action/Exception.php';
            throw new Zend_Controller_Action_Exception('ViewRenderer initialization failed: retrieved view base path is empty');
          }
        }
        if (null === $prefix) {
          $prefix = $this->_generateDefaultPrefix();
        }
        // Determine if this path has already been registered
        $currentPaths = $this->view->getScriptPaths();
        $path     = str_replace(array('/', '\\'), '/', $path);
        $pathExists  = false;
        foreach ($currentPaths as $tmpPath) {
          $tmpPath = str_replace(array('/', '\\'), '/', $tmpPath);
          if (strstr($tmpPath, $path)) {
            $pathExists = true;
            break;
          }
        }
        if (!$pathExists) {
          $this->view->addBasePath($path, $prefix);
        }
        // Register view with action controller (unless already registered)
        if ((null !== $this->_actionController) && (null === $this->_actionController->view)) {
          $this->_actionController->view    = $this->view;
          $this->_actionController->viewSuffix = $this->_viewSuffix;
        }
      }
      /**
       * init - initialize view
       *
       * @return void
       */
      public function init()
      {
        if ($this->getFrontController()->getParam('noViewRenderer')) {
          return;
        }
        $this->initView();
      }
      /**
       * Set view basePath specification
       *
       * Specification can contain one or more of the following:
       * - :moduleDir - current module directory
       * - :controller - name of current controller in the request
       * - :action - name of current action in the request
       * - :module - name of current module in the request
       *
       * @param string $path
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setViewBasePathSpec($path)
      {
        $this->_viewBasePathSpec = (string) $path;
        return $this;
      }
      /**
       * Retrieve the current view basePath specification string
       *
       * @return string
       */
      public function getViewBasePathSpec()
      {
        return $this->_viewBasePathSpec;
      }
      /**
       * Set view script path specification
       *
       * Specification can contain one or more of the following:
       * - :moduleDir - current module directory
       * - :controller - name of current controller in the request
       * - :action - name of current action in the request
       * - :module - name of current module in the request
       *
       * @param string $path
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setViewScriptPathSpec($path)
      {
        $this->_viewScriptPathSpec = (string) $path;
        return $this;
      }
      /**
       * Retrieve the current view script path specification string
       *
       * @return string
       */
      public function getViewScriptPathSpec()
      {
        return $this->_viewScriptPathSpec;
      }
      /**
       * Set view script path specification (no controller variant)
       *
       * Specification can contain one or more of the following:
       * - :moduleDir - current module directory
       * - :controller - name of current controller in the request
       * - :action - name of current action in the request
       * - :module - name of current module in the request
       *
       * :controller will likely be ignored in this variant.
       *
       * @param string $path
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setViewScriptPathNoControllerSpec($path)
      {
        $this->_viewScriptPathNoControllerSpec = (string) $path;
        return $this;
      }
      /**
       * Retrieve the current view script path specification string (no controller variant)
       *
       * @return string
       */
      public function getViewScriptPathNoControllerSpec()
      {
        return $this->_viewScriptPathNoControllerSpec;
      }
      /**
       * Get a view script based on an action and/or other variables
       *
       * Uses values found in current request if no values passed in $vars.
       *
       * If {@link $_noController} is set, uses {@link $_viewScriptPathNoControllerSpec};
       * otherwise, uses {@link $_viewScriptPathSpec}.
       *
       * @param string $action
       * @param array $vars
       * @return string
       */
      public function getViewScript($action = null, array $vars = array())
      {
        $request = $this->getRequest();
        if ((null === $action) && (!isset($vars['action']))) {
          $action = $this->getScriptAction();
          if (null === $action) {
            $action = $request->getActionName();
          }
          $vars['action'] = $action;
        } elseif (null !== $action) {
          $vars['action'] = $action;
        }
        $replacePattern = array('/[^a-z0-9]+$/i', '/^[^a-z0-9]+/i');
        $vars['action'] = preg_replace($replacePattern, '', $vars['action']);
        $inflector = $this->getInflector();
        if ($this->getNoController() || $this->getNeverController()) {
          $this->_setInflectorTarget($this->getViewScriptPathNoControllerSpec());
        } else {
          $this->_setInflectorTarget($this->getViewScriptPathSpec());
        }
        return $this->_translateSpec($vars);
      }
      /**
       * Set the neverRender flag (i.e., globally dis/enable autorendering)
       *
       * @param boolean $flag
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setNeverRender($flag = true)
      {
        $this->_neverRender = ($flag) ? true : false;
        return $this;
      }
      /**
       * Retrieve neverRender flag value
       *
       * @return boolean
       */
      public function getNeverRender()
      {
        return $this->_neverRender;
      }
      /**
       * Set the noRender flag (i.e., whether or not to autorender)
       *
       * @param boolean $flag
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setNoRender($flag = true)
      {
        $this->_noRender = ($flag) ? true : false;
        return $this;
      }
      /**
       * Retrieve noRender flag value
       *
       * @return boolean
       */
      public function getNoRender()
      {
        return $this->_noRender;
      }
      /**
       * Set the view script to use
       *
       * @param string $name
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setScriptAction($name)
      {
        $this->_scriptAction = (string) $name;
        return $this;
      }
      /**
       * Retrieve view script name
       *
       * @return string
       */
      public function getScriptAction()
      {
        return $this->_scriptAction;
      }
      /**
       * Set the response segment name
       *
       * @param string $name
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setResponseSegment($name)
      {
        if (null === $name) {
          $this->_responseSegment = null;
        } else {
          $this->_responseSegment = (string) $name;
        }
        return $this;
      }
      /**
       * Retrieve named response segment name
       *
       * @return string
       */
      public function getResponseSegment()
      {
        return $this->_responseSegment;
      }
      /**
       * Set the noController flag (i.e., whether or not to render into controller subdirectories)
       *
       * @param boolean $flag
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setNoController($flag = true)
      {
        $this->_noController = ($flag) ? true : false;
        return $this;
      }
      /**
       * Retrieve noController flag value
       *
       * @return boolean
       */
      public function getNoController()
      {
        return $this->_noController;
      }
      /**
       * Set the neverController flag (i.e., whether or not to render into controller subdirectories)
       *
       * @param boolean $flag
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setNeverController($flag = true)
      {
        $this->_neverController = ($flag) ? true : false;
        return $this;
      }
      /**
       * Retrieve neverController flag value
       *
       * @return boolean
       */
      public function getNeverController()
      {
        return $this->_neverController;
      }
      /**
       * Set view script suffix
       *
       * @param string $suffix
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setViewSuffix($suffix)
      {
        $this->_viewSuffix = (string) $suffix;
        return $this;
      }
      /**
       * Get view script suffix
       *
       * @return string
       */
      public function getViewSuffix()
      {
        return $this->_viewSuffix;
      }
      /**
       * Set options for rendering a view script
       *
       * @param string $action    View script to render
       * @param string $name     Response named segment to render to
       * @param boolean $noController Whether or not to render within a subdirectory named after the controller
       * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface
       */
      public function setRender($action = null, $name = null, $noController = null)
      {
        if (null !== $action) {
          $this->setScriptAction($action);
        }
        if (null !== $name) {
          $this->setResponseSegment($name);
        }
        if (null !== $noController) {
          $this->setNoController($noController);
        }
        return $this;
      }
      /**
       * Inflect based on provided vars
       *
       * Allowed variables are:
       * - :moduleDir - current module directory
       * - :module - current module name
       * - :controller - current controller name
       * - :action - current action name
       * - :suffix - view script file suffix
       *
       * @param array $vars
       * @return string
       */
      protected function _translateSpec(array $vars = array())
      {
        $inflector = $this->getInflector();
        $request  = $this->getRequest();
        $dispatcher = $this->getFrontController()->getDispatcher();
        $module   = $dispatcher->formatModuleName($request->getModuleName());
        $controller = $request->getControllerName();
        $action   = $dispatcher->formatActionName($request->getActionName());
        $params   = compact('module', 'controller', 'action');
        foreach ($vars as $key => $value) {
          switch ($key) {
            case 'module':
            case 'controller':
            case 'action':
            case 'moduleDir':
            case 'suffix':
              $params[$key] = (string) $value;
              break;
            default:
              break;
          }
        }
        if (isset($params['suffix'])) {
          $origSuffix = $this->getViewSuffix();
          $this->setViewSuffix($params['suffix']);
        }
        if (isset($params['moduleDir'])) {
          $origModuleDir = $this->_getModuleDir();
          $this->_setModuleDir($params['moduleDir']);
        }
        $filtered = $inflector->filter($params);
        if (isset($params['suffix'])) {
          $this->setViewSuffix($origSuffix);
        }
        if (isset($params['moduleDir'])) {
          $this->_setModuleDir($origModuleDir);
        }
        return $filtered;
      }
      /**
       * Render a view script (optionally to a named response segment)
       *
       * Sets the noRender flag to true when called.
       *
       * @param string $script
       * @param string $name
       * @return void
       */
      public function renderScript($script, $name = null)
      {
        if (null === $name) {
          $name = $this->getResponseSegment();
        }
        $this->getResponse()->appendBody(
          $this->view->render($script),
          $name
        );
        $this->setNoRender();
      }
      /**
       * Render a view based on path specifications
       *
       * Renders a view based on the view script path specifications.
       *
       * @param string $action
       * @param string $name
       * @param boolean $noController
       * @return void
       */
      public function render($action = null, $name = null, $noController = null)
      {
        $this->setRender($action, $name, $noController);
        $path = $this->getViewScript();
        $this->renderScript($path, $name);
      }
      /**
       * Render a script based on specification variables
       *
       * Pass an action, and one or more specification variables (view script suffix)
       * to determine the view script path, and render that script.
       *
       * @param string $action
       * @param array $vars
       * @param string $name
       * @return void
       */
      public function renderBySpec($action = null, array $vars = array(), $name = null)
      {
        if (null !== $name) {
          $this->setResponseSegment($name);
        }
        $path = $this->getViewScript($action, $vars);
        $this->renderScript($path);
      }
      /**
       * postDispatch - auto render a view
       *
       * Only autorenders if:
       * - _noRender is false
       * - action controller is present
       * - request has not been re-dispatched (i.e., _forward() has not been called)
       * - response is not a redirect
       *
       * @return void
       */
      public function postDispatch()
      {
        if ($this->_shouldRender()) {
          $this->render();
        }
      }
      /**
       * Should the ViewRenderer render a view script?
       *
       * @return boolean
       */
      protected function _shouldRender()
      {
        return (!$this->getFrontController()->getParam('noViewRenderer')
          && !$this->_neverRender
          && !$this->_noRender
          && (null !== $this->_actionController)
          && $this->getRequest()->isDispatched()
          && !$this->getResponse()->isRedirect()
        );
      }
      /**
       * Use this helper as a method; proxies to setRender()
       *
       * @param string $action
       * @param string $name
       * @param boolean $noController
       * @return void
       */
      public function direct($action = null, $name = null, $noController = null)
      {
        $this->setRender($action, $name, $noController);
      }
    }
    希望本文所述對(duì)大家基于Zend Framework框架的PHP程序設(shè)計(jì)有所幫助。