Skip to content
This is the documentation for pieceofcake2/cakephp, a community-maintained fork of CakePHP 2.x for PHP 8. About this fork.

Exceptions ​

Exceptions can be used for a variety of uses in your application. CakePHP uses exceptions internally to indicate logic errors or misuse. All of the exceptions CakePHP raises extend CakeException, and there are class/task specific exceptions that extend this base class.

CakePHP also provides a number of exception classes that you can use for HTTP errors. See the section on Built In Exceptions for more information.

Exception configuration ​

There are a few keys available for configuring exceptions:

// config/core.php
Configure::write('Exception', [
    'handler' => 'ErrorHandler::handleException',
    'renderer' => 'ExceptionRenderer',
    'log' => true,
]);
  • handler - callback - The callback to handle exceptions. You can set this to any callback type, including anonymous functions.
  • renderer - string - The class responsible for rendering uncaught exceptions. If you choose a custom class you should place the file for that class in src/Lib/Error/ (app/Lib/Error/ in the legacy layout). This class needs to implement a render() method.
  • log - boolean - When true, exceptions + their stack traces will be logged to CakeLog.
  • skipLog - array - A list of exception class names that should not be logged. Exceptions that extend one of the listed classes are skipped as well, e.g. 'skipLog' => ['NotFoundException', 'UnauthorizedException'].
  • consoleHandler - callback - The callback used to handle exceptions, in a console context. If undefined, CakePHP's default handler will be used.

Exception rendering by default displays an HTML page, you can customize either the handler or the renderer by changing the settings. Changing the handler, allows you to take full control over the exception handling process, while changing the renderer allows you to easily change the output type/contents, as well as add in application specific exception handling.

Added in version 2.2

The Exception.consoleHandler option was added in 2.2.

Exception classes ​

There are a number of exception classes in CakePHP. Each exception replaces a cakeError() error messages from the past. Exceptions offer additional flexibility in that they can be extended and contain some logic. The built in exception handling will capture any uncaught exceptions and render a useful page. Exceptions that do not specifically use a 400 range code, will be treated as an Internal Server Error.

The exception handler is registered with PHP's set_exception_handler(), so it also receives uncaught Error objects such as TypeError or ArgumentCountError. These are logged and rendered with the error500 template, like any other exception that is not a CakeException.

Built-in Exceptions for CakePHP ​

There are several built-in exceptions inside CakePHP, outside of the internal framework exceptions, there are several exceptions for HTTP methods. They are defined in src/Cake/Error/exceptions.php of the framework package and are always available.

ExceptionDescription
BadRequestExceptionUsed for doing 400 Bad Request error.
UnauthorizedExceptionUsed for doing a 401 Unauthorized error.
ForbiddenExceptionUsed for doing a 403 Forbidden error.
NotFoundExceptionUsed for doing a 404 Not found error.
MethodNotAllowedExceptionUsed for doing a 405 Method Not Allowed error.
InternalErrorExceptionUsed for doing a 500 Internal Server Error.
NotImplementedExceptionUsed for doing a 501 Not Implemented Errors.

All of them except NotImplementedException extend HttpException.

You can throw these exceptions from your controllers to indicate failure states, or HTTP errors. An example use of the HTTP exceptions could be rendering 404 pages for items that have not been found:

public function view($id)
{
    $post = $this->Post->findById($id);
    if (!$post) {
        throw new NotFoundException('Could not find that post');
    }
    $this->set('post', $post);
}

By using exceptions for HTTP errors, you can keep your code both clean, and give RESTful responses to client applications and users.

In addition, the following framework layer exceptions are available, and will be thrown from a number of CakePHP core components:

CakeException is the base exception class in CakePHP. All framework layer exceptions thrown by CakePHP will extend this class.

These exception classes all extend CakeException. By extending CakeException, you can create your own 'framework' errors. All of the standard Exceptions that CakePHP will throw also extend CakeException.

Added in version 2.3

CakeBaseException was added. Base exception class in CakePHP. All CakeExceptions and HttpExceptions above extend this class.

method Class::responseHeader($header = null, $value = null)

All Http and CakePHP exceptions extend the CakeBaseException class, which has a method to add headers to the response. For instance when throwing a 405 MethodNotAllowedException the rfc2616 says: "The response MUST include an Allow header containing a list of valid methods for the requested resource." The headers you set are added to the error response by ExceptionRenderer:

$exception = new MethodNotAllowedException();
$exception->responseHeader('Allow', 'GET, POST');
throw $exception;

The framework layer exceptions include:

