先来看一个正常的控制器前端的定义:
$front = Zend_Controller_Front::getInstance ();
$front->setBaseUrl ( '/' )
->setParam ( 'noViewRenderer', true )
->setControllerDirectory ( './application/modules/admin/controllers' )
->throwExceptions ( true )
->dispatch ();
第一行,获取控制器前端实例
第二行,设置 baseUrl
第三行,禁用ViewRenderer自动渲染
第四行,设置控制器目录
第五行,分发
这种模式下,如果访问一个URL中含有无效的 Controller 或 Action ,那么ZF就会抛出异常。于是,如何处理这种异常就非常有必要了。
ZF手册中也有相关的说明,只是没有给出完整的代码。在此,自己记录一下,也希望对其他的朋友能有所帮助。
方法一、通过 Zend_Controller_Front::throwExceptions()
如下代码段:
$front->setBaseUrl ( '/' )
->setParam ( 'noViewRenderer', true )
->setControllerDirectory ( './application/modules/admin/controllers' )
->throwExceptions ( true );
try{
$front->dispatch();
} catch (Exception $e) {
echo '显示错误信息';
}
其中主要是 throwExceptions ( true ); 用于设置异常由开发人员来处理。
方法二、通过 Zend_Controller_Front::returnResponse() 和 Zend_Controller_Response_Abstract::isException()
如下代码段:
$front->setParam('noErrorHandler', true)
->throwExceptions(false)
->setControllerDirectory ( './application/modules/admin/controllers' )
->returnResponse(true);
$response = $front->dispatch();
if ($response->isException()) {
$exceptions = $response->getException();
echo handleException($exceptions[0]);
} else {
echo $response;
}
function handleException(Exception $e)
{
switch ($e->getCode()) {
case 500: {
if (!include_once('./resource/html/500.html')) {
@header("HTTP/1.x 500 Internal Server Error");
@header('Status: 500 Internal Server Error');
}
exit;
break;
}
default: {
if (!include_once('./resource/html/404.html')) {
@header('HTTP/1.x 404 Not Found');
@header('Status: 404 Not Found');
}
exit;
break;
}
}
}
原理就是捕获异常的类型,然后重定向到错误页面。以上二种方法,都是通过控制器前端来实现的,而下面则是继承相应的类来实现。
方法三、继承 Zend_Controller_Action,
并重写 __call()
方法
class My_Controller_Action extends Zend_Controller_Action
{
public function __call($method, $args)
{
if ('Action' == substr($method, -6)) {
$controller = $this->getRequest()->getControllerName();
$url = '/' . $controller . '/index';
return $this->_redirect($url);
}
throw new Exception('Invalid method');
}
}
继承 Zend_Controller_Action 类,并重写魔术方法 __call(),然后所有的 Action 都继承这个子类,对于无效的 Action 就可以在 __call 里处理,比如可以重写向到一个错误页,也可以重定向到默认页。此处重定向到默认页。
方法五、继承 Zend_Controller_Dispatcher, 并重写 getAction()
class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
{
public function getAction($request)
{
$action = $request->getActionName();
if (empty($action)) {
$action = $this->getDefaultAction();
$request->setActionName($action);
$action = $this->formatActionName($action);
} else {
$controller = $this->getController();
$action = $this->formatActionName($action);
if (!method_exists($controller, $action)) {
$action = $this->getDefaultAction();
$request->setActionName($action);
$action = $this->formatActionName($action);
}
}
return $action;
}
}
分发器就是在用户请求数据时,先取得模块名、控制器名、动作名以及参数等,然后实例化相应的控件器,并调用相应动作的整个过程。
这里,去继承分发器类,就可以在“调用”动作时来设置来如何调用。如代码中的,先判断 Action 是否有效,有效就调用这个 Action,无效而设置成默认的Action。
继承后,就需要通知控制器前端,如下代码:
$myDispatcher = new My_Controller_Dispatcher();
$front->setDispatcher($myDispatcher);
这样就为系统设置了一个自己定义的分发器,并用此分发器处理无效的Action。
方法六、使用Zend_Controller_Action::preDispatch()
或者Zend_Controller_Plugin_Abstract::preDispatch()
来识别无效的动作。
class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
$controller = $dispatcher->getController($request);
if (!$controller) {
$controller = $dispatcher->getDefaultControllerName($request);
}
$action = $dispatcher->getAction($request);
if (!method_exists($controller, $action)) {
$defaultAction = $dispatcher->getDefaultAction();
$controllerName = $request->getControllerName();
$response = Zend_Controller_Front::getInstance()->getResponse();
$response->setRedirect('/' . $controllerName .
'/' . $defaultAction);
$response->sendHeaders();
exit;
}
}
}
preDispatch 是在分发之前调用,这里就是先判断 Controller 是否有效,如果无效就设置成默认的 Controller,然后再分发下去。