1. * When debug < 1 a CakeException will render 404 or 500 errors. If an uncaught exception is thrown * and it is a type that ExceptionHandler does not know about it will be treated as a 500 error. * * ### Implementing application specific exception rendering * * You can implement application specific exception handling in one of a few ways: * * - Create a AppController::appError(); * - Create a subclass of ExceptionRenderer and configure it to be the `Exception.renderer` * * #### Using AppController::appError(); * * This controller method is called instead of the default exception handling. It receives the * thrown exception as its only argument. You should implement your error handling in that method. * * #### Using a subclass of ExceptionRenderer * * Using a subclass of ExceptionRenderer gives you full control over how Exceptions are rendered, you * can configure your class in your core.php, with `Configure::write('Exception.renderer', 'MyClass');` * You should place any custom exception renderers in `app/libs`. * * @package Cake.Error */ class ExceptionRenderer { /** * Controller instance. * * @var Controller * @access public */ public $controller = null; /** * template to render for CakeException * * @var string */ public $template = ''; /** * The method corresponding to the Exception this object is for. * * @var string */ public $method = ''; /** * The exception being handled. * * @var Exception */ public $error = null; /** * Creates the controller to perform rendering on the error response. * If the error is a CakeException it will be converted to either a 400 or a 500 * code error depending on the code used to construct the error. * * @param string $method Method producing the error * @param array $messages Error messages */ public function __construct(Exception $exception) { $this->controller = $this->_getController($exception); if (method_exists($this->controller, 'apperror')) { return $this->controller->appError($exception); } $method = $template = Inflector::variable(str_replace('Exception', '', get_class($exception))); $code = $exception->getCode(); $methodExists = method_exists($this, $method); if ($exception instanceof CakeException && !$methodExists) { $method = '_cakeError'; if (empty($template)) { $template = 'error500'; } if ($template == 'internalError') { $template = 'error500'; } } elseif (!$methodExists) { $method = 'error500'; if ($code >= 400 && $code < 500) { $method = 'error400'; } } if (Configure::read('debug') == 0) { $parentClass = get_parent_class($this); if ($parentClass != __CLASS__) { $method = 'error400'; } $parentMethods = (array)get_class_methods($parentClass); if (in_array($method, $parentMethods)) { $method = 'error400'; } if ($code == 500) { $method = 'error500'; } } $this->template = $template; $this->method = $method; $this->error = $exception; } /** * Get the controller instance to handle the exception. * Override this method in subclasses to customize the controller used. * This method returns the built in `CakeErrorController` normally, or if an error is repeated * a bare controller will be used. * * @param Exception $exception The exception to get a controller for. * @return Controller * @access protected */ protected function _getController($exception) { App::uses('CakeErrorController', 'Controller'); if (!$request = Router::getRequest(false)) { $request = new CakeRequest(); } $response = new CakeResponse(array('charset' => Configure::read('App.encoding'))); try { $controller = new CakeErrorController($request, $response); } catch (Exception $e) { $controller = new Controller($request, $response); $controller->viewPath = 'Errors'; } return $controller; } /** * Renders the response for the exception. * * @return void */ public function render() { if ($this->method) { call_user_func_array(array($this, $this->method), array($this->error)); } } /** * Generic handler for the internal framework errors CakePHP can generate. * * @param CakeExeption $error * @return void */ protected function _cakeError(CakeException $error) { $url = $this->controller->request->here(); $code = $error->getCode(); $this->controller->response->statusCode($code); $this->controller->set(array( 'code' => $code, 'url' => h($url), 'name' => $error->getMessage(), 'error' => $error, )); try { $this->controller->set($error->getAttributes()); $this->_outputMessage($this->template); } catch (Exception $e) { $this->_outputMessageSafe('error500'); } } /** * Convenience method to display a 400 series page. * * @param array $params Parameters for controller */ public function error400($error) { $message = $error->getMessage(); if (Configure::read('debug') == 0 && $error instanceof CakeException) { $message = __d('cake', 'Not Found'); } $url = $this->controller->request->here(); $this->controller->response->statusCode($error->getCode()); $this->controller->set(array( 'name' => $message, 'url' => h($url), 'error' => $error, )); $this->_outputMessage('error400'); } /** * Convenience method to display a 500 page. * * @param array $params Parameters for controller */ public function error500($error) { $url = $this->controller->request->here(); $code = ($error->getCode() > 500) ? $error->getCode() : 500; $this->controller->response->statusCode($code); $this->controller->set(array( 'name' => __d('cake', 'An Internal Error Has Occurred'), 'message' => h($url), 'error' => $error, )); $this->_outputMessage('error500'); } /** * Generate the response using the controller object. * * @param string $template The template to render. */ protected function _outputMessage($template) { $this->controller->render($template); $this->controller->afterFilter(); $this->controller->response->send(); } /** * A safer way to render error messages, replaces all helpers, with basics * and doesn't call component methods. * * @param string $template The template to render */ protected function _outputMessageSafe($template) { $this->controller->helpers = array('Form', 'Html', 'Session'); $this->controller->render($template); $this->controller->response->send(); } }