Welcome 微信登录

首页 / 网页编程 / PHP / Zend Framework教程之动作的基类Zend_Controller_Action详解

本文实例讲述了Zend Framework教程之动作的基类Zend_Controller_Action。分享给大家供大家参考,具体如下:
Zend_Controller_Action的实现
Zend Framework的动作控制器需要继承Zend_Controller_Action,Zend_Controller_Action提供了动作控制器的基本功能,具体参考如下代码:
Zend_Controller_Action_Interface
<?phpinterface Zend_Controller_Action_Interface{/** * Class constructor * * The request and response objects should be registered with the * controller, as should be any additional optional arguments; these will be * available via {@link getRequest()}, {@link getResponse()}, and * {@link getInvokeArgs()}, respectively. * * When overriding the constructor, please consider this usage as a best * practice and ensure that each is registered appropriately; the easiest * way to do so is to simply call parent::__construct($request, $response, * $invokeArgs). * * After the request, response, and invokeArgs are set, the * {@link $_helper helper broker} is initialized. * * Finally, {@link init()} is called as the final action of * instantiation, and may be safely overridden to perform initialization * tasks; as a general rule, override {@link init()} instead of the * constructor to customize an action controller"s instantiation. * * @param Zend_Controller_Request_Abstract $request * @param Zend_Controller_Response_Abstract $response * @param array $invokeArgs Any additional invocation arguments * @return void */public function __construct(Zend_Controller_Request_Abstract $request,Zend_Controller_Response_Abstract $response,array $invokeArgs = array());/** * Dispatch the requested action * * @param string $action Method name of action * @return void */public function dispatch($action);}
Zend_Controller_Action
<?phprequire_once "Zend/Controller/Action/HelperBroker.php";require_once "Zend/Controller/Action/Interface.php";require_once "Zend/Controller/Front.php";abstract class Zend_Controller_Action implements Zend_Controller_Action_Interface{protected $_classMethods;protected $_delimiters;protected $_invokeArgs = array();protected $_frontController;protected $_request = null;protected $_response = null;public $viewSuffix = "phtml";public $view;protected $_helper = null;public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array()){$this->setRequest($request) ->setResponse($response) ->_setInvokeArgs($invokeArgs);$this->_helper = new Zend_Controller_Action_HelperBroker($this);$this->init();}public function init(){}public function initView(){if (!$this->getInvokeArg("noViewRenderer") && $this->_helper->hasHelper("viewRenderer")) {return $this->view;}require_once "Zend/View/Interface.php";if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) {return $this->view;}$request = $this->getRequest();$module = $request->getModuleName();$dirs= $this->getFrontController()->getControllerDirectory();if (empty($module) || !isset($dirs[$module])) {$module = $this->getFrontController()->getDispatcher()->getDefaultModule();}$baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . "views";if (!file_exists($baseDir) || !is_dir($baseDir)) {require_once "Zend/Controller/Exception.php";throw new Zend_Controller_Exception("Missing base view directory ("" . $baseDir . "")");}require_once "Zend/View.php";$this->view = new Zend_View(array("basePath" => $baseDir));return $this->view;}public function render($action = null, $name = null, $noController = false){if (!$this->getInvokeArg("noViewRenderer") && $this->_helper->hasHelper("viewRenderer")) {return $this->_helper->viewRenderer->render($action, $name, $noController);}$view= $this->initView();$script = $this->getViewScript($action, $noController);$this->getResponse()->appendBody($view->render($script),$name);}public function renderScript($script, $name = null){if (!$this->getInvokeArg("noViewRenderer") && $this->_helper->hasHelper("viewRenderer")) {return $this->_helper->viewRenderer->renderScript($script, $name);}$view = $this->initView();$this->getResponse()->appendBody($view->render($script),$name);}public function getViewScript($action = null, $noController = null){if (!$this->getInvokeArg("noViewRenderer") && $this->_helper->hasHelper("viewRenderer")) {$viewRenderer = $this->_helper->getHelper("viewRenderer");if (null !== $noController) {$viewRenderer->setNoController($noController);}return $viewRenderer->getViewScript($action);}$request = $this->getRequest();if (null === $action) {$action = $request->getActionName();} elseif (!is_string($action)) {require_once "Zend/Controller/Exception.php";throw new Zend_Controller_Exception("Invalid action specifier for view render");}if (null === $this->_delimiters) {$dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();$wordDelimiters = $dispatcher->getWordDelimiter();$pathDelimiters = $dispatcher->getPathDelimiter();$this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters));}$action = str_replace($this->_delimiters, "-", $action);$script = $action . "." . $this->viewSuffix;if (!$noController) {$controller = $request->getControllerName();$controller = str_replace($this->_delimiters, "-", $controller);$script = $controller . DIRECTORY_SEPARATOR . $script;}return $script;}public function getRequest(){return $this->_request;}public function setRequest(Zend_Controller_Request_Abstract $request){$this->_request = $request;return $this;}public function getResponse(){return $this->_response;}public function setResponse(Zend_Controller_Response_Abstract $response){$this->_response = $response;return $this;}protected function _setInvokeArgs(array $args = array()){$this->_invokeArgs = $args;return $this;}public function getInvokeArgs(){return $this->_invokeArgs;}public function getInvokeArg($key){if (isset($this->_invokeArgs[$key])) {return $this->_invokeArgs[$key];}return null;}public function getHelper($helperName){return $this->_helper->{$helperName};}public function getHelperCopy($helperName){return clone $this->_helper->{$helperName};}public function setFrontController(Zend_Controller_Front $front){$this->_frontController = $front;return $this;}public function getFrontController(){// Used cache version if foundif (null !== $this->_frontController) {return $this->_frontController;}// Grab singleton instance, if class has been loadedif (class_exists("Zend_Controller_Front")) {$this->_frontController = Zend_Controller_Front::getInstance();return $this->_frontController;}// Throw exception in all other casesrequire_once "Zend/Controller/Exception.php";throw new Zend_Controller_Exception("Front controller class has not been loaded");}public function preDispatch(){}public function postDispatch(){}public function __call($methodName, $args){require_once "Zend/Controller/Action/Exception.php";if ("Action" == substr($methodName, -6)) {$action = substr($methodName, 0, strlen($methodName) - 6);throw new Zend_Controller_Action_Exception(sprintf("Action "%s" does not exist and was not trapped in __call()", $action), 404);}throw new Zend_Controller_Action_Exception(sprintf("Method "%s" does not exist and was not trapped in __call()", $methodName), 500);}public function dispatch($action){// Notify helpers of action preDispatch state$this->_helper->notifyPreDispatch();$this->preDispatch();if ($this->getRequest()->isDispatched()) {if (null === $this->_classMethods) {$this->_classMethods = get_class_methods($this);}// If pre-dispatch hooks introduced a redirect then stop dispatch// @see ZF-7496if (!($this->getResponse()->isRedirect())) {// preDispatch() didn"t change the action, so we can continueif ($this->getInvokeArg("useCaseSensitiveActions") || in_array($action, $this->_classMethods)) {if ($this->getInvokeArg("useCaseSensitiveActions")) {trigger_error("Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"");}$this->$action();} else {$this->__call($action, array());}}$this->postDispatch();}// whats actually important here is that this action controller is// shutting down, regardless of dispatching; notify the helpers of this// state$this->_helper->notifyPostDispatch();}public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null){if (null !== $request) {$this->setRequest($request);} else {$request = $this->getRequest();}if (null !== $response) {$this->setResponse($response);}$action = $request->getActionName();if (empty($action)) {$action = "index";}$action = $action . "Action";$request->setDispatched(true);$this->dispatch($action);return $this->getResponse();}protected function _getParam($paramName, $default = null){$value = $this->getRequest()->getParam($paramName); if ((null === $value || "" === $value) && (null !== $default)) {$value = $default;}return $value;}protected function _setParam($paramName, $value){$this->getRequest()->setParam($paramName, $value);return $this;}protected function _hasParam($paramName){return null !== $this->getRequest()->getParam($paramName);}protected function _getAllParams(){return $this->getRequest()->getParams();}final protected function _forward($action, $controller = null, $module = null, array $params = null){$request = $this->getRequest();if (null !== $params) {$request->setParams($params);}if (null !== $controller) {$request->setControllerName($controller);// Module should only be reset if controller has been specifiedif (null !== $module) {$request->setModuleName($module);}}$request->setActionName($action)->setDispatched(false);}protected function _redirect($url, array $options = array()){$this->_helper->redirector->gotoUrl($url, $options);}}
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):
class FooController extends Zend_Controller_Action{public function barAction(){// disable autorendering for this action only:$this->_helper->viewRenderer->setNoRender();}}
禁止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() 的调用:
// Use default value of 1 if id is not set$id = $this->_getParam("id", 1);// Instead of:if ($this->_hasParam("id") {$id = $this->_getParam("id");} else {$id = 1;}
视图的相关操作
Zend_Controller_Action为视图继承提供了一个初步的灵活的机制。有两个方法来完成这个:initView() 和 render();前者松散地加载$view public 属性,后者基于当前请求的动作来解析视图,它们使用目录层次来决定脚本路径。
视图初始化
initView()初始化视图对象。为了读取视图对象,render()调用initView(),但它可以在任何时候被初始化;缺省地,它用Zend_View对象来组装$view属性,但任何实现Zend_View_Interface的类可以使用。如果$view已经被初始化,它就简单地返回属性。
缺省的实现使用下面假设的目录结构:
applicationOrModule/
    controllers/
        IndexController.php
    views/
        scripts/
            index/
                index.phtml
        helpers/
        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,记住当决定视图脚本文件名的时候,这将变成由"-"分隔的字。
一些例子:
class MyController extends Zend_Controller_Action{public function fooAction(){// Renders my/foo.phtml$this->render();// Renders my/bar.phtml$this->render("bar");// Renders baz.phtml$this->render("baz", null, true);// Renders my/login.phtml to the "form" segment of the// response object$this->render("login", "form");// Renders site.phtml to the "page" segment of the response// object; does not use the "my/" subirectory$this->render("site", "page", true);}public function bazBatAction(){// Renders my/baz-bat.phtml$this->render();}}
其它
_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 的异常。这使你很容易地在错误句柄里区分是页面没有发现还是程序错误。
如果想执行其它操作,你应该重写这个函数。例如,如果你想显示错误信息,可以象下面这样来写:
class MyController extends Zend_Controller_Action{public function __call($method, $args){if ("Action" == substr($method, -6)) {// If the action method was not found, render the error// templatereturn $this->render("error");}// all other methods throw an exceptionthrow new Exception("Invalid method "". $method. "" called",500);}}
另外的可能性就是你可能想转发到缺省控制页面:
class MyController extends Zend_Controller_Action{public function indexAction(){$this->render();}public function __call($method, $args){if ("Action" == substr($method, -6)) {// If the action method was not found, forward to the// index actionreturn $this->_forward("index");}// all other methods throw an exceptionthrow new Exception("Invalid method "". $method. "" called",500);}}
为了定制控制器,除了重写__call()以外,本章前面说涉及的初始化、实用程序、访问器、视图和派遣钩子等方法都可以被重写。作为例子,如果把视图对象保存到注册表里,你可能想用象下面的代码来修改initView():
abstract class My_Base_Controller extends Zend_Controller_Action{public function initView(){if (null === $this->view) {if (Zend_Registry::isRegistered("view")) {$this->view = Zend_Registry::get("view");} else {$this->view = new Zend_View();$this->view->setBasePath(dirname(__FILE__) . "/../views");}}return $this->view;}}
更多关于zend相关内容感兴趣的读者可查看本站专题:《Zend FrameWork框架入门教程》、《php优秀开发框架总结》、《Yii框架入门及常用技巧总结》、《ThinkPHP入门教程》、《php面向对象程序设计入门教程》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。