For my latest project, I was determined to avoid confusing Ajax requests by implementing my own JSON-RPC. Again, Zend Framework has made this incredibly easy.

The documentation recommends not running your Ajax request through the MVC. At first I was a little concerned, but it makes sense as the MVC does add a lot of unnecessary overhead.

I found this blog very helpful in figuring out how to do this.
The first step is to create a new bootstrap file.
I created one in public/api/1.0/jsonrpc.php

Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath('../../../library'),
    get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);

$application->getBootstrap()
            ->bootstrap('doctrine')
            ->bootstrap('config');

// Instantiate server, etc.
$server = new Zend_Json_Server();
$server->setClass('App_Model_JsonRpc');

if ('GET' == $_SERVER['REQUEST_METHOD']) {
    // Indicate the URL endpoint, and the JSON-RPC version used:
    $server->setTarget('/api/1.0/jsonrpc.php')
           ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);

    // Grab the SMD
    $smd = $server->getServiceMap();

    // Return the SMD to the client
    header('Content-Type: application/json');
    echo $smd;
    return;
}

$server->handle();

You may want to modify the $application->getBootstrap() line and add/remove bootstrap methods depending on your requirements. I need access to my database within my JSON-RPC server and use Doctrine as my ORM so I bootstrap that.

The most important line is:

$server->setClass('App_Model_JsonRpc');

This tells the server what class should handle all the JSON requests.

I also added a RedirectRule in my .htaccess file to hide the php extension. It’s unnecessary but the .php extension isn’t seen anywhere else on my site so I don’t want it on my JSON RPC server either.
I added this line…

RewriteRule ^api/([0-9].[0-9])/jsonrpc$ /api/$1/jsonrpc.php [NC,L]

…between these two lines:

RewriteRule ^.*$ - [NC,L]
RewriteRule ^api/([0-9].[0-9])/jsonrpc$ /api/$1/jsonrpc.php [NC,L]
RewriteRule ^.*$ index.php [NC,L]

[ad name=”Google Adsense 468×60″]
I then created a class called App_Model_JsonRpc and put it in my models directory.
/application/models/JsonRpc.php

class App_Model_JsonRpc
{

    /**
     * Return sum of two variables
     *
     * @param  int $x
     * @param  int $y
     * @return array
     */
    public function add($x, $y)
    {
        return  $x + $y;
    }
}

The doc blocks are very important as Zend_Json_Server generates the SMD based on the contents of the Doc block.

That’s it for the server. Send it the proper JSON code and it will add 2 numbers together and return the result.

Heres a quick example of how to use your new server.
I recommend installing the ZendJsonRpc jQuery plugin as it makes talking to your server much easier. You can download the plugin here.

<script src="/js/json2.js" type="text/javascript"></script>
<script src="/js/jquery.zend.jsonrpc.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
 myApi = jQuery.Zend.jsonrpc({url: '/api/1.0/jsonrpc'});

 alert('5+5=' + myApi.add(5,5));

 });
</script>

That’s it!
[ad name=”Google Adsense 468×60″]

Share

Zend Framework

Zend FrameworkI love the Zend Framework. I’ve been using it since version 1.5 (currently at 1.10 as of this writing). It has so many features and can do so many things–sometimes it’s just not immediately clear how to implement those great features.

One feature that took me awhile to figure out was AJAX context switching. The documentation contains various pieces of information about implementing AJAX, but it just wasn’t clear how to put those pieces together. To help make this more clear, I’m going to go through a simple example of how to add very basic AJAX to the Zend Framework QuickStart project. I’m going to be using jQuery because I prefer that to Dojo and the rest of the JavaScript frameworks.

This tutorial assumes you already have a development server set up, Zend Framework installed, and the Zend Framework QuickStart project up and running.

Modify IndexController.php

First we need to set up Ajax context switching in the main controller. Add the following init() function to the index controller found in controllers/IndexController.php

public function init()
{
    $ajaxContext = $this->_helper->getHelper('AjaxContext');
    $ajaxContext->addActionContext('list', 'html')
                ->addActionContext('modify', 'html')
                ->initContext();
}

The html parameter is the type of Ajax request. You can also use JSON or XML.

Note: The modify context is not used in this tutorial but is merely there to demonstrate that you can have as many action contexts as you want.

Now we need to add the list action that we specified above in the addActionContext call to the IndexController.php.

public function listAction() {
    // pretend this is a sophisticated database query
    $data = array('red','green','blue','yellow');
    $this->view->data = $data;
}

Create the list view scripts

By default, Zend Framework tries to render view scripts with the same name as the action. If our action’s name is list and is controlled by the controller named index, then Zend will try to render a view script located at view/scripts/index/list.phtml. Since we are using Ajax context switching, Zend Framework attempts to render view/scripts/index/list.ajax.phtml instead.

For testing my Ajax actions I usually create a normal view helper as well as the Ajax helper but then just include the Ajax view helper.

Create the following view scripts. The second script list.phtml is optional but might aid in troubleshooting.

views/scripts/index/list.ajax.phtml

<!-- views/scripts/list.ajax.phtml should contain something like the following -->
<ul>
<?php foreach ($this->data as $color) : ?>
<li><?= $color ?></li>
<?php endforeach; ?>
</ul>

views/scripts/index/list.phtml

<?php
include('list.ajax.phtml');

[ad name=”Google Adsense 468×60″]

jQuery time

The last thing we need to do is to add some HTML and JavaScript to our index.phtml view script to test everything out.

Add the following to the bottom of views/scripts/index/index.phtml

<div id="container">
</div>
<script type="text/javascript">
  $(document).ready(function() {
        $('#container').load('/default/index/list/format/html');
  });
</script>

The most important part of that jQuery code is the content of the URL you specify. This is one of those cases when you need to specify the module and controller and action even if they are set to the default value.

‘/module/controller/action/format/html’

You must also not forget the format/html part. If you forget it, you’ll notice that Zend is rendering your layout too instead of just rendering the view script.

That’s it. You should now have a list of colours on the first page of your site.

UPDATE: there was an error in the jQuery code on the index.phtml view script. The code is correct now. I have also added a working project to my Google Code repository. Thanks to the commenters for pointing this out.

Share