The Error Controller
Wednesday, October 21, 2009

There are two basic kinds of errors that occur in Zend Framework applications: Page Not Found and Internal Error. These are handled by the error controller.

The ErrorController class is normally stored in the file ErrorController.php inside the application/controllers directory. This convention is followed by the sample application.

The skeleton for the class code is as follows:

class ErrorController extends Zend_Controller_Action
{
  public function errorAction()
  {
    // Insert error handling code here
  }
}

Note that the ErrorController is derived from Zend_Controller_Action, as controllers usually are. Note also that the action is error.

The error handling code starts by determining whether the request was an AJAX request; this is important, as standard requests should be greated with a full error page for the benefit of the user, but AJAX requests should receive a terse error message that is easily processed by the calling code.

$isAjaxRequest = $this->getRequest()->isXmlHttpRequest();

Next, it retrieves the error handle in order to get more information about the error:

$errors = $this->_getParam('error_handler');

Then it fetches the log object from the registry; the mechanism by which this is created and stored there is described in the earlier blog post Bootstrapping the Application: a Custom Log Resource Plugin.

$log = Zend_Registry::get('Zend_Log');

There is then a switch statement, that determines which of the two basic kinds of errors has occurred; the skeleton for this statement is:

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
    // Insert page not found error handling code here
    break;
 
  default:
    // application error
    // Insert internal error handling code here
    break;
}

The page not found error is handled as follows: an AJAX request for a non-existent resource is met by a terse error message, while other request receive a more expansive response. The error details are written to the log file.

if ($isAjaxRequest)
{
  $errorMessage = 'ERROR,404';
}
else
{
  $this->view->title = 'Page not found';
  $this->view->message = 
    'The page you requested could not be found.';
}
 
$log->info('404 error occured: ' . 
  $this->getRequest()->getRequestUri());

Internal errors are handled in the same fashion:

if ($isAjaxRequest)
{
  $errorMessage = 'ERROR,500';
}
else 
{
  $this->view->title = 'Application error';
  $this->view->message = 
    'An error occured in the web application.';
}
 
$log->crit('500 error occured: ' . 
  $errors->exception->getMessage());

Finally, if it is an AJAX request, the application disables the layout and view script rendering, then simply echoes the error; otherwise, it passes the error details to the view script:

if ($isAjaxRequest)
{
  $this->_helper->layout->disableLayout();
  $this->_helper->viewRenderer->setNoRender(true);
  echo $errorMessage;
}
else 
{
  $this->view->exception = $errors->exception;
  $this->view->request   = $errors->request;
}

The view script is called error.phtml and is stored in the views/scripts/error directory. It contains the following code:

<?php
printf('<h1>%s</h1>', $this->title);
printf('<p>%s</p>', $this->message);
 
if (APPLICATION_ENV == 'development')
{
  echo '<h2>Exception information:</h2>';
  printf('<p><b>Message:</b> %s</p>', $this->exception->getMessage());
 
  echo '<h2>Stack trace:</h2>';
  printf('<p>%s</p>', $this->exception->getTraceAsString());
 
  echo '<h3>Request Parameters:</h3>';
  printf('<p>%s</p>', var_export($this->request->getParams(), 1));
}

Note how the function checks the APPLICATION_ENV constant to see whether the application is in a development environment; in that case, it will supply a more extensive on screen error message to assist with debugging.

Posted by James at 7:45 pm   0 comments

Leave a Reply