PDA

View Full Version : Zend_Json_Server



albeva
29 May 2009, 8:05 PM
How to use this with Zend_Json_Server. Has anyone tried that? It seems that specs are different.

albeva
31 May 2009, 10:31 PM
Ok I decided to write a provider for the Ext.Direct to support JSON-RPC 2 specification ( http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal ) mind that this is still a work in progress, but I would like to hear your thoughts.

This provider requires a method definition according to "Service Mapping Description" proposal ( http://groups.google.com/group/json-schema/web/service-mapping-description-proposal )

There are 2 ways to provide the SMD - passing a JSON notation to constructor in the config or let the provider fetch the info from the server using GET request.

The provider: JsonRpc2.js
/**
* Ext.Direct provider for JS-RPC ver 2
* http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal
*
* @author Albert Varaksin
*/

// define the namespace
Ext.ns('Ext.albeva');

/**
* Declare the class
*/
Ext.albeva.JsonRpc2Provider = Ext.extend(Ext.direct.RemotingProvider, {

/**
* Service Mapping Description
*
* @param {Object} _smd
*/
smd : null,


/**
* Create JSON-RPC 2 provider
* @param {Object} config
*/
constructor : function (config)
{
if (config.namespace == undefined)
{
throw "JsonRpc2 requires a namespace";
return;
}
Ext.albeva.JsonRpc2Provider.superclass.constructor.call(this, config);
},


/**
* Connect
*/
connect : function ()
{
if(this.url)
{
this.initAPI();
}
else if(!this.url)
{
throw 'Error initializing RemotingProvider, no url configured.';
}
},


/**
* Request success
*/
onSMDSuccess : function (response, opts)
{
// get response
this.initSMD(Ext.decode(response.responseText));
},


/**
* Initalize SMD
* @param {Object} smd
*/
initSMD : function (smd)
{
// check for correct response
if (smd == undefined || smd == undefined)
{
throw "Invalid response. Expected Service Map Description";
return;
}

// check for version
if (smd.SMDVersion != '2.0')
{
throw "JsonRpc2 works only with version 2.0 of Service Map Description specification";
}

// iterate through the methods
for (var name in smd.methods)
{
var info = smd.methods[name];
var m = {
len : info.parameters.length
}
this.namespace[name] = this.createMethod(name, m);
}

// finalize and notify
this.smd = smd;
this.connected = true;
this.fireEvent('connect', this);
},


/**
* SMD failed.
*
* @param {Object} response
* @param {Object} opts
*/
onSMDFailure : function (response, opts)
{
// do something
},


/**
* Initalize API. The information is pulled using
* Service Mapping Description
* http://groups.google.com/group/json-schema/web/service-mapping-description-proposal
*/
initAPI : function () {

if (this.smd != undefined)
{
this.initSMD(this.smd);
}
else {
Ext.Ajax.request({
url: this.url,
success: this.onSMDSuccess,
failure: this.onSMDFailure,
scope: this
});
}
},


/**
* Fool...
*
* @param {Object} xhr
*/
parseResponse: function(xhr){
if(!Ext.isEmpty(xhr.responseText)){
var o = (typeof xhr.responseText == 'object') ? xhr.responseText : Ext.decode(xhr.responseText);
o.type = 'rpc';
o.tid = o.id;
return o;
}
return null;
},



/**
* Get RPC call data according to
* JSON-RPC 2 spec
*/
getCallData : function (t)
{
return {
jsonrpc : this.smd.methods[t.action].envelope,
method : t.action,
params : t.data,
id : t.tid
};
}


})
Ext.Direct.PROVIDERS['jsonrpc2'] = Ext.albeva.JsonRpc2Provider;


Sample JS app.js
/**
* Simple js-rpc test
*/
Ext.onReady( function () {

Ext.Direct.addProvider({
type : 'jsonrpc2', // the provider type.
url : 'server.php',
id : 'my-provider',
namespace : 'Calculator', // required! methods will be placed in taht
// namespace.
enableBuffer: false,
smd : mySmdApi, // this can be omitted in whitch case
// provider will make GET request to the url
// to try and get SMD
listeners : {
'connect' : Loaded
}
});
});


/**
* Fully loaded...
*/
function Loaded ()
{
new Ext.Button({
renderTo : document.body,
text : 'Send',
listeners : {
'click' : function () {
Calculator.add(10,10, function (a, b) {
alert(a);
});
}
}
});
}



Sample PHP using Zend_Json_Server (Zend version 1.8): server.php
<?php
/**
* Simple example of Zend_Json_Server
*/


/**
* Calculator - sample class to expose via JSON-RPC
*/
class Calculator
{
/**
* Return sum of two variables
*
* @param int $x
* @param int $y
* @return int
*/
public function add($x, $y)
{
return $x + $y;
}

/**
* Return difference of two variables
*
* @param int $x
* @param int $y
* @return int
*/
public function subtract($x, $y)
{
return $x - $y;
}

/**
* Return product of two variables
*
* @param int $x
* @param int $y
* @return int
*/
public function multiply($x, $y)
{
return $x * $y;
}

/**
* Return the division of two variables
*
* @param int $x
* @param int $y
* @return float
*/
public function divide($x, $y)
{
return $x / $y;
}
}


// Autoload Zend classes
// -----------------------------------------------------------------------------
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

// The JSON-RPC server
// -----------------------------------------------------------------------------
$server = new Zend_Json_Server();
$server->setClass('Calculator');

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

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

// if passing JSON notation directly to the
// config of the provider then collect SMD into a variable
echo "var mySmdApi = ($smd)";
// otherwise:
// header('Content-Type: application/json');
// echo $smd;
return;
}

