当前位置:首页 > CMS教程 > 其它CMS > 列表

Zend Framework教程之动作的基类Zend_Controller_Action详解

发布:smiling 来源: PHP粉丝网  添加日期:2021-07-13 15:43:42 浏览: 评论:0 

这篇文章主要介绍了Zend Framework教程之动作的基类Zend_Controller_Action的用法,结合实例形式详细分析了动作的基类Zend_Controller_Action具体功能,使用方法与相关注意事项,需要的朋友可以参考下。

本文实例讲述了Zend Framework教程之动作的基类Zend_Controller_Action。分享给大家供大家参考,具体如下:

Zend_Controller_Action的实现

Zend Framework的动作控制器需要继承Zend_Controller_Action,Zend_Controller_Action提供了动作控制器的基本功能,具体参考如下代码:

Zend_Controller_Action_Interface

  1. <?php 
  2. interface Zend_Controller_Action_Interface 
  3. { 
  4.   /** 
  5.    * Class constructor 
  6.    * 
  7.    * The request and response objects should be registered with the 
  8.    * controller, as should be any additional optional arguments; these will be 
  9.    * available via {@link getRequest()}, {@link getResponse()}, and 
  10.    * {@link getInvokeArgs()}, respectively. 
  11.    * 
  12.    * When overriding the constructor, please consider this usage as a best 
  13.    * practice and ensure that each is registered appropriately; the easiest 
  14.    * way to do so is to simply call parent::__construct($request, $response, 
  15.    * $invokeArgs). 
  16.    * 
  17.    * After the request, response, and invokeArgs are set, the 
  18.    * {@link $_helper helper broker} is initialized. 
  19.    * 
  20.    * Finally, {@link init()} is called as the final action of 
  21.    * instantiation, and may be safely overridden to perform initialization 
  22.    * tasks; as a general rule, override {@link init()} instead of the 
  23.    * constructor to customize an action controller's instantiation. 
  24.    * 
  25.    * @param Zend_Controller_Request_Abstract $request 
  26.    * @param Zend_Controller_Response_Abstract $response 
  27.    * @param array $invokeArgs Any additional invocation arguments 
  28.    * @return void 
  29.    */ 
  30.   public function __construct(Zend_Controller_Request_Abstract $request, 
  31.                 Zend_Controller_Response_Abstract $response, 
  32.                 array $invokeArgs = array()); 
  33.   /** 
  34.    * Dispatch the requested action 
  35.    * 
  36.    * @param string $action Method name of action 
  37.    * @return void 
  38.    */ 
  39.   public function dispatch($action); 
  40. } 

