Zend Framework Exception Handling

Code Naked

  • Homepage
  • About
  • Contact

Jun 20: Zend Framework Exception Handling

Handling exceptions is extremely import if you want to have an application that is stable and end-user friendly. The Zend Framework comes with some great features for handling things like missing controllers and actions right out of the box. Like many things with the Zend Framework, you have to dig a little before you find the answers that you need. There are three steps needed to take advantage of the build in exception handling features:

1) You have to register the Zend_Controller_Plugin_ErrorHandler plugin.
2) You have to create an error controller
3) You have to create the templates for the specific error types

Read on to see what my versions of the above look like...
First is registering the plugin. That's super easy.
// Set up controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true)
                ->registerPlugin(new Zend_Controller_Plugin_ErrorHandler());

For production, you probably want to turn off the front controller's abililty to throw exceptions.

Next is my error controller. By default, the Zend_Controller_Plugin_ErrorHandler looks for the error controller in your default controllers directory. Mine is located at /modules/default/controllers/ErrorController.php and looks like this:
class ErrorController extends MDJP_Controller_Action
{
    /**
     * Should we display the errors?
     *
     * @var boolean
     */
    protected $_displayErrors = true;

    /**
     * The error handler
     *
     * @var Zend_Controller_Plugin_ErrorHandler
     */
    protected $_error = null;

    /**
     * Controller init method
     */
    public function init()
    {
        if ($this->getInvokeArg('displayErrors') == true) {
            $this->_displayErrors = true;
        }

        $this->_error = $this->getRequest()->getParam('error_handler');
    }

    /**
     * Default action of the Zend_Controller_Plugin_ErrorHandler
     */
    public function errorAction()
    {
        // Clear previous content
        $this->getResponse()->clearBody();

        // This method delegates to others so there is no template for it
        $this->getHelper('ViewRenderer')->setNoRender();

        switch ($this->_error->type) {
            case 'EXCEPTION_NO_CONTROLLER':
            case 'EXCEPTION_NO_ACTION':
                $this->_forward('not-found');
                return;
            case 'EXCEPTION_OTHER':
                $this->_forward('server-error');
                return;
        }
    }

    /**
     * Handle a missing controller or action
     *
     * If displaying errors, we include the exception in the view variables
     */
    public function notFoundAction()
    {
        $this->_response->setHttpResponseCode(404);

        if ($this->_displayErrors === true) {
            $this->view->ExceptionMessage = $this->_error->exception->getMessage();
        }
    }


    /**
     * Handle an unknown server error
     *
     * If displaying errors we pass back the exception message and the traceback
     */
    public function serverErrorAction()
    {
        if ($this->_displayErrors === true) {
            $this->view->ExceptionMessage = $this->_error->exception->getMessage();

            $rawTrace = array_reverse($this->_error->exception->getTrace());
            $traceback = array();
            $index = 0;
            foreach ($rawTrace as $traceEntry) {
                $tracebackArgs = '';
                if (array_key_exists('args', $traceback)) {
                    $tracebackArgs = implode(',', $traceback['args']);
                }

                $traceback[] = '#'.$index++
                                .' '.$traceEntry['file']
                                .'('.$traceEntry['line'].')'
                                .' '.$traceEntry['class'].$traceEntry['type'].$traceEntry['function'].'('.$tracebackArgs.')';
            }

            $this->view->Traceback = print_r(implode("\n", $traceback), TRUE);
        }

        // Always log errors
        $exception = $this->_error->exception;
        error_log($exception);

        $this->_response->setHttpResponseCode(500);
    }
}
So the plugin will forward to the error action of your ErrorController. In there you can do anything you want, I choose to handle the 404 missing controller or action using a template and any other uncaught exceptions with a 500 server error which is also rendered out as a template.

Here are those two templates:
not-found.phtml
server-error.phtmlThat's it. In case you are wondering where all of the HTML is in those templates, I use Zend_Layout so my action-based view scripts are quite minimal.

Now you have a top level catch-all that can handle routing errors without having to write a "No Route" plugin and you get a top level exception handler in case you let one slip by you. Which would never happen of course ;-)
Posted by Matthew Purdon in PHP Comments: (0) Trackbacks: (0)

Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)

No comments


Add Comment

Standard emoticons like :-) and ;-) are converted to images.
 
 

Subscribe

Archives

  • March 2010 (0)
  • February 2010 (1)
  • January 2010 (4)
  • December 2009 (6)
  • Recent...
  • Older...

Categories

  • XML Technology
  • XML Databases
  • XML MySQL
  • XML Software Development
  • XML Being a Contractor
  • XML Client Side
  • XML PHP
  • XML State of the Art


All categories

Blog Administration

Open login screen

Recommended Reading

Amazon.com: Refactoring: Improving the Design of Existing Code (9780201485677): Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts: Books
Amazon.com: Domain-Driven Design: Tackling Complexity in the Heart of Software (0076092019565): Eric Evans: Books
Amazon.com: Patterns of Enterprise Application Architecture (0076092019909): Martin Fowler: Books
Amazon.com: The Nomadic Developer: Surviving and Thriving in the World of Technology Consulting (9780321606396): Aaron Erickson: Books

Feedburner

Numeric Feedburner ID Required!




 

Layout by Andreas Viklund | Serendipity template by Carl