
Well, it’s always easy to state that something is slow, so let me be a bit more precise: If you need to do a lot of complex date/time operations in you applications, Zend_Date might turn out to be the major bottleneck. If you just need localization for some date’s Zend_Date presumably won’t be your problem.
In the Calendar app of Tine 2.0 it turned out, that Zend_Date consumes 66% of the time of a Month view Request in a realistic szenario.
Just bashing Zend_Date would be to easy, as it has a remarkable feature set. Most notably in my view:
- solves the year 2038 problem on 32 bit systems
- full timezone support
- full localization support
- full support for ISO 8601 date string identifiers
As Date/Time is a really complex topic, here my full acknowledgement for this feature set at a time when PHP couldn’t help on all this.
On the other hand you don’t always need all the nice features it has, but you might want to use Zend_Date as generic date/time abstraction all over your applications. In this case Zend_Date is slow and has a lot of potential for improvements.
Zend_Dates could be created from a date string in an arbitrary format and locale. This is great if you need to parse custom date strings.
When dealing with Zend_Date in backend operations, you normally only use very few date/time representation formats. e.g. ‘yyyy-MM-dd HH:mm:ss’ which is the mysql date/time format.
For this kind of input Zend_Date has no optimization. An easy performance patch for this problem could be:
if ($format === 'yyyy-MM-dd HH:mm:ss') { $matches = array(); preg_match("/^(\d{4})-(\d{2})-(\d{2})[T ]{1}(\d{2}):(\d{2}):(\d{2})/", $_ISO, $matches); if (count($matches) == 7) { list($match, $year, $month, $day, $hour, $minute, $second) = $matches; // NOTE: PHP5 timestamp support is 32 bit and ends on 2038-01-19 03:14:07 if ($year < 2038) { $date = mktime($hour, $minute, $second, $month, $day, $year); $format = Zend_Date::TIMESTAMP } }}When converting Zend_Dates to strings, the same as above applies. Here an easy patch could be:
if (! $part) { $part = self::TIMESTAMP;}if (array_key_exists($part, self::$_dateMap)) { $dt = new DateTime('@' . $this->getUnixTimestamp()); $dt->setTimezone(new DateTimeZone($this->getTimezone())); $s = $dt->format(self::$_dateMap[$part]); switch($part) { case 'm': $s = (int) preg_replace('/^0/', '', $s); break; } return $s;}with this dateMap
private static $_dateMap = array( 'yyyy-MM-dd HH:mm:ss' => 'Y-m-d H:i:s', 'MM' => 'm', 'm' => 'i', // spechial handling required! 'M' => 'n', 'd' => 'j', 'h' => 'g', 'H' => 'G', 'HH' => 'H', 's' => 's', 'I' => 'I', 'z' => 'T', 'U' => 'U', 'eee' => 'N', 'D' => 'z', 'e' => 'w', 'X' => 'Z');
As ZF requires PHP 5.2.4 and above, we can use native PHP functions to improve setTimezone:
public function setTimezone($zone = null){ try { $dtz = new DateTimeZone($zone); $this->_offset = $dtz->getOffset(new DateTime('1970-02-01 00:00:00')); $this->_timezone = $zone; } catch (Exception $e) { require_once 'Zend/Date/Exception.php'; throw new Zend_Date_Exception("timezone ($zone) is not a known timezone", $zone); } if (($zone == 'UTC') or ($zone == 'GMT')) { $this->_dst = false; } else { $this->_dst = true; } return $this;}This are just 3 very easy patches, but for a Tine 2.0 Calendar month view request it saves 41% of the request time!
Derick Rethans contributed a great DateTime class to PHP which is in included beginning with version 5.2 which got even more improved in version 5.3. This class solves the year 2038 problem, has full timezone support.
So my first idea was to write a new Zend_Date class which requires PHP version >= 5.3 to be used as a drop in replacement. Unfortunately it turned out, that the design of Zend_Date is not compatible with the DateTime, or to be more precise, the new class would also be slow due to two base restrictions in Zend_Date:
- ISO representation for date string identifiers
- Zend_Date also represents date intervals which have a separate class in PHP.
At the end I implemented on own wrapper class around DateTime which supports some old Zend_Date signatures, so that we don’t had to edit all our code. Zend_Date is only used when Server side locale handling is needed, like in exports.
Switching from Zend_Date to native DateTime brought us a speed up of 66% in a calendar month view request.
As it’s becomeing a FAQ, here a small note, how to procounce “Tine 2.0“:![]()
For those of you who are curious what Tine 2.0 stands for, please find my post from 2007/12
If you still need some more input for the next nerd party, you can find the meaning of our version names here.
Superb organisation! Congrats to the whole Team of the “Chemnitzer Linux Tage”. CLT is definitely on the road of becoming THE german Linux community event. Tine 2.0 will be there again next year!
In anticipation of the new Tine 2.0 version Mialena which is scheduled for March 2010 I’d like to show you a sneak preview about the new file upload features.
Tine 2.0 is now able to upload multiple files at once. Additionally Files can be uploaded from directly out of the operating systems file manager or desktop using drag & drop.
Being an open source project, it’s extremely important for us to chose freely available standard technologies. Therefore it has to to be emphasized, that these new features run in FF, Chrome and Safari without any additional plugins.
The ExtJS wrappers for File Browsing are wrapped into
Ext.ux.file.BrowsePlugin
HTML 5 File uploading for ExtJS is wrapped into
Ext.ux.file.Uploader
Cross site communication in the browser using the XHTTPRequest Object is prohibited by the Same Domain Policy. With HTML 5 this restriction is relaxed within the so called workers.
As of now, normally the browser can only communicate with the domain the document being displayed comes from. As always, most restrictions can be circumvented somehow. Quite a while now, the de facto standard approach for cross-site communication in the wild is JSONP.
In short: A javascript located at the foreign domain is inserted in background. Via the GET url parameters the data of the request is send. The script returned by the foreign server contains code which gets directly executed at include time of this script, e.g: callback({jsondata});
It is widely accepted that JSONP should be rated highly insecure for multiple reasons:
- Including a script of a foreign domain is a build in XSS attack.
- All parameters send to the foreign domain are part of the standard access logs of the foreign web servers.
- …
A new idea for secure cross site communication has come up a year ago utilizes the fact, that the name property of browser windows/frames remains unchanged when a window/frame loads a new document even from a foreign domain. With this, it is possible to create a transport by inserting a hidden iframe which switches its document between the origin- and foreign domain.
This approach has the major advantage, that the data returned by the foreign domain is encoded as a string and could be evaluated in a safely. Moreover the request could be done via POST’s which solves EOI issues with server logs.
While I was aware of this new technique, I never had the need to do cross site request from the browser. In general my approach is to proxy data from foreign domains via the server as this gives a better control. However for a Tine 2.0 related customer project I had the requirement to do cross site request from a website to a Tine 2.0 installation directly from the browser.
Unfortunately I didn’t find any extjs/ext-core implementation of the window.name technique. Moreover I realized, that the implementation of other libraries always POST their request using form submits. But doing all request via form Submits would require an additional API for Tine 2.0 as the standard JSON API talks JSONRPC.
So what I needed was a XHTTPRequest/AJAX solution to be able to utilize the standard Tine 2.0 API’s. For this I created a windowNameConnection Proxy which based on ext-core does AJAX requests to the foreign domain. This sequence diagram visualizes it’s simple workings:

You can find the latest version of the implementation here. The usage of this connection class is straight forward as it works like a normal extjs connection:
var connection = new Ext.ux.data.windowNameConnection({
// this url is autodetected if windowNameConnection is loaded
// from the foreign domain
proxyUrl: https://foreign.domain/windowNameConnection.html
});
connection.request({
url: https://foregin.domain/apiurl,
header: {...}
params: {...},
success: someSuccessCb
});
Of course the ability to do AJAX requests is purchased by a minor performance loss compared to form posts. BUT: The windowNameProxy should only be seen as a fallback for Browsers which are not capable of the HTML5 workers. Users of these old browsers are obviously not keen on enhanced performance. Otherwise they would use an up to date browser.
Cross site communication in the browser using the XHTTPRequest Object is prohibited by the Same Domain Policy. With HTML 5 this restriction is relaxed within the so called workers.
As of now, normally the browser can only communicate with the domain the document being displayed comes from. As always, most restrictions can be circumvented somehow. Quite a while now, the de facto standard approach for cross-site communication in the wild is JSONP.
In short: A javascript located at the foreign domain is inserted in background. Via the GET url parameters the data of the request is send. The script returned by the foreign server contains code which gets directly executed at include time of this script, e.g: callback({jsondata});
It is widely accepted that JSONP should be rated highly insecure for multiple reasons:
- Including a script of a foreign domain is a build in XSS attack.
- All parameters send to the foreign domain are part of the standard access logs of the foreign web servers.
- …
A new idea for secure cross site communication has come up a year ago utilizes the fact, that the name property of browser windows/frames remains unchanged when a window/frame loads a new document even from a foreign domain. With this, it is possible to create a transport by inserting a hidden iframe which switches its document between the origin- and foreign domain.
This approach has the major advantage, that the data returned by the foreign domain is encoded as a string and could be evaluated in a safely. Moreover the request could be done via POST’s which solves EOI issues with server logs.
While I was aware of this new technique, I never had the need to do cross site request from the browser. In general my approach is to proxy data from foreign domains via the server as this gives a better control. However for a Tine 2.0 related customer project I had the requirement to do cross site request from a website to a Tine 2.0 installation directly from the browser.
Unfortunately I didn’t find any extjs/ext-core implementation of the window.name technique. Moreover I realized, that the implementation of other libraries always POST their request using form submits. But doing all request via form Submits would require an additional API for Tine 2.0 as the standard JSON API talks JSONRPC.
So what I needed was a XHTTPRequest/AJAX solution to be able to utilize the standard Tine 2.0 API’s. For this I created a windowNameConnection Proxy which based on ext-core does AJAX requests to the foreign domain. This sequence diagram visualizes it’s simple workings:

You can find the latest version of the implementation here. The usage of this connection class is straight forward as it works like a normal extjs connection:
var connection = new Ext.ux.data.windowNameConnection({
// this url is autodetected if windowNameConnection is loaded
// from the foreign domain
proxyUrl: https://foreign.domain/windowNameConnection.html
});
connection.request({
url: https://foregin.domain/apiurl,
header: {...}
params: {...},
success: someSuccessCb
});
Of course the ability to do AJAX requests is purchased by a minor performance loss compared to form posts. BUT: The windowNameProxy should only be seen as a fallback for Browsers which are not capable of the HTML5 workers. Users of these old browsers are obviously not keen on enhanced performance. Otherwise they would use an up to date browser.
Cross site communication in the browser using the XHTTPRequest Object is prohibited by the Same Domain Policy. With HTML 5 this restriction is relaxed within the so called workers.
As of now, normally the browser can only communicate with the domain the document being displayed comes from. As always, most restrictions can be circumvented somehow. Quite a while now, the de facto standard approach for cross-site communication in the wild is JSONP.
In short: A javascript located at the foreign domain is inserted in background. Via the GET url parameters the data of the request is send. The script returned by the foreign server contains code which gets directly executed at include time of this script, e.g: callback({jsondata});
It is widely accepted that JSONP should be rated highly insecure for multiple reasons:
- Including a script of a foreign domain is a build in XSS attack.
- All parameters send to the foreign domain are part of the standard access logs of the foreign web servers.
- …
A new idea for secure cross site communication has come up a year ago utilizes the fact, that the name property of browser windows/frames remains unchanged when a window/frame loads a new document even from a foreign domain. With this, it is possible to create a transport by inserting a hidden iframe which switches its document between the origin- and foreign domain.
This approach has the major advantage, that the data returned by the foreign domain is encoded as a string and could be evaluated in a safely. Moreover the request could be done via POST’s which solves EOI issues with server logs.
While I was aware of this new technique, I never had the need to do cross site request from the browser. In general my approach is to proxy data from foreign domains via the server as this gives a better control. However for a Tine 2.0 related customer project I had the requirement to do cross site request from a website to a Tine 2.0 installation directly from the browser.
Unfortunately I didn’t find any extjs/ext-core implementation of the window.name technique. Moreover I realized, that the implementation of other libraries always POST their request using form submits. But doing all request via form Submits would require an additional API for Tine 2.0 as the standard JSON API talks JSONRPC.
So what I needed was a XHTTPRequest/AJAX solution to be able to utilize the standard Tine 2.0 API’s. For this I created a windowNameConnection Proxy which based on ext-core does AJAX requests to the foreign domain. This sequence diagram visualizes it’s simple workings:
You can find the latest version of the implementation here. The usage of this connection class is straight forward as it works like a normal extjs connection:
var connection = new Ext.ux.data.windowNameConnection({ // this url is autodetected if windowNameConnection is loaded // from the foreign domain proxyUrl: https://foreign.domain/windowNameConnection.html});connection.request({ url: https://foregin.domain/apiurl, header: {...} params: {...}, success: someSuccessCb});Of course the ability to do AJAX requests is purchased by a minor performance loss compared to form posts. BUT: The windowNameProxy should only be seen as a fallback for Browsers which are not capable of the HTML5 workers. Users of these old browsers are obviously not keen on enhanced performance. Otherwise they would use an up to date browser.
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.
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);
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;
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.
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.
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 bytesunset($smdArray['methods']);echo "Ext.app.JSONRPC_API = " . Zend_Json::encode($smdArray);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;
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.
As promised in my previous post, I’ll introduce Ext.Direct and discuss how it fits with the new JSON-RPC standards and especially with the Zend_Json_Server component.
Ext.direct is a namespace and a bit of a buzzword in the ExtJS 3.0 release. In short, the Ext.direct stuff introduces high level communication features.
The key component of these new features is the “EXT.DIRECT REMOTING SPECIFICATION” which covers the aspects ‘remote procedure call‘ and ’service description’. Ext.Direct implements this specifications within the ExtJS framework as service consumer and for multiple server side stacks as service provider.
Besides having a well defined and documented communication and transport layer Ext.direct also has the advantage, that other ExtJs classes dealing with data can work on the stubs, created based on the ’service map descriptions’. The Ext.tree.TreeLoader can be configured with a directFn to fetch it’s data. More over the Ext.data.DirectStore can be configured with a complete set of direct functions for CRUD actions.
An other cool thing about the javascript implementation of the Ext.direct.RemotingProvider is, that is queues request of the direct stubs for a configurable time span. After this span, it sends one batched request to the server.
However, its important to note, that the “EXT.DIRECT REMOTING SPECIFICATION” is different form the JSON-RPC/JSON-SMD specifications introduced in part 1.
While digging in the specs I found some pros and cons for the “EXT.DIRECT REMOTING SPECIFICATION” compared to the JSON-RPC standardization:
The last point is IMHO the strongest point why not to use this specification. While the rest of the javascript/webservice addicted world tries to find a common standard, ExtJs goes its own way. There are already a number of implementations for the JSON-RPC and JSON-SMD out there, and more and more will follow. I also expect to see service consumers written in PHP which ease writing server-server web-services using the same API.
For that reasons I choose to take the standard Zend_Json_Server implementation and to write a Ext.ux.direct.ZendFrameworkProvider we can use in Tine 2.0 and other Zend Framework based projects.
It’s only fair to note, the the Zend_Json_Server also has several issues which needs to be improved. Most notably:
After all this theory I’ll cover the actual implementation of the Ext.ux.direct.ZendFrameworkProvider in part 3.
As promised in my previous post, I’ll introduce Ext.Direct and discuss how it fits with the new JSON-RPC standards and especially with the Zend_Json_Server component.
Ext.direct is a namespace and a bit of a buzzword in the ExtJS 3.0 release. In short, the Ext.direct stuff introduces high level communication features.
The key component of these new features is the “EXT.DIRECT REMOTING SPECIFICATION” which covers the aspects ‘remote procedure call‘ and ’service description’. Ext.Direct implements this specifications within the ExtJS framework as service consumer and for multiple server side stacks as service provider.
Besides having a well defined and documented communication and transport layer Ext.direct also has the advantage, that other ExtJs classes dealing with data can work on the stubs, created based on the ’service map descriptions’. The Ext.tree.TreeLoader can be configured with a directFn to fetch it’s data. More over the Ext.data.DirectStore can be configured with a complete set of direct functions for CRUD actions.
An other cool thing about the javascript implementation of the Ext.direct.RemotingProvider is, that is queues request of the direct stubs for a configurable time span. After this span, it sends one batched request to the server.
However, its important to note, that the “EXT.DIRECT REMOTING SPECIFICATION” is different form the JSON-RPC/JSON-SMD specifications introduced in part 1.
While digging in the specs I found some pros and cons for the “EXT.DIRECT REMOTING SPECIFICATION” compared to the JSON-RPC standardization:
The last point is IMHO the strongest point why not to use this specification. While the rest of the javascript/webservice addicted world tries to find a common standard, ExtJs goes its own way. There are already a number of implementations for the JSON-RPC and JSON-SMD out there, and more and more will follow. I also expect to see service consumers written in PHP which ease writing server-server web-services using the same API.
For that reasons I choose to take the standard Zend_Json_Server implementation and to write a Ext.ux.direct.ZendFrameworkProvider we can use in Tine 2.0 and other Zend Framework based projects.
It’s only fair to note, the the Zend_Json_Server also has several issues which needs to be improved. Most notably:
After all this theory I’ll cover the actual implementation of the Ext.ux.direct.ZendFrameworkProvider in part 3.
By writing this post, I noticed that it’s quite some stuff, so I broke it up in parts. This part is about the new specifications which help to standardize JSON protocols/apis.
When we started to implement Tine 2.0 about 2 years ago, we got quite some confused request why we chose JSON over SOAP as our data transport between the server and the client. Technically the answer is very easy. JSON protocols only need a fraction of the bandwidths and even more important JSON has a significant better performance on client side, cause no XML parsing is needed.
On the other hand, two years ago SOAP was a mature protocol but JSON only an data encapsulation and no real standards did exist, so that we where forced to implement a custom protocol.
Fortunately this has changed in the last two years. There are three cool standardization efforts in the JSON community I’d like to introduce.
--> { "jsonrpc":"2.0", "method":"Tinebase.login", "params": { "username":"tine20admin", "password":"lars" }, "id":2}<-- {"id":"2","jsonrpc":"2.0","result":{ "success":true, "account": { "accountId":"0e7d07cb453b15f520021e0a433956b234a7c0bd", "accountDisplayName":"Admin Account, Tine 2.0", "accountLastName":"Admin Account", "accountFirstName":"Tine 2.0", "accountFullName":"Tine 2.0 Admin Account", "contact_id":"1" }, "jsonKey":"85160b59b4421bbe2f350c5b3888a2efdbfcb949", "welcomeMessage":"Welcome to Tine 2.0!"}}Multi batch calls are also possible. The client only has to send an array of request objects. Unfortunately the Protocol does not handle “Form-Posts” which are necessary for some special actions like file-uploads.
But nevertheless libraries are starting to implement the spec and this is the most important thing about it!
{"transport":"POST","envelope":"JSON-RPC-2.0","contentType":"application/json","SMDVersion":"2.0","target":"index.php","services": { "Tinebase.login":{ "envelope":"JSON-RPC-2.0", "transport":"POST", "parameters":[{ "type":"string", "name":"username", "optional":false }, { "type":"string", "name":"password", "optional":false}],"returns":"array"}}}The client can use this descriptions to automatically create the stubs for calling the services which already encapsulates all the proxy and transport and protocol overhead. With this, instead of creating an AJAX request per hand you only have to call the method:
Tinebase.login('tine20admin', 'lars', cb);
where cb is a callback function, cause we do our requests asynchronous.
In Part 2 I’ll introduce Ext.Direct and go into the details how to apply this new standards within the Ext.Direct framework.
|
|
May '13 | |||||
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
| 1 | 2 | 3 | 4 | 5 | ||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| 20 | 21 | 22 | 23 | 24 | 25 | 26 |
| 27 | 28 | 29 | 30 | 31 | ||