// handle the request
$server->handle();




Your thoughts, suggestions etc are welcome. I haven't fully tested this yet and there are some problems - for example form submit is not yet supported. Also JSON_RPC does nto return the action as Ext.Direct requires. But these can be solved.

myram
2 Jun 2009, 2:44 AM
Although you suggest to echo $mySmdApi variable at server-side it seems that JsonRpc2Provider doesn't use smd variable in method requests. I added a line of code to initSMD method:


// finalize and notify
this.smd = smd;
this.url = smd.target; // now provider use smd.target url (as noted in SMD specification) in method calls
// instead of url specified in Ext.Direct.addProvider
this.connected = true;
this.fireEvent('connect', this);

And now we can use different urls for getting SMD and calling methods.

albeva
2 Jun 2009, 9:06 AM
probably better this way. thanks

ryzmen
7 Jun 2009, 8:38 AM
Great job, albeva.

I think there's an error somewhere in Ext.Direct (or maybe in JsonRpc2?). When I call remote method without parameters, JSON request looks like this:

{"jsonrpc":"JSON-RPC-2.0","method":"getStoragesData","params":null,"id":3}

params should be JSONArray, not null. Zend_Json_Server_Request also throws an exception.

PS. Hi everybody :) It's my 1st post here and 3rd intensive day with ExtJS ;) I wanna to use them in my new project.

myram
8 Jun 2009, 5:37 AM
Hi, I've noticed this error too. Once I've solved this problem, but now can't remember how :)
I think there may be a problem in Ext.encode (Ext.util.JSON.encode) method: if no data is present it returns "null" as a result:


this.encode = isNative ? JSON.stringify : function(o){
if(typeof o == "undefined" || o === null){
return "null";
...


Now I'm trying to use JsonRpc2 function as directFn in DirectStore object, but I'm getting infinite loop in Ext.util.JSON.encode method - 'params' field of jsonData, that is being encoded before calling server function, contains cycle references :(

ryzmen
11 Jun 2009, 10:28 AM
myram, you get infinite loop when there're more then 1 or 2 params to the remote func? I found a solution: DirectProxy.paramOrder.

myram
17 Jun 2009, 1:42 AM
Thanx, but I've nevertheless decided to use api.load function to call remote proc instead of directFn - too difficult ( for me :) ) to find solution for successful using remote proc as directFn in DirectStore.

And I offer to use this changed code in case of calling remote function without parameters (you've mentioned above) in JsonRpc2 provider:


getCallData : function (t)
{
return {
jsonrpc : this.smd.methods[t.action].envelope,
method : t.action,
params : t.data === null ? new Array() : t.data,
id : t.tid
};
}

For me it works.

albeva
17 Jun 2009, 5:11 AM
Thanks guys. I've been working a bit on this and will soon post updated version.

Dumbledore
25 Jun 2009, 2:50 AM
can some made a complete package with a samle code (Ext-Zend)?

pmarko
27 Jun 2009, 12:21 PM
I wouuld like to see sample package as well. Thanks.

jon.whitcraft
6 Nov 2009, 7:19 AM
Any update on the JsonRpc2 provider?

Air_Mike
6 Nov 2009, 9:50 AM
+1 interested in this

JorisA
8 Nov 2009, 6:50 AM
I also would really like to see Ext/ZF integretion. any updates? :">

jon.whitcraft
9 Nov 2009, 6:22 AM
I'm trying to get this to work with parameters but it's not working..can anyone help?

albeva
17 Nov 2009, 2:39 PM
I'm trying to get this to work with parameters but it's not working..can anyone help?Sample?

I will review this over the weekend and post an updated package with a sample soon.

mynsa04
10 Jun 2010, 7:08 AM
it's still alive?