/** * Handle errors and exceptions * * If the 'noErrorHandler' front Controller flag has been set, * returns early. * * @param Zend_Controller_Request_Abstract $request * @return void */ protected function _handleError(RThink_Controller_Request $request, RThink_Controller_Response $response) { $frontController = RThink_Controller_Front::getInstance(); if ($frontController->getParam('noErrorHandler')) { return; } if ($this->_isInsideErrorHandlerLoop) { $exceptions = $response->getException(); if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) { // Exception thrown by error handler; tell the front Controller to throw it $frontController->throwExceptions(true); throw array_pop($exceptions); } } // check for an exception AND allow the error handler Controller the option to forward if ($response->isException() && !$this->_isInsideErrorHandlerLoop) { $this->_isInsideErrorHandlerLoop = true; // Get exception information $error = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); $exceptions = $response->getException(); $exception = $exceptions[0]; $error->exception = $exception; $exceptionType = get_class($exception); $error->exception = $exception; switch ($exceptionType) { case 'RThink_Controller_Router_Exception': if (404 == $exception->getCode()) { $error->type = self::EXCEPTION_NO_ROUTE; } else { $error->type = self::EXCEPTION_OTHER; } break; case 'RThink_Controller_Dispatcher_Exception': $error->type = self::EXCEPTION_NO_CONTROLLER; break; case 'RThink_Controller_Action_Exception': if (404 == $exception->getCode()) { $error->type = self::EXCEPTION_NO_ACTION; } else { $error->type = self::EXCEPTION_OTHER; } break; default: $error->type = self::EXCEPTION_OTHER; break; } // get a count of the number of exceptions encountered $this->_exceptionCountAtFirstEncounter = count($exceptions); // Keep a copy of the original Request $error->request = clone $request; // Forward to the error handler $request->setParam('error_handler', $error)->setModuleName($this->getErrorHandlerModule())->setControllerName($this->getErrorHandlerController())->setActionName($this->getErrorHandlerAction())->setDispatched(false); } }
/** * 派遣请求到 Controller/action. * 处理线索 dispatch(RThink_Controller_Front) ->dispatch(RThink_Controller_DispatcherStandard) -> dispatch(RThink_Controller_Action) * 最终还是交由动作控制器自己分发 * * @return void RThink_Controller_Response Response object if returnResponse() is true */ public function dispatch() { $_plugins = array(); if ($this->getParam('plugins')) { // if (!$this->getParam('plugin_path')) { // throw new RThink_Exception("插件注册失败!入口文件没有指定plugin_path!"); // } foreach ($this->getParam('plugins') as $plugin) { // include $this->getParam('plugin_path') . '/' . $plugin . '.php'; include APP_PATH . '/app/plugins/' . $plugin . '.php'; $_plugins[] = new $plugin(); } } if (!$this->getParam('noErrorHandler')) { include 'RThink/Controller/Plugin/ErrorHandler.php'; $_plugins[] = new RThink_Controller_Plugin_ErrorHandler(); } $this->_plugins->registerPlugin($_plugins); /** * 获取请求对象 */ if (null === $this->_request) { $this->getRequest(); } /** * 获取响应对象 */ if (null === $this->_response) { $this->getResponse(); } /** * Initialize Router */ $router = $this->getRouter(); /** * 初始化派遣器 */ $dispatcher = $this->getDispatcher(); $dispatcher->setParams($this->getParams())->setResponse($this->_response); // 开始派遣 try { /** * Notify plugins of Router startup */ $this->_plugins->routeStartup($this->_request, $this->_response); try { $router->route($this->_request); } catch (Exception $e) { if ($this->throwExceptions()) { throw $e; } $this->_response->setException($e); } /** * Notify plugins of Router completion */ $this->_plugins->routeShutdown($this->_request, $this->_response); /** * Notify plugins of dispatch loop startup */ $this->_plugins->dispatchLoopStartup($this->_request, $this->_response); /** * 尝试派遣controller/action.如果 $this->_request表明需要被派遣, * 移动到request的下一个action */ do { $this->_request->setDispatched(true); /** * Notify plugins of dispatch startup */ $this->_plugins->preDispatch($this->_request, $this->_response); /** * 如果 preDispatch() 重置了请求的action则跳过 */ if (false == $this->_request->isDispatched()) { continue; } /** * 派遣请求 */ try { $dispatcher->dispatch($this->_request, $this->_response); } catch (Exception $e) { if ($this->throwExceptions()) { throw $e; } $this->_response->setException($e); } /** * Notify plugins of dispatch completion */ $this->_plugins->postDispatch($this->_request, $this->_response); } while (!$this->_request->isDispatched()); } catch (Exception $e) { if ($this->throwExceptions()) { throw $e; } $this->_response->setException($e); } /** * Notify plugins of dispatch loop completion */ try { $this->_plugins->dispatchLoopShutdown($this->_response); } catch (Exception $e) { if ($this->throwExceptions()) { throw $e; } $this->_response->setException($e); } if ($this->_request->getParam('db_debug')) { RThink_Debug::dbDebug(); } if ($this->returnResponse()) { return $this->_response; } $this->_response->sendResponse(); }