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($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']);
}
}
}
?>
You can find all the source code and more examples inside the rar file.