Zend_Controller_Action

  1. <?php 
  2. require_once 'Zend/Controller/Action/HelperBroker.php'; 
  3. require_once 'Zend/Controller/Action/Interface.php'; 
  4. require_once 'Zend/Controller/Front.php'; 
  5. abstract class Zend_Controller_Action implements Zend_Controller_Action_Interface 
  6. { 
  7.   protected $_classMethods; 
  8.   protected $_delimiters; 
  9.   protected $_invokeArgs = array(); 
  10.   protected $_frontController; 
  11.   protected $_request = null; 
  12.   protected $_response = null; 
  13.   public $viewSuffix = 'phtml'; 
  14.   public $view; 
  15.   protected $_helper = null; 
  16.   public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array()) 
  17.   { 
  18.     $this->setRequest($request) 
  19.        ->setResponse($response) 
  20.        ->_setInvokeArgs($invokeArgs); 
  21.     $this->_helper = new Zend_Controller_Action_HelperBroker($this); 
  22.     $this->init(); 
  23.   } 
  24.   public function init() 
  25.   { 
  26.   } 
  27.   public function initView() 
  28.   { 
  29.     if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { 
  30.       return $this->view; 
  31.     } 
  32.     require_once 'Zend/View/Interface.php'; 
  33.     if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) { 
  34.       return $this->view; 
  35.     } 
  36.     $request = $this->getRequest(); 
  37.     $module = $request->getModuleName(); 
  38.     $dirs  = $this->getFrontController()->getControllerDirectory(); 
  39.     if (emptyempty($module) || !isset($dirs[$module])) { 
  40.       $module = $this->getFrontController()->getDispatcher()->getDefaultModule(); 
  41.     } 
  42.     $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views'; 
  43.     if (!file_exists($baseDir) || !is_dir($baseDir)) { 
  44.       require_once 'Zend/Controller/Exception.php'; 
  45.       throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")'); 
  46.     } 
  47.     require_once 'Zend/View.php'; 
  48.     $this->view = new Zend_View(array('basePath' => $baseDir)); 
  49.     return $this->view; 
  50.   } 
  51.   public function render($action = null, $name = null, $noController = false) 
  52.   { 
  53.     if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { 
  54.       return $this->_helper->viewRenderer->render($action, $name, $noController); 
  55.     } 
  56.     $view  = $this->initView(); 
  57.     $script = $this->getViewScript($action, $noController); 
  58.     $this->getResponse()->appendBody( 
  59.       $view->render($script), 
  60.       $name 
  61.     ); 
  62.   } 
  63.   public function renderScript($script, $name = null) 
  64.   { 
  65.     if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { 
  66.       return $this->_helper->viewRenderer->renderScript($script, $name); 
  67.     } 
  68.     $view = $this->initView(); 
  69.     $this->getResponse()->appendBody( 
  70.       $view->render($script), 
  71.       $name 
  72.     ); 
  73.   } 
  74.   public function getViewScript($action = null, $noController = null) 
  75.   { 
  76.     if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { 
  77.       $viewRenderer = $this->_helper->getHelper('viewRenderer'); 
  78.       if (null !== $noController) { 
  79.         $viewRenderer->setNoController($noController); 
  80.       } 
  81.       return $viewRenderer->getViewScript($action); 
  82.     } 
  83.     $request = $this->getRequest(); 
  84.     if (null === $action) { 
  85.       $action = $request->getActionName(); 
  86.     } elseif (!is_string($action)) { 
  87.       require_once 'Zend/Controller/Exception.php'; 
  88.       throw new Zend_Controller_Exception('Invalid action specifier for view render'); 
  89.     } 
  90.     if (null === $this->_delimiters) { 
  91.       $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher(); 
  92.       $wordDelimiters = $dispatcher->getWordDelimiter(); 
  93.       $pathDelimiters = $dispatcher->getPathDelimiter(); 
  94.       $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters)); 
  95.     } 
  96.     $action = str_replace($this->_delimiters, '-', $action); 
  97.     $script = $action . '.' . $this->viewSuffix; 
  98.     if (!$noController) { 
  99.       $controller = $request->getControllerName(); 
  100.       $controller = str_replace($this->_delimiters, '-', $controller); 
  101.       $script = $controller . DIRECTORY_SEPARATOR . $script; 
  102.     } 
  103.     return $script; 
  104.   } 
  105.   public function getRequest() 
  106.   { 
  107.     return $this->_request; 
  108.   } 
  109.   public function setRequest(Zend_Controller_Request_Abstract $request) 
  110.   { 
  111.     $this->_request = $request; 
  112.     return $this; 
  113.   } 
  114.   public function getResponse() 
  115.   { 
  116.     return $this->_response; 
  117.   } 
  118.   public function setResponse(Zend_Controller_Response_Abstract $response) 
  119.   { 
  120.     $this->_response = $response; 
  121.     return $this; 
  122.   } 
  123.   protected function _setInvokeArgs(array $args = array()) 
  124.   { 
  125.     $this->_invokeArgs = $args; 
  126.     return $this; 
  127.   } 
  128.   public function getInvokeArgs() 
  129.   { 
  130.     return $this->_invokeArgs; 
  131.   } 
  132.   public function getInvokeArg($key) 
  133.   { 
  134.     if (isset($this->_invokeArgs[$key])) { 
  135.       return $this->_invokeArgs[$key]; 
  136.     } 
  137.     return null; 
  138.   } 
  139.   public function getHelper($helperName) 
  140.   { 
  141.     return $this->_helper->{$helperName}; 
  142.   } 
  143.   public function getHelperCopy($helperName) 
  144.   { 
  145.     return clone $this->_helper->{$helperName}; 
  146.   } 
  147.   public function setFrontController(Zend_Controller_Front $front) 
  148.   { 
  149.     $this->_frontController = $front; 
  150.     return $this; 
  151.   } 
  152.   public function getFrontController() 
  153.   { 
  154.     // Used cache version if found 
  155.     if (null !== $this->_frontController) { 
  156.       return $this->_frontController; 
  157.     } 
  158.     // Grab singleton instance, if class has been loaded 
  159.     if (class_exists('Zend_Controller_Front')) { 
  160.       $this->_frontController = Zend_Controller_Front::getInstance(); 
  161.       return $this->_frontController; 
  162.     } 
  163.     // Throw exception in all other cases 
  164.     require_once 'Zend/Controller/Exception.php'; 
  165.     throw new Zend_Controller_Exception('Front controller class has not been loaded'); 
  166.   } 
  167.   public function preDispatch() 
  168.   { 
  169.   } 
  170.   public function postDispatch() 
  171.   { 
  172.   } 
  173.   public function __call($methodName, $args) 
  174.   { 
  175.     require_once 'Zend/Controller/Action/Exception.php'; 
  176.     if ('Action' == substr($methodName, -6)) { 
  177.       $action = substr($methodName, 0, strlen($methodName) - 6); 
  178.       throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404); 
  179.     } 
  180.     throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500); 
  181.   } 
  182.   public function dispatch($action) 
  183.   { 
  184.     // Notify helpers of action preDispatch state 
  185.     $this->_helper->notifyPreDispatch(); 
  186.     $this->preDispatch(); 
  187.     if ($this->getRequest()->isDispatched()) { 
  188.       if (null === $this->_classMethods) { 
  189.         $this->_classMethods = get_class_methods($this); 
  190.       } 
  191.       // If pre-dispatch hooks introduced a redirect then stop dispatch 
  192.       // @see ZF-7496 
  193.       if (!($this->getResponse()->isRedirect())) { 
  194.         // preDispatch() didn't change the action, so we can continue 
  195.         if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) { 
  196.           if ($this->getInvokeArg('useCaseSensitiveActions')) { 
  197.             trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"'); 
  198.           } 
  199.           $this->$action(); 
  200.         } else { 
  201.           $this->__call($action, array()); 
  202.         } 
  203.       } 
  204.       $this->postDispatch(); 
  205.     } 
  206.     // whats actually important here is that this action controller is 
  207.     // shutting down, regardless of dispatching; notify the helpers of this 
  208.     // state 
  209.     $this->_helper->notifyPostDispatch(); 
  210.   } 
  211.   public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) 
  212.   { 
  213.     if (null !== $request) { 
  214.       $this->setRequest($request); 
  215.     } else { 
  216.       $request = $this->getRequest(); 
  217.     } 
  218.     if (null !== $response) { 
  219.       $this->setResponse($response); 
  220.     } 
  221.     $action = $request->getActionName(); 
  222.     if (emptyempty($action)) { 
  223.       $action = 'index'; 
  224.     } 
  225.     $action = $action . 'Action'; 
  226.     $request->setDispatched(true); 
  227.     $this->dispatch($action); 
  228.     return $this->getResponse(); 
  229.   } 
  230.   protected function _getParam($paramName, $default = null) 
  231.   { 
  232.     $value = $this->getRequest()->getParam($paramName); 
  233.      if ((null === $value || '' === $value) && (null !== $default)) { 
  234.       $value = $default; 
  235.     } 
  236.     return $value; 
  237.   } 
  238.   protected function _setParam($paramName, $value) 
  239.   { 
  240.     $this->getRequest()->setParam($paramName, $value); 
  241.     return $this; 
  242.   } 
  243.   protected function _hasParam($paramName) 
  244.   { 
  245.     return null !== $this->getRequest()->getParam($paramName); 
  246.   } 
  247.   protected function _getAllParams() 
  248.   { 
  249.     return $this->getRequest()->getParams(); 
  250.   } 
  251.   final protected function _forward($action, $controller = null, $module = null, array $params = null) 
  252.   { 
  253.     $request = $this->getRequest(); 
  254.     if (null !== $params) { 
  255.       $request->setParams($params); 
  256.     } 
  257.     if (null !== $controller) { 
  258.       $request->setControllerName($controller); 
  259.       // Module should only be reset if controller has been specified 
  260.       if (null !== $module) { 
  261.         $request->setModuleName($module); 
  262.       } 
  263.     } 
  264.     $request->setActionName($action) 
  265.         ->setDispatched(false); 
  266.   } 
  267.   protected function _redirect($url, array $options = array()) 
  268.   { 
  269.     $this->_helper->redirector->gotoUrl($url, $options); 
  270.   } 
  271. } 

