Zend Framework教程之动作的基类Zend_Controller_Action详解_php实例
本文实例讲述了Zend Framework教程之动作的基类Zend_Controller_Action。分享给大家供大家参考,具体如下:
Zend_Controller_Action的实现
Zend Framework的动作控制器需要继承Zend_Controller_Action,Zend_Controller_Action提供了动作控制器的基本功能,具体参考如下代码:
Zend_Controller_Action_Interface
<?php interface 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
<?php require_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 found if (null !== $this->_frontController) { return $this->_frontController; } // Grab singleton instance, if class has been loaded if (class_exists('Zend_Controller_Front')) { $this->_frontController = Zend_Controller_Front::getInstance(); return $this->_frontController; } // Throw exception in all other cases require_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-7496 if (!($this->getResponse()->isRedirect())) { // preDispatch() didn't change the action, so we can continue if ($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 specified if (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 // template return $this->render('error'); } // all other methods throw an exception throw 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 action return $this->_forward('index'); } // all other methods throw an exception throw 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程序设计有所帮助。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

.NET Framework 4 is required by developers and end users to run the latest versions of applications on Windows. However, while downloading and installing .NET Framework 4, many users complained that the installer stopped midway, displaying the following error message - " .NET Framework 4 has not been installed because Download failed with error code 0x800c0006 ". If you are also experiencing it while installing .NETFramework4 on your device then you are at the right place

Whenever your Windows 11 or Windows 10 PC has an upgrade or update issue, you will usually see an error code indicating the actual reason behind the failure. However, sometimes confusion can arise when an upgrade or update fails without an error code being displayed. With handy error codes, you know exactly where the problem is so you can try to fix it. But since no error code appears, it becomes challenging to identify the issue and resolve it. This will take up a lot of your time to simply find out the reason behind the error. In this case, you can try using a dedicated tool called SetupDiag provided by Microsoft that helps you easily identify the real reason behind the error.
![SCNotification has stopped working [5 steps to fix it]](https://img.php.cn/upload/article/000/887/227/168433050522031.png?x-oss-process=image/resize,m_fill,h_207,w_330)
As a Windows user, you are likely to encounter SCNotification has stopped working error every time you start your computer. SCNotification.exe is a Microsoft system notification file that crashes every time you start your PC due to permission errors and network failures. This error is also known by its problematic event name. So you might not see this as SCNotification having stopped working, but as bug clr20r3. In this article, we will explore all the steps you need to take to fix SCNotification has stopped working so that it doesn’t bother you again. What is SCNotification.e

Microsoft Windows users who have installed Microsoft.NET version 4.5.2, 4.6, or 4.6.1 must install a newer version of the Microsoft Framework if they want Microsoft to support the framework through future product updates. According to Microsoft, all three frameworks will cease support on April 26, 2022. After the support date ends, the product will not receive "security fixes or technical support." Most home devices are kept up to date through Windows updates. These devices already have newer versions of frameworks installed, such as .NET Framework 4.8. Devices that are not updating automatically may

It's been a week since we talked about the new safe mode bug affecting users who installed KB5012643 for Windows 11. This pesky issue didn't appear on the list of known issues Microsoft posted on launch day, thus catching everyone by surprise. Well, just when you thought things couldn't get any worse, Microsoft drops another bomb for users who have installed this cumulative update. Windows 11 Build 22000.652 causes more problems So the tech company is warning Windows 11 users that they may experience problems launching and using some .NET Framework 3.5 applications. Sound familiar? But please don't be surprised

How to use ACL (AccessControlList) for permission control in Zend Framework Introduction: In a web application, permission control is a crucial function. It ensures that users can only access the pages and features they are authorized to access and prevents unauthorized access. The Zend framework provides a convenient way to implement permission control, using the ACL (AccessControlList) component. This article will introduce how to use ACL in Zend Framework

PHP implementation framework: ZendFramework introductory tutorial ZendFramework is an open source website framework developed by PHP and is currently maintained by ZendTechnologies. ZendFramework adopts the MVC design pattern and provides a series of reusable code libraries to serve the implementation of Web2.0 applications and Web Serve. ZendFramework is very popular and respected by PHP developers and has a wide range of

According to news on December 9, Cooler Master recently demonstrated a mini chassis kit in cooperation with notebook modular solution provider Framework at a demonstration event at the Taipei Compute Show. The unique thing about this kit is that it can be compatible with and Install the motherboard from the framework notebook. Currently, this product has begun to be sold on the market, priced at 39 US dollars, which is equivalent to approximately 279 yuan at the current exchange rate. The model number of this chassis kit is named "frameWORKMAINBOARDCASE". In terms of design, it embodies the ultimate compactness and practicality, measuring only 297x133x15 mm. Its original design is to be able to seamlessly connect to framework notebooks