ExceptionDescription
MissingViewExceptionThe chosen view file could not be found.
MissingLayoutExceptionThe chosen layout could not be found.
MissingHelperExceptionA helper was not found.
MissingBehaviorExceptionA configured behavior could not be found.
MissingComponentExceptionA configured component could not be found.
MissingTaskExceptionA configured task was not found.
MissingShellExceptionThe shell class could not be found.
MissingShellMethodExceptionThe chosen shell class has no method of that name.
MissingDatabaseExceptionThe configured database is missing.
MissingConnectionExceptionA model's connection is missing.
MissingTableExceptionA model's table is missing from CakePHP's cache or the datasource. Upon adding a new table to a datasource, the model cache (found in tmp/cache/models by default) must be removed.
MissingActionExceptionThe requested controller action could not be found.
MissingControllerExceptionThe requested controller could not be found.
PrivateActionExceptionPrivate action access. Either accessing private/protected/_ prefixed actions, or trying to access prefixed routes incorrectly.

Using HTTP exceptions in your controllers ​

You can throw any of the HTTP related exceptions from your controller actions to indicate failure states. For example:

public function view($id)
{
    $post = $this->Post->findById($id);
    if (!$post) {
        throw new NotFoundException();
    }
    $this->set(compact('post'));
}

The above would cause the configured Exception.handler to catch and process the NotFoundException. By default this will create an error page, and log the exception.

Exception Renderer ​

class ExceptionRenderer(Exception $exception)

The ExceptionRenderer class with the help of CakeErrorController takes care of rendering the error pages for all the exceptions thrown by you application.

The error page views are located at templates/Errors/ (app/View/Errors/ in the legacy layout). For all 4xx and 5xx errors the view files error400.ctp and error500.ctp are used respectively. You can customize them as per your needs. By default your templates/Layouts/default.ctp is used for error pages too. If for eg. you want to use another layout templates/Layouts/my_error.ctp for your error pages, then simply edit the error views and add the statement $this->layout = 'my_error'; to the error400.ctp and error500.ctp. If rendering the error page itself fails, CakePHP falls back to a minimal rendering that uses the error layout (templates/Layouts/error.ctp).

Each framework layer exception has its own view file located in the core templates (the templates/Errors/ directory of the framework package), but you really don't need to bother customizing them as they are used only during development. With debug turned off all framework layer exceptions are converted to InternalErrorException.

application exceptions

Creating your own application exceptions ​

You can create your own application exceptions using any of the built in SPL exceptions, Exception itself, or CakeException. Application exceptions that extend Exception or the SPL exceptions will be treated as 500 error in production mode. CakeException is special in that all CakeException objects are coerced into either 500 or 404 errors depending on the code they use. When in development mode CakeException objects simply need a new template that matches the class name in order to provide useful information. If your application contained the following exception:

class MissingWidgetException extends CakeException
{
}

You could provide nice development errors, by creating templates/Errors/missing_widget.ctp. When in production mode, the above error would be treated as a 500 error. The constructor for CakeException has been extended, allowing you to pass in hashes of data. These hashes are interpolated into the the messageTemplate, as well as into the view that is used to represent the error in development mode. This allows you to create data rich exceptions, by providing more context for your errors. You can also provide a message template which allows the native __toString() methods to work as normal:

class MissingWidgetException extends CakeException
{
    protected $_messageTemplate = 'Seems that %s is missing.';
}

throw new MissingWidgetException(['widget' => 'Pointy']);

When caught by the built-in exception handler, you would get a $widget variable in your error view template. In addition if you cast the exception as a string or use its getMessage() method you will get Seems that Pointy is missing.. This allows you easily and quickly create your own rich development errors, just like CakePHP uses internally.

Creating custom status codes ​

You can create custom HTTP status codes by changing the code used when creating an exception:

throw new MissingWidgetHelperException('Its not here', 501);

Will create a 501 response code, you can use any HTTP status code you want. In development, if your exception doesn't have a specific template, and you use a code equal to or greater than 500 you will see the error500 template. For any other error code you'll get the error400 template. If you have defined an error template for your custom exception, that template will be used in development mode. If you'd like your own exception handling logic even in production, see the next section.

Extending and implementing your own Exception handlers ​

You can implement application specific exception handling in one of a few ways. Each approach gives you different amounts of control over the exception handling process.

  • Set Configure::write('Exception.handler', 'YourClass::yourMethod');
  • Create AppController::appError();
  • Set Configure::write('Exception.renderer', 'YourClass');

In the next few sections, we will detail the various approaches and the benefits each has.

Create your own Exception handler with Exception.handler ​

