Handling Ajax requests in the Zend Framework

Tags:

Originally posted in my old blog at My Opera

Doing Ajax is quite simple these days with the various JavaScript libraries offering easy ways to do it. But how do you do it on the server side, without complicating things too much?

Typically, in addition to the Ajax response, you need a traditional page response to a request as well – for example, for browsers which don't support Ajax.

Let's look at some methods how one can detect if a request is an Ajax request and how to respond to them in the Zend Framework.


Recognizing Ajax requests

First, we need to be able to detect that a request was an Ajax request to be able to properly respond them.

The most obvious method for achieving this would be to append something like ?ajax=1 as a GET parameter to the URL. This is probably the simplest and most sure to work method for doing this.
In your controller,

if($this->_request->getQuery('ajax') == 1)
{
  //Ajax
}

You could also have separate actions in your controllers for ajax, but that wouldn't always be the best alternative as many Ajax requests require the same kind of data as normal ones do, so it could lead to code duplication. Of course, if your application does some more specialized Ajax things, then this is the best choice as this will efficiently separate your Ajax responses from the rest.

Zend Framework also provides a method in the Request-object that can be used to test this.
In your controller code,

if($this->_request->isXmlHttpRequest())
{
  //The request was made with JS XmlHttpRequest
}

The isXmlHttpRequest function checks if the HTTP request header X_REQUESTED_WITH is set to XMLHttpRequest. This is not set automatically by browsers, so depending on your JavaScript code, it might not work. It does work with Prototype and Mootools at least, as I've used both of them in my projects.

Responding differently

If you are sharing actions for both normal and Ajax requests, you will probably want to send different data to to each.

– Full pages to normal requests
– Small HTML snippets, JSON or XML to Ajax

Using the methods I mentioned in the previous chapter, we can check if the request is Ajax. After this, it's just a matter of displaying a different view script to the user.

Manual view instantiation

$view->render('ajax.phtml');

With the ViewRenderer

$this->_helper->viewRenderer('ajax');

Outputting XML is quite simple with normal view scripts: Instead of HTML, you just write XML in your view script. The Zend Framework also makes it very easy to output JSON if needed:

//Disable ViewRenderer as we just want to output JSON
$this->_helper->viewRenderer->setNoRender();

//Some dummy data
$myArray = array(
             'someData',
             'moreData' => array(
                             'hello'
                           )
           );

$jsonData = Zend_Json::encode($myArray);
$this->response->appendBody($jsonData);

What about layouts?

What if you're using layouts with the ViewRenderer?

You could run into a small problem: Even if you change the view script, it would still give you the layout code.

This can be fixed with a small predispatch plugin. You've probably used a plugin for checking user authentication against an Acl, but there are other uses too, like this one.

Instead of manually replacing the ViewRenderer with something else, or stopping the rendering, we can simply use a plugin to automatically replace the layout renderer with the default viewrenderer. This is pretty simple:

isXmlHttpRequest())
      return;


    $oldViewHelper = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');

    $viewHelper = new Zend_Controller_Action_Helper_ViewRenderer($oldViewHelper->view);

    Zend_Controller_Action_HelperBroker::addHelper($viewHelper);
  }
}
?>

This plugin simply checks if the request is made with an XmlHttpRequest and replaces the viewrenderer with the default one. It also keeps the old view from the old viewrenderer. This is because if you assign some data to the view in your bootstrap, the data would be lost if we didn't re-assign the old view.

Adding this to the front controller is easy:

$fc = Zend_Controller_Front::getInstance();
$fc->registerPlugin(new AjaxCheckPlugin());

This is why I really like the Zend Framework: It provides you with many nice features such as the plugins which make doing things simple and easy.

Conclusion

So it's very easy to respond to Ajax if you know these few simple things.