Zend_Controller_Action提供了动作和视图的render功能,以及注册请求和响应对象,常用助手等等。

动作控制器的常用方法

在动作控制器中常用的方法和属性如下:

$this->_helper主要完成助手的相关操作例如:

只是局部控制器;当初始化加载时,对这个控制器的所有动作有效:

$this->_helper->viewRenderer->setNoRender(true);

全局:

$this->_helper->removeHelper('viewRenderer');

也是全局,但需要和本地版本协作,以便繁殖这个控制器:

Zend_Controller_Front::getInstance()->setParam('noViewRenderer', true);

通过设置ViewRenderer的noRender标记,可以简单地为一个独立的视图禁止解析(rendering):

  1. class FooController extends Zend_Controller_Action 
  2. { 
  3.   public function barAction() 
  4.   { 
  5.     // disable autorendering for this action only: 
  6.     $this->_helper->viewRenderer->setNoRender(); 
  7.   } 
  8. } 

禁止ViewRenderer的主要原因是如果你不需要视图对象或者如果你不通过视图脚本(例如,当使用动作控制器来司服网站服务协议如SOAP,XML-RPC或REST)来解析。大多数情况下,你不需要全局地禁止ViewRenderer,只选择性地在个别控制器或动作里禁止它。

请求对象和响应对象的相关操作

