A Gateway class for Amfphp remoting.
I thought I'd share a bit about the ActionScript Gateway class we've been using in our Flex/Amfphp projects at work.
The Gateway class follows the Singleton Pattern and takes inspiration from the common jQuery practice of using anonymous functions for event handlers. E.g:
$("a.example").click(function() {
// Link clicked. :D
});
I will explain the usage and benefits using code snippets from a sample application that you can demo and download below. If something doesn't quite make sense, try looking at the full source code or post a question in the comments.
The Gateway class is designed to be portable; you should be able to drop it into a new project without any modification. There are two files required: RemotingConnection and Gateway - they both belong in the com.inlight.remoting package and should be placed in the /com/inlight/remoting directory. The Gateway class requires the gatewayUrl property to be set before it can be used (dependency injection).
So, start by adding an initialize handler to the application:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
initialize="initializeHandler()">
and in that function, set the gatewayUrl...
protected function initializeHandler():void {
// Initialise the Gateway for use throughout the application.
Gateway.gatewayUrl = Constants.GATEWAY_URL;
}
If you peek into the Constants class you will see the GATEWAY_URL looks like this:
public class Constants
{
/* Amfphp service urls: */
public static const BASE_URL:String = "http://chucknorris/";
public static const AMFPHP_URL:String = BASE_URL + "amfphp/";
public static const GATEWAY_URL:String = AMFPHP_URL + "gateway"
public function Constants() {}
}
Please note: you may need to adjust some of the config values. E.g. BASE_URL may need to be "http://localhost/" and GATEWAY_URL may need to be "gateway.php" - depending on how you've configured your web server.
We could start writing calls using our Gateway class. The function declaration looks like this:
Gateway.call(command:String, callback:Function, errorHandler:Function, ...parameters):void {}
command [String] : A mapping to the php function we want to call in the format of: 'class_name.function_name'.
callback [Function] : This is the function that will be called upon successful completion of the php function. It can be declared with a parameter, which will contain the results returned from the php function.
errorHandler [Function] : Same as callback but will be called if something shits itself along the way.
...parameters : This is cool. You can specify as many parameters as you like and they will be passed into the php function you are calling (in the order you specified).
However, I don't use the Gateway call function directly from my components, instead I make those calls from ActionScript classes called controllers (in the past I had called them services, but they're essentially the same). The benefit I get from doing this is that I can extend a BaseController, where I define my errorHandler and other common functions that should be present in all of my controllers. For example: getAll and getById are two functions that can be used across all of my controllers. We now have strongly named and typed functions matching our php functions, contained in light weight and specific ActionScript controllers. Neat.
Take the QuotesController from our example application, it has two methods getRandom() and getByIndex() as well as the ones inherited from the BaseController (getAll and getById):
public class QuotesController extends BaseController
{
/**
* Controller class name as is in php/cakephp.
*/
public const CONTROLLER:String = "QuotesController";
public function QuotesController() {}
public function getRandom(callback:Function):void {
Gateway.call(controller+".getRandom", callback, errorHandler);
}
public function getByIndex(index:int, callback:Function):void {
Gateway.call(controller+".getByIndex", callback, errorHandler, index);
}
}
We are only using getRandom() in our application. Note: quotesController is a protected instance variable of type QuotesController.
quotesController.getRandom(function(response):void {
txtQuote.text = response;
});
The last piece of functionality built into the Gateway class worth mentioning is the pre and post call hooks. Our typical applications are much more complex than the demo, and often have multiple asynchronous calls being handled at once - as such, we had the need to indicate to the user that the application was busy loading. So, as you'll notice, when the Gateway is waiting for one or more responses from the server, the mouse cursor turns to the busy indicator and when it's finished receiving responses it returns back to normal. Currently there isn't any way to pass in your own pre or post call functions to the Gateway class - but you could override them in a sub class (or just hack the functions as needed).
Here's the demo:
As you can see, clicking the "Fetch Another" button makes an Amfphp request to the server, switching the mouse cursor to busy while the request takes place. When the response is returned, the callback function runs and updates the UI with the quote.
Here's the flex project files:
Here's the php files (including the amfphp version 1.9)