zen of coding

Dealing with errors in CakePHP

Chances are if your app is already out in production, you have your debug level set to ‘0’. This is probably good news, since the users will not be seeing any nasty errors and in the worst case, they’ll see a blank page or a ‘not found’ page in case of an application error. (You might have noticed that when running with debug = 0, PHP errors are disabled and all application errors will point the user to a standard 404 page).

However, this may not be good enough for you and you’d like to extend the error handling capabilities of your app…

First, let’s take a look at what types of errors we should handle, and how to deal with them properly.

Technically we have two types of errors: PHP errors and CakePHP errors. CakePHP errors (application errors) would be something that is triggered by your application, for example a missing view file or a missing database table, PHP errors would be something like a fatal error that’s caused by a missing bracket or a notice of an undefined variable.
It goes without saying that in production your code should not have any missing brackets or missing views, but there are cases (i.e. division by zero) where a problem can slip by even with rigorous testing. Surely, you don’t want your users to see it, but it would be good for the developer/manager to know if that happens.

Let’s take a look at what to do with our PHP errors… It is important to realize that PHP errors should be dealt with completely separately from the CakePHP errors. Thankfully you can pretty easily control what happens when a PHP error arises by using our good ol’ .htaccess or php.ini. A simple google search will teach you all you need to know about how to ensure that PHP errors are logged, but not displayed to the user.

So what about CakePHP errors?
To extend CakePHP’s error handling you should create a file called app_error.php in your /app/ directory.

You then neeed to create a class there: class AppError extends ErrorHandler…

Now, you can override any default CakePHP error handling methods, to suit your own needs.

Here’s a trick to allow CakePHP errors to be emailed to the developer, while running with debug = 0, set in core.php:

class AppError extends ErrorHandler {

function __construct($method, $messages) {
   Configure::write('debug', 1);
   parent::__construct($method, $messages);
}

function _outputMessage($template) {
   $this->controller->render($template);
   $this->controller->afterFilter();

   App::import('Core', 'Email');

   $email = new EmailComponent;

   $email->from = 'CakePHP <cakephpapp@yourdomain.com>';
   $email->to = 'Developer <somedeveloper@yourdomain.com>';
   $email->sendAs = 'html';
   $email->subject = 'Error in my CakePHP app';

   $email->send($this->controller->output);
}

}

So now, the end-user will not see any errors (PHP or CakePHP), but the developer should have PHP errors logged on the server and CakePHP errors sent to him in an email.

It is also a good idea to add some output so that the user is not stuck looking at a blank page. You can easily extend above method to have:

$this->controller->output = null;
$this->controller->render('someGenericErrorTemplate');
echo $this->controller->output;

You could just as easily log the errors to a file or define your own error methods (see cake’s default error.php) to add improved error logging and handling.

I’m sure this approach goes against some rules, but I have not seen a different way to handle this situation… so any suggestions/improvements are certainly welcomed.

P.S.
primeminister pointed out that by using Object::cakeError() (see API) as well as defining some methods in App Error, one can easily add a more robust error handling to deal with various situations that can arise in your application. In a way you can think of using cakeError() within your app similarly to how you’d use trigger_error() in good ol’ PHP.

  • HeathNail

    How about a database error page?
    One thing about db errors in production mode (with CakePHP), you get a page not found. If your site is being indexed the search engine sees a 404 it may remove the page from its index. Usually if the search engine sees a 500 it will try again later.

  • teknoid

    @HeathNail

    By using the approach similar to the above you can override any method in core’s error.php and display your own page as well as setting the header as seen in error404().

  • Teknoid! Good you posted it. Just asked this in the IRC a while ago and was looking at the AppError.
    Still trying to do some trigger_error() stuff and the AppError class is getting that error and email me this.

    thnx again!

  • teknoid

    @primeminister

    No problem, hope this helps a little.

  • Mark

    Hi. Just wanted to say thanks for posting this up! I’m using it like this…

    controller->redirect(‘/users/view/’.$params[‘url’]);
    }
    }
    ?>

    Now if a page doesn’t exist, it looks for a user by that name instead!

  • teknoid

    @Mark

    Glad it helped.

  • majna

    __outputMessage($template) is changed to protected:
    _outputMessage($template)

  • @majna

    Thanks for pointing this out… well it’s about time, since I felt that it was “wrong” to begin with :)
    (I’ve updated the post to reflect the change).

  • Pingback: Error handling in cakephp | DevArticles.In()

  • bdwankhede

    Is there any way to display 504 temporary unavailable if db is down?

  • @bdwankhede

    You can override any appropriate method and set the headers as you wish.

    • bdwankhede

      thanks:)

  • cakedox

    has anybody notice that if you set Configure::write(‘debug’,0); the one and only
    errorfunction that is called in the app_error() handler is error404 ? :-) or am i wrong

  • @cakedox

    That’s true, and that’s intentional, so we don’t show the users in production any “major” problems with the app. However, as mentioned, you can override this to your liking.

  • Hi,

    I am trying to display an error message if the application does not connect to the DB. All I get is a blank page.

    What function would I use to display a database connection error and is there anything else I need to add to the application?

    Seags

  • Pingback: Tweets that mention Dealing with errors in CakePHP¬†|¬†nuts and bolts of cakephp -- Topsy.com()

  • Hugo Ferreira

    Hi everyone!
    Firstly Thank’s for the rich post! =D

    Unfortunately, Just creating a file named /app/app_error.php was not suficiently to override the /cake/libs/error.php methods. I’m trying many ways to do it but no success yet.

    My /cake/libs/ is shared with various projects and I can’t edit the error404() method directly, So I need to create a specific app_error.php page for each project (in /app/ I think)

    someone have any idea of how to force cakephp to override the the methods in /cake/libs/error.php ?

    Thank’s

    • Hugo Ferreira

      I figure out what was happening.. seem that it did not load app_error.php because there was a error.php file in the same directory

  • Pingback: links for 2011-04-04 « Breyten’s Dev Blog()

  • Pingback: CakePHP: Keeping login information on error pages()

  • Adam Friedman

    I’m still waiting for a response to Seags’ question: how can I handle a database error, particularly from a $this->Model->query() call? Is this fixed in 2.0?

  • teknoid

    @Adam Friedman

    Have you seen this?
    http://nuts-and-bolts-of-cakephp.com/2010/10/31/catch-database-errors-before-its-too-late/

    Not sure how this works with the query() method, maybe another reason to avoid it… maybe not.

%d bloggers like this: