Now, with the results from Part 1 and Part 2, let’s take a deeper look into the Ext.Direct Providers to see how they work and what to do.
Prepareing a JSON Service Map Description
To use the Ext.direct framework we need to register a provider. For a remoting provider we need a service mapping description.
Ext.Direct.addProvider(Ext.apply(Ext.app.JSONRPC_API, {
'type' : 'zfprovider',
'url' : Ext.app.JSONRPC_API.target
}));
Ext.app.JSONRPC_API holds the service mapping description which in the Tine 2.0 case we deliver it with our registry data, but you can also fetch it e.g. by a javascript include as suggested in the “EXT.DIRECT REMOTING SPECIFICATION”.
<script src=”index.php?method=Tinebase.getServiceMap” type=”text/javascript”></script>
The Service Map could be generated like this:
$server = new Zend_Json_Server();
// set all classes you want to expose
$server->setClass('MyModule_Service_Json', 'MyModul');
$server->setTarget('index.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
$smdArray = $server->getServiceMap()->toArray();
// save some bytes
unset($smdArray['methods']);
echo "Ext.app.JSONRPC_API = " . Zend_Json::encode($smdArray);
Ext.ux.direct.ZendFrameworkProvider
To Enable Ext.Direct to understand the JSON-SMD data and also communicate using the JSON-RPC protocol we create an own provider:
Ext.ux.direct.ZendFrameworkProvider = Ext.extend(Ext.direct.RemotingProvider, {
...
At first we need to parse the JSON-SMD and to create the stubs. This is done by overwriting the initAPI method:
// private
initAPI : function() {
for (var method in this.services){
var mparts = method.split('.');
var cls = this.namespace[mparts[0]] || (this.namespace[mparts[0]] = {});
cls[mparts[1]] = this.createMethod(mparts[0], Ext.apply(this.services[method], {
name: mparts[1],
len: this.services[method].parameters.length
}));
}
},
All we do is to transform the JSON-SMD definition data in to a from the original createMethod method can understand to create the stubs.
It’s important to understand, that the createMethod creates stubs which do only trigger further processing of the provider and do _NOT_ contain all the code to do requests and protocol processing.
Once a stub is called, it applies the doCall function of our provider. In order to support named parameters we inspect the call and transform a named parameter call into a positional parameter call. This is needed, cause the ZendFrameworks Zend_Json_Server is itself not able to understand named parameter calls witch by the way are indeed part of the JSON-RPC specification.
// private
doCall : function(c, m, args) {
// support named parameters
if (args[args.length-1].paramsAsHash) {
var o = args.shift();
for (var i = 0; i < m.parameters.length; i++) {
args.splice(i,0, o[m.parameters[i].name]);
}
}
return Ext.ux.direct.ZendFrameworkProvider.superclass.doCall.call(this, c, m, args);
},
After the parameters a prepared, the provider assembles the request according to the protocol definitions. This is done in the getCallData method.
// private
getCallData: function(t){
return {
jsonrpc: '2.0',
method: t.action + '.' + t.method,
params: t.data,
id: t.tid
};
},
This protocol encapsulation only deals with single transaction calls. The processing for batched calls is done elsewhere. Luckily The both protocols use the same simple outer array for batched calls, so that we don’t need to touch it.
Finally the response needs to be decoded according to the protocol and the callback function needs to get called using the decoded data. This is done in the onData method:
// private
onData: function(opt, success, xhr) {
var rpcresponse = Ext.decode(xhr.responseText);
xhr.responseText = {
type: rpcresponse.result ? 'rpc' : 'exception',
result: rpcresponse.result,
tid: rpcresponse.id
};
return Ext.ux.direct.ZendFrameworkProvider.superclass.onData.apply(this, arguments);
}
And voila, thats it. This is our custom provider to enable Ext.Direct to use and talk pure standard JSON-PRC/JSON-SMD.
Finally let’s register the provider for lazy invocation
Ext.Direct.PROVIDERS['zfprovider'] = Ext.ux.direct.ZendFrameworkProvider;
Server Side Batched Requests
As noted in Part 2, the biggest problem with the Zend_Json_Server is the fact that it’s not capable to handle batched requests yet. To overcome this in a simple way, you can monitor the first character of an JSON request in your dispatcher and dispatch multiple request if it’s a ‘[‘. Of course this is far away from optimum, but it’s a start point till we have the feature in the Zend_Json_Server.
