先来看一个正常的控制器前端的定义:
$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,然后再分发下去。