Since 3.6.0 version BEdita ships with a redesigned exception handling system that gives better error responses to client requests.
With this new design every html/json/xml request will be served with the right response content type (text/html, application/json, text/xml). In this way all errors thrown by an Exception are consistent, output the expected type and set up the same $error
var to the view.
In order to achieve this the following new components have been introduced:
- new HTTP exceptions
- a new Exception handler
- new ResponseHandler components, JsonView and XmlView
HTTP Exceptions
In bedita-app/bedita_exceptions.php
common http error status codes are mapped with exceptions as BeditaBadRequestException
, BeditaNotFoundException
, etc..
Every Exception sets the right status code and a corresponding message, if any is passed.
For example
/** * Represents an HTTP 404 error */ class BeditaNotFoundException extends BeditaException { /** * Constructor * * @param string $message If no message is given 'Not Found' will be the message * @param mixed $details The exception details * @param $res The result status * @param int $code Status code, default to 404 */ public function __construct($message = null, $details = null, $res = self::ERROR, $code = 404) { if (empty($message)) { $message = 'Not Found'; } parent::__construct($message, $details, $res, $code); } }
Introducing new Exception Handler
While previously exceptions were handled through a try {} catch() {}
block in index.php now in bedita-app/config/bootstrap.php we are using set_exception_handler()
PHP function.
For shell scripts the exception handler is defined in BeditaBaseShell::__construct()
instead.
In order to adopt new errors handling in old frontend apps be sure to remove the try catch block from app/webroot/index.php replacing it with
$Dispatcher = new Dispatcher(); $Dispatcher->dispatch();
The default exception handler instantiates an AppError
class located at bedita-app/app_error.php that takes care of preparing error data for the client and tries to render a view.
$error
var is identical for any type of response (html/xml/json) and contains the following keys:
'status' => null, // http status code 'code' => null, // error code 'message' => null, // error message 'details' => null, // error details 'moreInfo' => null, // url to look for more information 'url' => null // url that caused the error
Note that at the current state some keys are always empty.
Following this schema the AppError::setError()
method sets the App::error
property to be serialized and sends the right header to the client based on the http error code thrown.
$this->controller->ResponseHandler->sendStatus($this->error['status']); $this->controller->set(array( 'error' => $this->error, '_serialize' => array('error') ));
Setup custom exceptions handler
By default bedita-app/libs/errors/be_exception_handler.php is used but it is possible to write a custom handler and set it up from configuration. To do so in frontend app you can edit frontend.cfg.php in app/config folder
Configure::write('Exception', array( 'handler' => array( 'class' => 'MyExceptionHandler', 'method' => 'myHandleExceptions' ) ));
The custom class should be placed in bedita-app/libs/errors or app/libs/errors in frontend app.
Rarely you would use custom exceptions handling in backend, in this case you need to configure it in bedita-app/config/bedita.cfg.php (possible, but NOT recommended)
The custom method accepts an Exception as argument and it has to be defined as public static, so following the above configuration we should create the file app/libs/errors/my_exception_handler.php
class MyExceptionHandler extends Object { /** * Custom method to handle Exceptions * * @param Exception $exception * @return void */ public static function myHandleExceptions(Exception $exception) { // code here } }
ResponseHandler Component, JsonView and XmlView
It is responsible to respond in the right way to client requests. It's used by AppError
to send the correct status code and set the $error
var that ResponseHandler, will eventually serialize it in the right format (json, xml) setting up the right view (JsonView, XmlView)