Creating your own exception handler gives you full control over the exception handling process. The class you choose should be loaded in your config/bootstrap.php, so it's available to handle any exceptions. You can define the handler as any callback type. By settings Exception.handler CakePHP will ignore all other Exception settings. A sample custom exception handling setup could look like:

// config/core.php
Configure::write('Exception.handler', 'AppExceptionHandler::handle');

// config/bootstrap.php
App::uses('AppExceptionHandler', 'Lib');

// src/Lib/AppExceptionHandler.php
class AppExceptionHandler
{
    public static function handle(Throwable $error)
    {
        echo 'Oh noes! ' . $error->getMessage();
        // ...
    }

    // ...
}

You can run any code you wish inside handle(). The code above would simple print 'Oh noes! ' plus the exception message. The handler receives every uncaught Throwable, including PHP Error objects, so type the parameter as Throwable (or leave it untyped) rather than Exception. You can define exception handlers as any type of callback, even an anonymous function:

Configure::write('Exception.handler', function (Throwable $error) {
    echo 'Ruh roh ' . $error->getMessage();
});

By creating a custom exception handler you can provide custom error handling for application exceptions. In the method provided as the exception handler you could do the following:

// src/Lib/AppErrorHandler.php
class AppErrorHandler
{
    public static function handleException(Throwable $error)
    {
        if ($error instanceof MissingWidgetException) {
            return static::handleMissingWidget($error);
        }
        // do other stuff.
    }
}

appError

Using AppController::appError() ​

Implementing this method is an alternative to implementing a custom exception handler. It's primarily provided for backwards compatibility, and is not recommended for new applications. This controller method is called instead of the default exception rendering. It receives the thrown exception as its only argument. You should implement your error handling in that method:

// src/Controller/AppController.php
class AppController extends Controller
{
    public function appError($error)
    {
        // custom logic goes here.
    }
}

Using a custom renderer with Exception.renderer to handle application exceptions ​

If you don't want to take control of the exception handling, but want to change how exceptions are rendered you can use Configure::write('Exception.renderer', 'AppExceptionRenderer'); to choose a class that will render exception pages. By default ExceptionRenderer is used. Your custom exception renderer class should be placed in src/Lib/Error/ (app/Lib/Error/ in the legacy layout), or an Error directory in any bootstrapped Lib path. ErrorHandler loads it with App::uses() from the Error package, so you don't need to load it yourself. Use the Plugin.ClassName syntax to use a renderer from a plugin. In a custom exception rendering class you can provide specialized handling for application specific errors:

// src/Lib/Error/AppExceptionRenderer.php
class AppExceptionRenderer extends ExceptionRenderer
{
    public function missingWidget($error)
    {
        echo 'Oops that widget is missing!';
    }
}

The above would handle any exceptions of the type MissingWidgetException, and allow you to provide custom display/handling logic for those application exceptions. Exception handling methods get the exception being handled as their argument.

NOTE

Your custom renderer should expect an exception in its constructor, and implement a render method. Failing to do so will cause additional errors.

NOTE

If you are using a custom Exception.handler this setting will have no effect. Unless you reference it inside your implementation.

Creating a custom controller to handle exceptions ​

In your ExceptionRenderer sub-class, you can use the _getController method to allow you to return a custom controller to handle your errors. By default CakePHP uses CakeErrorController which omits a few of the normal callbacks to help ensure errors always display. However, you may need a more custom error handling controller in your application. By implementing _getController in your AppExceptionRenderer class, you can use any controller you want:

// src/Lib/Error/AppExceptionRenderer.php
class AppExceptionRenderer extends ExceptionRenderer
{
    protected function _getController($exception)
    {
        App::uses('SuperCustomErrorController', 'Controller');

        return new SuperCustomErrorController();
    }
}

Piece of Cake 2 fork

Framework classes, including CakeErrorController, are autoloaded through Composer's classmap, so placing a CakeErrorController in your application's Controller directory no longer reliably replaces the core one. Return your own controller from _getController() instead.

If you are using a custom controller for error handling, make sure you do all the setup you need in your constructor, or the render method. As those are the only methods that the built-in ErrorHandler class directly call.

Logging exceptions ​

Using the built-in exception handling, you can log all the exceptions that are dealt with by ErrorHandler by setting Exception.log to true in your config/core.php. Enabling this will log every exception to CakeLog and the configured loggers. With the default log configuration, they are written to logs/error.log. Use Exception.skipLog to exclude exceptions you don't want logged, such as NotFoundException.

NOTE

If you are using a custom Exception.handler this setting will have no effect. Unless you reference it inside your implementation.

Based on the CakePHP Cookbook. Content licensed under CC BY-NC-SA 4.0. Not affiliated with the Cake Software Foundation.