1. #1
    Sencha User
    Join Date
    Mar 2007
    Location
    Haarlem, Netherlands
    Posts
    1,243
    Vote Rating
    10
    TommyMaintz will become famous soon enough TommyMaintz will become famous soon enough

      0  

    Default Alternative Ext Direct PHP Implementation

    Alternative Ext Direct PHP Implementation


    Updated 08/04/2009: Fixed len property issue and class level path's

    Hi guys,

    I thought it would be nice to show another way of implementing Direct on a PHP server stack. It is using PHP comments and reflection to create the API for you automagically. I haven't documented it properly yet, and I dont have a client-side example to show it of, but I thought I would put it out here already anyway for you to try. I think the result is quite flexible and the router part should be easily extensible to use this with any server-side MVC framework out there . You can download the source code here.

    It consists of 3 classes called:
    • ExtDirect_API
    • ExtDirect_Router
    • ExtDirect_CacheProvider

    An example api.php that you would include in a <script> tag:
    PHP Code:
    <?php
    session_start
    ();

    // Include ExtDirect PHP Helpers
    require_once('ExtDirect/API.php');
    require_once(
    'ExtDirect/CacheProvider.php');

    // I created a Cache to save the parsed API so it doesnt have to
    // do all the reflecting and parsing over and over again
    $cache = new ExtDirect_CacheProvider('cache/api_cache.txt');

    // Create an ExtDirect_API instance
    $api = new ExtDirect_API();

    // Set up some special config options
    $api->setRouterUrl('router.php'); // default
    $api->setCacheProvider($cache);
    $api->setNamespace('Ext.ss');
    $api->setDescriptor('Ext.ss.APIDesc'); // defaults to Ext.app.REMOTING_API

    // These defaults will be applied to each class when using the add method later on
    $api->setDefaults(array(
        
    'autoInclude' => true// this will automatically figure out file paths and include them
        
    'basePath' => 'classes' // the base folder in which all your classes exist
    ));
    // if you want to use autoInclude you have to make sure that your classes (without the prefix) 
    // are named the exact same as the name of the file it exists in and that only one 
    // class exists in each file.

    // Now we have to add all the classes we want to scan for remotable methods
    $api->add(
        array(
            
    'Echo' => array('prefix' => 'Class_'), // Echo is a reserved keyword so i used a prefix
            
    'Exception' => array('prefix' => 'Class_'), // Same reason as Echo
            
    'Time',
            
    'File'
        
    )
    );
    // The config options you can specify for each individual class are:
    // - autoInclude
    // - subPath (to specify classes inside a nested folder structure, starts from the basePath)
    // - prefix

    // this will generate the API and output it properly for you
    $api->output();

    // by saving the state the router doesnt have to do all this parsing and 
    // reflecting again. here i chose to save the state in a session but you
    // can save it wherever you want
    $_SESSION['ext-direct-state'] = $api->getState();
    ?>
    Obviously another important part of the implementation is the router. Here is an example of a router.php:
    PHP Code:
    <?php
    session_start
    ();

    require_once(
    'ExtDirect/API.php');
    require_once(
    'ExtDirect/Router.php');

    // this should always be set but if its not, then execute api.php without outputting it
    if(!isset($_SESSION['ext-direct-state'])) {
        
    ob_start();
        include(
    'api.php');
        
    ob_end_clean();
    }

    // A router needs an API instance aswell so thats why we create one and set its
    // state to what we saved in the session in api.php
    $api = new ExtDirect_API();
    $api->setState($_SESSION['ext-direct-state']);
     
    // Create the router, dispatch the call and output the response
    $router = new ExtDirect_Router($api);
    $router->dispatch();
    $router->getResponse(true); // true to print the response instantly
    ?>
    I also included some sample classes inside the /classes/ folder inside the rar file, but basically its a matter of putting comments about your function that include tags like @remotable, @formHandler and @remoteName (to specify a different name for a method on the client side). Here is an example of a simple Echo class that returns whatever you pass its send function:
    PHP Code:
    <?php
        
    class Class_Echo {
            
    /**
             * @remotable
             */
            
    public function send($string){
                return 
    $string;
            }
        }
    ?>

    Here is a simple File class that shows of some of the other options like @formHandler (see how it handles file uploads nicely) and @remoteName (list is a reserved keyword in PHP so thats why we have to use the @remoteName option)
    PHP Code:
    <?php
        
    class File {
            
    /**
             * @remotable
             * @remoteName list
             */
            
    public function listFiles($folder){
                if(
    substr($folder03) === '../') {
                    return 
    'Nice try buddy';
                }
                return 
    array_slice(scandir($folder), 2);
            }
            
            
    /**
             * @remotable
             * @formHandler
             */
            
    public function add($post$files){
                if(
    $files && !empty($files[$post['formField']])) {
                    
    $file $files[$post['formField']];
                    
    move_uploaded_file($file['tmp_name'], 'data/' $file['name']);
                    return 
    pathinfo('data/' $file['name']);
                }            
            }
        }
    ?>
    You can find all the source code and more examples inside the rar file.
    Attached Files

  2. #2
    Ext User fabrizim's Avatar
    Join Date
    Mar 2007
    Location
    Lowell, MA
    Posts
    47
    Vote Rating
    0
    fabrizim is on a distinguished road

      0  

    Default Nice!

    Nice!


    Hi Tommy-

    That is great. I wrote something similar for database field instantiantion / altering by parsing the files for doc comments in PHP4 - I didn't even realize the PHP5 reflection API lets you grab the doc comments. I plan on continuing development with my stuff and if I come up with any additional / generic parsing stuff, I'll post it back.

    Best Regards-
    Mark

  3. #3
    Sencha User
    Join Date
    Mar 2007
    Location
    Haarlem, Netherlands
    Posts
    1,243
    Vote Rating
    10
    TommyMaintz will become famous soon enough TommyMaintz will become famous soon enough

      0  

    Default


    Hi Fabrizim,

    I had never looked at the Reflection capabilities in PHP5 before, but when I started doing this PHP router I thought it would be very useful. And it turned out it was. Im interested in what you come up with in regards to additional / generic parsing of the classes and looking forward to your post.

  4. #4
    Sencha - Training Team mrsunshine's Avatar
    Join Date
    Sep 2008
    Location
    Germany - Darmstadt
    Posts
    691
    Vote Rating
    12
    mrsunshine will become famous soon enough

      0  

    Default


    Ported your nice classes to a TYPO3 Extension will it release it soon

  5. #5
    Sencha User steffenk's Avatar
    Join Date
    Jul 2007
    Location
    Haan, Germany
    Posts
    2,664
    Vote Rating
    7
    steffenk has a spectacular aura about steffenk has a spectacular aura about steffenk has a spectacular aura about

      0  

    Default


    yeah, this can be used in TYPO3 very well, great! (increase the TYPO3 lobby )
    vg Steffen
    --------------------------------------
    Release Manager of TYPO3 4.5

  6. #6
    Ext User meza's Avatar
    Join Date
    Mar 2008
    Posts
    5
    Vote Rating
    0
    meza is on a distinguished road

      0  

    Default ExtDirectPack refactored

    ExtDirectPack refactored


    Hi!

    There are some huge problems with the ExtJs's ExtDirectPack.
    The first enormous design error is, that we definitely don't want a third-party tool to know the way our classes should be constructed. First I tried the reverse-engineers way to implement the Sphicy style automatic dependency injections. But still, that's not what we want from a third-party. The other trouble was the untestability. Anyone interested in php unit-testing can find a great slide by Sebastian Bergman at this link.

    So I've started to solve these problems, and below is the first peak of it.
    The key concept is to add already constructed instances to the api instead of classnames.

    First of all, How a simple class looks like:
    TestClass.php
    Code:
    <?php
    class TestClass
    {
        /**
         * @remotable
         */
        public function shout($what)
        {
            return 'SHOUT: '.$what;
        }
    
        /**
         * @remotable
         */
        public function postHandler($name,$files=array()){
            return array(
              'gotName'=>$name,
              'gotFiles'=>$files
            );
        }
    }
    ?>
    Now for the Api. It works the same way, you include it on client-side in a <script>

    api.php
    Code:
    <?php
    
    require_once('TestClass.php');
    require_once('ExtDirect/Api.php');
    
    $api=new ExtDirect_Api();
    $api->add(new TestClass());
    
    //$api->setRouterUrl('router.php');
    
    echo $api->output();
    
    ?>
    Because the router.php is still the default, it is commented out.

    router.php
    Code:
    <?php
    
    require_once('TestClass.php');
    require_once('ExtDirect/Api.php');
    require_once('ExtDirect/Router.php');
    
    $api=new ExtDirect_Api();
    $api->add(new TestClass());
    
    //$api->setRouterUrl('router.php');
    
    $router = new ExtDirect_Router($api);
    
    echo $router->getResponse();
    
    ?>
    And that's about it.
    Grab the source from here.

    The development is far from finished. Caching and the yet not refactored candy-s are soon to come. This release is just the absolute core

    Due to the refactoring, the code is all covered with tests which ensure the stability and functionality. A bit later the project will be public to see for anyone.

  7. #7
    Ext JS Premium Member
    Join Date
    Jan 2008
    Posts
    51
    Vote Rating
    0
    mark_l_lewis is on a distinguished road

      0  

    Default


    L]hi,

    I'm having a little problem with the Ext.Direct PHP implementation. I have copied the entire example locally.

    I then created a basic html file, included the api.php as script source. added a button and then implemented a handler.
    The Handler below is called successfully, but the return value is undefined.

    PHP Code:
    var rv Ext.ss.Echo.send('hello, world');
                    
                    
    alert (rv
    ;

    Using firebug I examined the router.php response as follows:

    PHP Code:
    {"type":"rpc","tid":2,"action":"Echo","method":"send","result":"hello, world"
    I'm not sure why the
    PHP Code:
    rv 
    is coming up as undefined?

    I have downloaded the latest version of Ext RC2

    Any help or direction would be appreciated.

    Thanks,
    Mark

  8. #8
    Sencha - Training Team mrsunshine's Avatar
    Join Date
    Sep 2008
    Location
    Germany - Darmstadt
    Posts
    691
    Vote Rating
    12
    mrsunshine will become famous soon enough

      0  

    Default


    i think you have to handle the response like that,

    PHP Code:
     Ext.ss.Echo.send(text.getValue(), function(resulte){
                    var 
    e.getTransaction();
                    
    out.append(String.format('<p><b>Successful call to {0}.{1} with response:</b><xmp>{2}</xmp></p>',
                           
    t.actiont.methodExt.encode(result)));
                    
    out.el.scrollTo('t'100000true);
                }); 

  9. #9
    Ext JS Premium Member
    Join Date
    Jan 2008
    Posts
    51
    Vote Rating
    0
    mark_l_lewis is on a distinguished road

      0  

    Default


    and you truly are, mr sunshine :-)

    that works a treat. although, is there another implementation which doesn't require a function handler for the return value?

    the docs are a little thin on direct, although i'm piecing the bits together.

  10. #10
    Sencha - Community Support Team JeffHowden's Avatar
    Join Date
    Mar 2007
    Location
    Forest Grove, OR
    Posts
    1,038
    Vote Rating
    1
    JeffHowden is on a distinguished road

      0  

    Default


    Quote Originally Posted by mark_l_lewis View Post
    PHP Code:
    var rv Ext.ss.Echo.send('hello, world');
                    
    alert (rv
    ;
    Keep in mind that Ext.Direct is asynchronous. So, that means that in order to act upon the value being returned by the server, you'll have to specify a callback in your method call to the server. Mr. Sunshine illustrates that, but didn't specifically indicate the issue was with not staying within the asynch paradigm.
    Jeff Howden
    Ext JS - Support Team Volunteer
    jeff@extjs.com

    Any and all code samples that are authored by me and posted on the Ext forums or website are hereby released into the public domain and I release anyone or entity of liability by using said code samples unless explicitly stated otherwise.

    Opinions are mine and not necessarily endorsed by Ext, LLC. Please do not contact me directly for assistance unless requested by me.