无数的对象和变量与对象一起注册,并且每个都有访问器方法。

请求对象:getRequest()可用来读取调用动作请求对象。

响应对象: getResponse()可用来读取收集最终响应的响应对象,一些典型的调用看起来象这样:

$this->getResponse()->setHeader('Content-Type', 'text/xml');

$this->getResponse()->appendBody($content);

调用参数:前端控制器可能把参数传给路由器、派遣器和动作控制器。为了读取这些参数,可使用getInvokeArg($key);另外,用getInvokeArgs()读取整个参数列表。

请求参数:请求对象手机请求参数,如任何_GET 或 _POST 参数,或者指定在URL的路径信息里的用户参数。为了读取这些参数,可使用_getParam($key)或_getAllParams()。也可以用_setParam()来设置请求参数;当转发到另外的动作时这很有用。

用_hasParam($key)来测试是否一个参数存在(对逻辑分支有用)。

Note: _getParam()可带有一个可选的第二个参数,如果它不是空的,就包含一个缺省的值。用它在读取值之前来消除对_hasParam() 的调用:

  1. // Use default value of 1 if id is not set 
  2. $id = $this->_getParam('id', 1); 
  3. // Instead of: 
  4. if ($this->_hasParam('id') { 
  5.   $id = $this->_getParam('id'); 
  6. } else { 
  7.   $id = 1; 
  8. } 

视图的相关操作

Zend_Controller_Action为视图继承提供了一个初步的灵活的机制。有两个方法来完成这个:initView() 和 render();前者松散地加载$view public 属性,后者基于当前请求的动作来解析视图,它们使用目录层次来决定脚本路径。

视图初始化

initView()初始化视图对象。为了读取视图对象,render()调用initView(),但它可以在任何时候被初始化;缺省地,它用Zend_View对象来组装$view属性,但任何实现Zend_View_Interface的类可以使用,如果$view已经被初始化,它就简单地返回属性。

缺省的实现使用下面假设的目录结构:

  1. applicationOrModule/ 
  2.     controllers/ 
  3.         IndexController.php 
  4.     views/ 
  5.         scripts/ 
  6.             index/ 
  7.                 index.phtml 
  8.         helpers/ 
  9.         filters/ 

换句话说,视图脚本假定放在views/scripts/子目录,同时假定 views子目录还包含兄弟功能(助手和过滤器)。确定视图脚本名称和路径时,先以 views/scripts/作为基路径,然后加上以视图脚本对应控制器命名的目录。

解析(Rendering)视图

render() 有下列特征:has the following signature:

string render(string $action = null,

string $name = null,

bool $noController = false);

render()解析视图脚本。如果没有传递参数,它假定请求的脚本是[controller]/[action].phtml (.phtml是$viewSuffix属性的值)。为$action传递一个值将解析在[controller]子目录中的模板。为用[controller]重写,传递一个true值给$noController。最后,模板被解析到响应对象;如果你希望解析到一个在响应对象里指定的named segment,传递一个值给$name。

Note: 因为控制器和动作名字里可能包含分隔符如'_'、 '.' 和 '-',当决定视图名字时,render()把它们规格化成 '-'.在内部,它使用派遣器的字和路径分隔符来做规格化。这样,对/foo.bar/baz-bat的请求将解析脚本foo-bar/baz-bat.phtml。如果动作方法包含camelCasing,记住当决定视图脚本文件名的时候,这将变成由'-'分隔的字。

一些例子:

  1. class MyController extends Zend_Controller_Action 
  2. { 
  3.   public function fooAction() 
  4.   { 
  5.     // Renders my/foo.phtml 
  6.     $this->render(); 
  7.     // Renders my/bar.phtml 
  8.     $this->render('bar'); 
  9.     // Renders baz.phtml 
  10.     $this->render('baz', null, true); 
  11.     // Renders my/login.phtml to the 'form' segment of the 
  12.     // response object 
  13.     $this->render('login', 'form'); 
  14.     // Renders site.phtml to the 'page' segment of the response 
  15.     // object; does not use the 'my/' subirectory 
  16.     $this->render('site', 'page', true); 
  17.   } 
  18.   public function bazBatAction() 
  19.   { 
  20.     // Renders my/baz-bat.phtml 
  21.     $this->render(); 
  22.   } 
  23. } 

其它

_forward($action, $controller = null, $module = null, array $params = null) :执行另外一个动作。如果在preDispatch()里调用,当前请求的动作将被跳过来支持新的动作。否则,在当前动作被处理之后,在_forward()请求的动作将被执行。

_redirect($url, array $options = array()):重定向到另外一个地方,这个方法用URL和一组可选的选项,缺省地,它执行HTTP 302 重定向。

选项可包括一个或多个下面这些:

exit:是否立即退出。如果被请求,它将干净地关闭任何打开的会话和执行重定向。

可以用setRedirectExit()访问器在控制器里全局地设置这个选项。

prependBase:是否预先考虑基础URL和URL提供的请求对象一起注册。

使用setRedirectPrependBase()访问器,在控制器里全局地设置这个选项。

code:在重定向时要用什么HTTP代码。缺省使用302;可以用从301到306之间的任何代码。

使用setRedirectCode()访问器,在控制器里全局地设置这个选项。

扩展自定义Zend_Controller_Action

为了创建动作控制器,设计上,Zend_Controller_Action 必须被继承。至少,需要定义控制器可能调用的动作方法。

除了为web应用程序创建有用的函数外,你可能发现在不同的控制器里重复同样的设置和实用方法;如果这样,创建一个继承(extends)Zend_Controller_Action 的基础类可能会解决问题。

Example #1 如何处理不存在的动作

如果控制器的请求包括一个未定义的动作方法,Zend_Controller_Action::__call()将被调用。__call()当然是PHP中用来重载方法的魔术方法。

缺省地,这个方法抛出一个Zend_Controller_Action_Exception 来表明在控制器里没有发现要求的方法。如果要求的方法以'Action'结尾,就假设一个动作被请求并且不存在;这样的错误导致带有代码为 404 的异常。所有其它方法导致带有代码为 500 的异常。这使你很容易地在错误句柄里区分是页面没有发现还是程序错误。

如果想执行其它操作,你应该重写这个函数。例如,如果你想显示错误信息,可以象下面这样来写:

  1. class MyController extends Zend_Controller_Action 
  2. { 
  3.   public function __call($method, $args) 
  4.   { 
  5.     if ('Action' == substr($method, -6)) { 
  6.       // If the action method was not found, render the error 
  7.       // template 
  8.       return $this->render('error'); 
  9.     } 
  10.     // all other methods throw an exception 
  11.     throw new Exception('Invalid method "' 
  12.               . $method 
  13.               . '" called', 
  14.               500); 
  15.   } 
  16. } 

另外的可能性就是你可能想转发到缺省控制页面:

  1. class MyController extends Zend_Controller_Action 
  2. { 
  3.   public function indexAction() 
  4.   { 
  5.     $this->render(); 
  6.   } 
  7.   public function __call($method, $args) 
  8.   { 
  9.     if ('Action' == substr($method, -6)) { 
  10.       // If the action method was not found, forward to the 
  11.       // index action 
  12.       return $this->_forward('index'); 
  13.     } 
  14.     // all other methods throw an exception 
  15.     throw new Exception('Invalid method "' 
  16.               . $method 
  17.               . '" called', 
  18.               500); 
  19.   } 
  20. } 

为了定制控制器,除了重写__call()以外,本章前面说涉及的初始化、实用程序、访问器、视图和派遣钩子等方法都可以被重写,作为例子,如果把视图对象保存到注册表里,你可能想用象下面的代码来修改initView():

  1. abstract class My_Base_Controller extends Zend_Controller_Action 
  2. { 
  3.   public function initView() 
  4.   { 
  5.     if (null === $this->view) { 
  6.       if (Zend_Registry::isRegistered('view')) { 
  7.         $this->view = Zend_Registry::get('view'); 
  8.       } else { 
  9.         $this->view = new Zend_View(); 
  10.         $this->view->setBasePath(dirname(__FILE__) . '/../views'); 
  11.       } 
  12.     } 
  13.     return $this->view; 
  14.   } 
  15. }

Tags: Zend_Controller_Action

分享到: