Error handling in Zend Framework

For a couple of days I've been breaking my scull how to provide a good way to handle exceptions in a Zend Framework MVC application.

The ZF Manual has several ways of doing stuff, but none of them have a good example how to take care of these exceptions, and how to present a nice message dependend on the exception that was raised.

1. Using the ErrorHandler plugin
This is the easiest way of handling missing controllers, actions or modules. But it's usage is limited to these kind of exceptions. Other exceptions may break your application.

In your bootstrap file (index.php) you have your controller front setup:

<?php
/**
* File: index.php
*/

require_once 'Zend/Controller/Front.php';

/**
* Setup controller
*/
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory( '../application/controllers');
$controller->dispatch();

For using the ErrorHandler plugin, you need to have an error controller and an error view.

Here is an example of a simple errorcontroller script, that uses a log to write exceptions.

<?php
/**
* ErrorController - The default error controller class
*
* File: application/controllers/ErrorController.php
*
*/

require_once 'Zend/Controller/Action.php' ;
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';

class ErrorController extends Zend_Controller_Action
{

    /**
     * This action handles
     *    - Application errors
     *    - Errors in the controller chain arising from missing
     *     controller classes and/or action methods
     */
    public function errorAction ()
    {
        $content = null;
        $errors = $this->_getParam ('error_handler') ;
        switch ($errors->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER :
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION :
                // 404 error -- controller or action not found
                $this->getResponse ()->setRawHeader ( 'HTTP/1.1 404 Not Found' ) ;
                // ... get some output to display...
                $content .= "<h1>404 Page not found!</h1>" . PHP_EOL;
                $content .= "<p>The page you requested was not found.</p>";
                break ;
            default :
                // application error; display error page, but don't change            
                // status code
                $content .= "<h1>Error!</h1>" . PHP_EOL;
                $content .= "<p>An unexpected error occurred with your request. Please try again later.</p>";
                // ...

                // Log the exception
                $exception = $errors->exception;
                $log = new Zend_Log(
                    new Zend_Log_Writer_Stream('/path/to/logs/demo-exceptions_log' )
                );
                $log->debug(
                 $exception->getMessage() . PHP_EOL . $exception->getTraceAsString()
                );
                break ;
        }

        // Clear previous content
        $this->getResponse()->clearBody();
        $this->view->content = $content;
    }
}

A minimalistic error view file resides in /application/views/scripts/error/error.phtml using Zend Framework standards.

<html>
    <head>
     <title>An error has occured</title>
    </head>
    <body>
            <?php echo $this->content; ?>
    </body>
</html>

2. Catching Exceptions

If we want to catch all kinds of exceptions, we better enable our MVC model to throw exceptions.

<?php
/**
* File: index.php
*/

require_once 'Zend/Controller/Front.php';
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php'

/**
* Setup controller
*/
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory( '../application/controllers');
$controller->throwExceptions( true);

try {
    $controller->dispatch();
} catch (Exception $e) {
    // Handle the exception
    $log = new Zend_Log(
        new Zend_Log_Writer_Stream('/path/to/logs/demo-exceptions_log' )
    );
    $log->debug(
        $e->getMessage() . PHP_EOL . $e->getTraceAsString()
    );
}

Another way to handle exceptions, is the use of the response object.

<?php
/**
* File: index.php
*/

require_once 'Zend/Controller/Front.php';
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php'

/**
* Setup controller
*/
$controller = Zend_Controller_Front::getInstance();
$controller->setControllerDirectory( '../application/controllers');
$controller->returnResponse( true);

$response = $controller ->dispatch();
if ($response ->isException()) {
    $exceptions = $response->getException();
    $log = new Zend_Log(
        new Zend_Log_Writer_Stream('/path/to/logs/demo-exceptions_log' )
    );
    $log->debug(
        $exceptions->getMessage() . PHP_EOL . $exceptions->getTraceAsString()
    );
    // Handle the exception
} else {
    $response->sendHeaders();
    $response->outputBody();
}

Now I'm actually stuck, because I want to capture these exceptions in a logfile, but I still want to use the ErrorHandler functionality. This is I want a 404 page when a controller, action or module is not found, a 500 page for exceptions thrown within the application and all the rest working as it is supposed to be.

Comments

  1. Anonymous15/3/08 21:41

    Very useful. Thanks.

    ReplyDelete
  2. try this

    $request = $controller->getRequest();

    $errorController = New ErrorController($request,$response);

    $errorController->dispatch('errorAction');

    ReplyDelete
  3. I try this, but the error still displayed on the screen :(. So it doesn't work what I want. catch the exception and display a general error page.

    ReplyDelete
  4. Anonymous8/10/09 15:14

    Have you got any solution for it. Since I also need "want to caputure the exception at the same time error handling functionlity should work". Please guide me .

    ReplyDelete
  5. Excellent, thanks for sharing this info - its made a big difference to me.
    My site is built on the Zend FW, and not having proper logging when dev'ing was so frustrating!

    ReplyDelete

Post a Comment

Popular Posts