1. #1
    Sencha User
    Join Date
    Mar 2007
    Location
    London, UK
    Posts
    143
    Vote Rating
    0
    albeva is infamous around these parts albeva is infamous around these parts

      0  

    Default Zend_Json_Server

    Zend_Json_Server


    How to use this with Zend_Json_Server. Has anyone tried that? It seems that specs are different.

  2. #2
    Sencha User
    Join Date
    Mar 2007
    Location
    London, UK
    Posts
    143
    Vote Rating
    0
    albeva is infamous around these parts albeva is infamous around these parts

      0  

    Default


    Ok I decided to write a provider for the Ext.Direct to support JSON-RPC 2 specification ( http://groups.google.com/group/json-...c-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-...ption-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
    Code:
    /**
     * 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
    Code:
    /**
     * 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 Code:
    <?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.

  3. #3
    Ext User
    Join Date
    May 2009
    Posts
    5
    Vote Rating
    0
    myram is on a distinguished road

      0  

    Default


    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:
    Code:
            // 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.

  4. #4
    Sencha User
    Join Date
    Mar 2007
    Location
    London, UK
    Posts
    143
    Vote Rating
    0
    albeva is infamous around these parts albeva is infamous around these parts

      0  

    Default


    probably better this way. thanks

  5. #5
    Ext User
    Join Date
    Jul 2008
    Location
    Poland, Warsaw
    Posts
    3
    Vote Rating
    0
    ryzmen is on a distinguished road

      0  

    Default


    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.

  6. #6
    Ext User
    Join Date
    May 2009
    Posts
    5
    Vote Rating
    0
    myram is on a distinguished road

      0  

    Default


    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:
    Code:
        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

  7. #7
    Ext User
    Join Date
    Jul 2008
    Location
    Poland, Warsaw
    Posts
    3
    Vote Rating
    0
    ryzmen is on a distinguished road

      0  

    Default


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

  8. #8
    Ext User
    Join Date
    May 2009
    Posts
    5
    Vote Rating
    0
    myram is on a distinguished road

      0  

    Default


    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:
    Code:
        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.

  9. #9
    Sencha User
    Join Date
    Mar 2007
    Location
    London, UK
    Posts
    143
    Vote Rating
    0
    albeva is infamous around these parts albeva is infamous around these parts

      0  

    Default


    Thanks guys. I've been working a bit on this and will soon post updated version.

  10. #10
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    Germany
    Posts
    678
    Vote Rating
    13
    Dumbledore will become famous soon enough

      0  

    Default


    can some made a complete package with a samle code (Ext-Zend)?