Zend Framework教程之动作的基类Zend_Controller_Action详解
本文实例讲述了ZendFramework教程之动作的基类Zend_Controller_Action。分享给大家供大家参考,具体如下:
Zend_Controller_Action的实现
ZendFramework的动作控制器需要继承Zend_Controller_Action,Zend_Controller_Action提供了动作控制器的基本功能,具体参考如下代码:
Zend_Controller_Action_Interface
<?php
interfaceZend_Controller_Action_Interface
{
/**
*Classconstructor
*
*Therequestandresponseobjectsshouldberegisteredwiththe
*controller,asshouldbeanyadditionaloptionalarguments;thesewillbe
*availablevia{@linkgetRequest()},{@linkgetResponse()},and
*{@linkgetInvokeArgs()},respectively.
*
*Whenoverridingtheconstructor,pleaseconsiderthisusageasabest
*practiceandensurethateachisregisteredappropriately;theeasiest
*waytodosoistosimplycallparent::__construct($request,$response,
*$invokeArgs).
*
*Aftertherequest,response,andinvokeArgsareset,the
*{@link$_helperhelperbroker}isinitialized.
*
*Finally,{@linkinit()}iscalledasthefinalactionof
*instantiation,andmaybesafelyoverriddentoperforminitialization
*tasks;asageneralrule,override{@linkinit()}insteadofthe
*constructortocustomizeanactioncontroller'sinstantiation.
*
*@paramZend_Controller_Request_Abstract$request
*@paramZend_Controller_Response_Abstract$response
*@paramarray$invokeArgsAnyadditionalinvocationarguments
*@returnvoid
*/
publicfunction__construct(Zend_Controller_Request_Abstract$request,
Zend_Controller_Response_Abstract$response,
array$invokeArgs=array());
/**
*Dispatchtherequestedaction
*
*@paramstring$actionMethodnameofaction
*@returnvoid
*/
publicfunctiondispatch($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';
abstractclassZend_Controller_ActionimplementsZend_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;
publicfunction__construct(Zend_Controller_Request_Abstract$request,Zend_Controller_Response_Abstract$response,array$invokeArgs=array())
{
$this->setRequest($request)
->setResponse($response)
->_setInvokeArgs($invokeArgs);
$this->_helper=newZend_Controller_Action_HelperBroker($this);
$this->init();
}
publicfunctioninit()
{
}
publicfunctioninitView()
{
if(!$this->getInvokeArg('noViewRenderer')&&$this->_helper->hasHelper('viewRenderer')){
return$this->view;
}
require_once'Zend/View/Interface.php';
if(isset($this->view)&&($this->viewinstanceofZend_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';
thrownewZend_Controller_Exception('Missingbaseviewdirectory("'.$baseDir.'")');
}
require_once'Zend/View.php';
$this->view=newZend_View(array('basePath'=>$baseDir));
return$this->view;
}
publicfunctionrender($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
);
}
publicfunctionrenderScript($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
);
}
publicfunctiongetViewScript($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';
thrownewZend_Controller_Exception('Invalidactionspecifierforviewrender');
}
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;
}
publicfunctiongetRequest()
{
return$this->_request;
}
publicfunctionsetRequest(Zend_Controller_Request_Abstract$request)
{
$this->_request=$request;
return$this;
}
publicfunctiongetResponse()
{
return$this->_response;
}
publicfunctionsetResponse(Zend_Controller_Response_Abstract$response)
{
$this->_response=$response;
return$this;
}
protectedfunction_setInvokeArgs(array$args=array())
{
$this->_invokeArgs=$args;
return$this;
}
publicfunctiongetInvokeArgs()
{
return$this->_invokeArgs;
}
publicfunctiongetInvokeArg($key)
{
if(isset($this->_invokeArgs[$key])){
return$this->_invokeArgs[$key];
}
returnnull;
}
publicfunctiongetHelper($helperName)
{
return$this->_helper->{$helperName};
}
publicfunctiongetHelperCopy($helperName)
{
returnclone$this->_helper->{$helperName};
}
publicfunctionsetFrontController(Zend_Controller_Front$front)
{
$this->_frontController=$front;
return$this;
}
publicfunctiongetFrontController()
{
//Usedcacheversioniffound
if(null!==$this->_frontController){
return$this->_frontController;
}
//Grabsingletoninstance,ifclasshasbeenloaded
if(class_exists('Zend_Controller_Front')){
$this->_frontController=Zend_Controller_Front::getInstance();
return$this->_frontController;
}
//Throwexceptioninallothercases
require_once'Zend/Controller/Exception.php';
thrownewZend_Controller_Exception('Frontcontrollerclasshasnotbeenloaded');
}
publicfunctionpreDispatch()
{
}
publicfunctionpostDispatch()
{
}
publicfunction__call($methodName,$args)
{
require_once'Zend/Controller/Action/Exception.php';
if('Action'==substr($methodName,-6)){
$action=substr($methodName,0,strlen($methodName)-6);
thrownewZend_Controller_Action_Exception(sprintf('Action"%s"doesnotexistandwasnottrappedin__call()',$action),404);
}
thrownewZend_Controller_Action_Exception(sprintf('Method"%s"doesnotexistandwasnottrappedin__call()',$methodName),500);
}
publicfunctiondispatch($action)
{
//NotifyhelpersofactionpreDispatchstate
$this->_helper->notifyPreDispatch();
$this->preDispatch();
if($this->getRequest()->isDispatched()){
if(null===$this->_classMethods){
$this->_classMethods=get_class_methods($this);
}
//Ifpre-dispatchhooksintroducedaredirectthenstopdispatch
//@seeZF-7496
if(!($this->getResponse()->isRedirect())){
//preDispatch()didn'tchangetheaction,sowecancontinue
if($this->getInvokeArg('useCaseSensitiveActions')||in_array($action,$this->_classMethods)){
if($this->getInvokeArg('useCaseSensitiveActions')){
trigger_error('Usingcasesensitiveactionswithoutwordseparatorsisdeprecated;pleasedonotrelyonthis"feature"');
}
$this->$action();
}else{
$this->__call($action,array());
}
}
$this->postDispatch();
}
//whatsactuallyimportanthereisthatthisactioncontrolleris
//shuttingdown,regardlessofdispatching;notifythehelpersofthis
//state
$this->_helper->notifyPostDispatch();
}
publicfunctionrun(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();
}
protectedfunction_getParam($paramName,$default=null)
{
$value=$this->getRequest()->getParam($paramName);
if((null===$value||''===$value)&&(null!==$default)){
$value=$default;
}
return$value;
}
protectedfunction_setParam($paramName,$value)
{
$this->getRequest()->setParam($paramName,$value);
return$this;
}
protectedfunction_hasParam($paramName)
{
returnnull!==$this->getRequest()->getParam($paramName);
}
protectedfunction_getAllParams()
{
return$this->getRequest()->getParams();
}
finalprotectedfunction_forward($action,$controller=null,$module=null,array$params=null)
{
$request=$this->getRequest();
if(null!==$params){
$request->setParams($params);
}
if(null!==$controller){
$request->setControllerName($controller);
//Moduleshouldonlyberesetifcontrollerhasbeenspecified
if(null!==$module){
$request->setModuleName($module);
}
}
$request->setActionName($action)
->setDispatched(false);
}
protectedfunction_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):
classFooControllerextendsZend_Controller_Action
{
publicfunctionbarAction()
{
//disableautorenderingforthisactiononly:
$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()的调用:
//Usedefaultvalueof1ifidisnotset
$id=$this->_getParam('id',1);
//Insteadof:
if($this->_hasParam('id'){
$id=$this->_getParam('id');
}else{
$id=1;
}
视图的相关操作
Zend_Controller_Action为视图继承提供了一个初步的灵活的机制。有两个方法来完成这个:initView()和render();前者松散地加载$viewpublic属性,后者基于当前请求的动作来解析视图,它们使用目录层次来决定脚本路径。
视图初始化
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()有下列特征:hasthefollowingsignature:
stringrender(string$action=null, string$name=null, bool$noController=false);
render()解析视图脚本。如果没有传递参数,它假定请求的脚本是[controller]/[action].phtml(.phtml是$viewSuffix属性的值)。为$action传递一个值将解析在[controller]子目录中的模板。为用[controller]重写,传递一个true值给$noController。最后,模板被解析到响应对象;如果你希望解析到一个在响应对象里指定的namedsegment,传递一个值给$name。
Note:因为控制器和动作名字里可能包含分隔符如'_'、'.'和'-',当决定视图名字时,render()把它们规格化成'-'.在内部,它使用派遣器的字和路径分隔符来做规格化。这样,对/foo.bar/baz-bat的请求将解析脚本foo-bar/baz-bat.phtml。如果动作方法包含camelCasing,记住当决定视图脚本文件名的时候,这将变成由'-'分隔的字。
一些例子:
classMyControllerextendsZend_Controller_Action
{
publicfunctionfooAction()
{
//Rendersmy/foo.phtml
$this->render();
//Rendersmy/bar.phtml
$this->render('bar');
//Rendersbaz.phtml
$this->render('baz',null,true);
//Rendersmy/login.phtmltothe'form'segmentofthe
//responseobject
$this->render('login','form');
//Renderssite.phtmltothe'page'segmentoftheresponse
//object;doesnotusethe'my/'subirectory
$this->render('site','page',true);
}
publicfunctionbazBatAction()
{
//Rendersmy/baz-bat.phtml
$this->render();
}
}
其它
_forward($action,$controller=null,$module=null,array$params=null):执行另外一个动作。如果在preDispatch()里调用,当前请求的动作将被跳过来支持新的动作。否则,在当前动作被处理之后,在_forward()请求的动作将被执行。
_redirect($url,array$options=array()):重定向到另外一个地方。这个方法用URL和一组可选的选项。缺省地,它执行HTTP302重定向。
选项可包括一个或多个下面这些:
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的异常。这使你很容易地在错误句柄里区分是页面没有发现还是程序错误。
如果想执行其它操作,你应该重写这个函数。例如,如果你想显示错误信息,可以象下面这样来写:
classMyControllerextendsZend_Controller_Action
{
publicfunction__call($method,$args)
{
if('Action'==substr($method,-6)){
//Iftheactionmethodwasnotfound,rendertheerror
//template
return$this->render('error');
}
//allothermethodsthrowanexception
thrownewException('Invalidmethod"'
.$method
.'"called',
500);
}
}
另外的可能性就是你可能想转发到缺省控制页面:
classMyControllerextendsZend_Controller_Action
{
publicfunctionindexAction()
{
$this->render();
}
publicfunction__call($method,$args)
{
if('Action'==substr($method,-6)){
//Iftheactionmethodwasnotfound,forwardtothe
//indexaction
return$this->_forward('index');
}
//allothermethodsthrowanexception
thrownewException('Invalidmethod"'
.$method
.'"called',
500);
}
}
为了定制控制器,除了重写__call()以外,本章前面说涉及的初始化、实用程序、访问器、视图和派遣钩子等方法都可以被重写。作为例子,如果把视图对象保存到注册表里,你可能想用象下面的代码来修改initView():
abstractclassMy_Base_ControllerextendsZend_Controller_Action
{
publicfunctioninitView()
{
if(null===$this->view){
if(Zend_Registry::isRegistered('view')){
$this->view=Zend_Registry::get('view');
}else{
$this->view=newZend_View();
$this->view->setBasePath(dirname(__FILE__).'/../views');
}
}
return$this->view;
}
}
更多关于zend相关内容感兴趣的读者可查看本站专题:《ZendFrameWork框架入门教程》、《php优秀开发框架总结》、《Yii框架入门及常用技巧总结》、《ThinkPHP入门教程》、《php面向对象程序设计入门教程》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。