Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zend Framework: How to handle exceptions in Ajax requests?

Normally when an exception is thrown, Error controller takes command and displays error page with regular common header and footer.

This behavior is not wanted in Ajax request. Because in case of error, whole html page is sent over. And in cases where I'm directly loading the content of http response in a div, this is even more unwanted.

Instead in case of Ajax request, I just want to receive 'the actual error' thrown by exception.

How can I do this?

I think, one dirty way could be: set a var in ajax request and process accordingly. Not a good solution.

like image 875
understack Avatar asked Jun 01 '10 06:06

understack


3 Answers

if you use either the contextSwitch or ajaxContext action helpers to encode your error (possibly turning off autoJsonSerialization) you could just pass the errors back as JSON / XML objects.

http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch

class Error_Controller extends Zend_Controller{
    public function errorAction(){
        $contextSwitch = $this->_helper->getHelper('contextSwitch');
        $contextSwitch->addActionContext($this->getRequest()->getActionName(),'json')
            ->initContext();
        $errors = $this->_getParam('error_handler');
        $this->view->exception = $errors->exception;
    }
}

From there you have to either pass a format=json parameter which each AJAX request or setup a routing chain that automatically appends it.

For a 'slightly' more secure setup you could use ajaxContext as your helper and only requests that have the XMLHttpRequest header will be served json.

like image 141
Ballsacian1 Avatar answered Nov 16 '22 21:11

Ballsacian1


I played with both of the previous answers but kept running into problems. There are a few reasons I had trouble, one of them is that I wanted to be able to return raw HTML from my regular controller when things went well.

This is the solution I eventually came up with:

class ErrorController extends Zend_Controller_Action
{
    public function init()
    {
        // Add the context to the error action
        $this->_helper->contextSwitch()->addActionContext('error', 'json');
    }

    public function errorAction()
    {
        // Check if this is an Ajax request
        if ($this->getRequest()->isXmlHttpRequest()) {

            // Force to use the JSON context, which will disable the layout.
            $this->_helper->contextSwitch()->initContext('json');

            //   Note: Using the 'json' parameter is required here unless you are
            //   passing '/format/json' as part of your URL.
        }

        // ... standard ErrorController code, cont'd ...
like image 2
Brian Lacy Avatar answered Nov 16 '22 20:11

Brian Lacy


The code I use preserves error handling for non-Ajax requests, while keeping the 'displayExceptions' option intact. It is exactly like the regular error handler, in that the stack trace, and request params are also sent back when 'displayExceptions' is active within your application.ini file. There's a lot of flexibility as far as sending back the JSON data - you could create a custom class, use a view with the JSON view helper, etc.

class ErrorController extends Zend_Controller_Action
{
    public function errorAction()
    {
        $errors = $this->_getParam('error_handler');

        if ($this->getRequest()->isXmlHttpRequest()) {
            $this->_helper->contextSwitch()->initJsonContext();

            $response = array('success' => false);

            if ($this->getInvokeArg('displayExceptions') == true) {
                // Add exception error message
                $response['exception'] = $errors->exception->getMessage();

                // Send stack trace
                $response['trace'] = $errors->exception->getTrace();

                // Send request params
                $response['request'] = $this->getRequest()->getParams();
            }

            echo Zend_Json::encode($response);
            return;
        }

        switch ($errors->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
            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()->setHttpResponseCode(404);
                $this->view->message = 'Page not found';
                break;
            default:
                // application error
                $this->getResponse()->setHttpResponseCode(500);
                $this->view->message = 'Application error';
                break;
        }

        // conditionally display exceptions
        if ($this->getInvokeArg('displayExceptions') == true) {
            $this->view->exception = $errors->exception;
        }

        $this->view->request = $errors->request;
    }
}
like image 1
webjawns.com Avatar answered Nov 16 '22 21:11

webjawns.com