-
11 May 2009 2:40 PM #1Sencha - Sencha Touch Dev Team
- Join Date
- Mar 2007
- Location
- Haarlem, Netherlands
- Posts
- 1,235
- Vote Rating
- 4
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:
Obviously another important part of the implementation is the router. Here is an example of a router.php: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();
?>
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
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
?>
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)
You can find all the source code and more examples inside the rar file.PHP Code:<?php
class File {
/**
* @remotable
* @remoteName list
*/
public function listFiles($folder){
if(substr($folder, 0, 3) === '../') {
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']);
}
}
}
?>
-
11 May 2009 5:17 PM #2
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
-
12 May 2009 8:28 AM #3Sencha - Sencha Touch Dev Team
- Join Date
- Mar 2007
- Location
- Haarlem, Netherlands
- Posts
- 1,235
- Vote Rating
- 4
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.
-
14 May 2009 8:24 AM #4
Ported your nice classes to a TYPO3 Extension will it release it soon
-
18 May 2009 5:08 AM #5
yeah, this can be used in TYPO3 very well, great! (increase the TYPO3 lobby
)vg Steffen
--------------------------------------
Release Manager of TYPO3 4.5
energlobe.de - german online magazine
-
29 May 2009 3:22 AM #6
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
Now for the Api. It works the same way, you include it on client-side in a <script>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 ); } } ?>
api.php
Because the router.php is still the default, it is commented out.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(); ?>
router.php
And that's about it.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(); ?>
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.
-
4 Jun 2009 2:44 AM #7
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:
I'm not sure why thePHP Code:{"type":"rpc","tid":2,"action":"Echo","method":"send","result":"hello, world"}
is coming up as undefined?PHP Code:rv
I have downloaded the latest version of Ext RC2
Any help or direction would be appreciated.
Thanks,
Mark
-
4 Jun 2009 3:00 AM #8
i think you have to handle the response like that,
PHP Code:Ext.ss.Echo.send(text.getValue(), function(result, e){
var t = e.getTransaction();
out.append(String.format('<p><b>Successful call to {0}.{1} with response:</b><xmp>{2}</xmp></p>',
t.action, t.method, Ext.encode(result)));
out.el.scrollTo('t', 100000, true);
});
-
4 Jun 2009 3:11 AM #9
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 Jun 2009 11:16 PM #10Sencha - Community Support Team
- Join Date
- Mar 2007
- Location
- Forest Grove, OR
- Posts
- 1,038
- Vote Rating
- 0
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.




Reply With Quote