A Gateway class for Amfphp remoting.

5

Featuring usage instructions, source code and Chuck Norris!

on 29/3/10

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:

chucknorris-flex.zip [184kb]

Here's the php files (including the amfphp version 1.9)

chucknorris-php.zip [483kb]

Jason Smale

  -  http://www.jwswj.com

on 30/3/10

Great article mate. Look forward to using your library in my next freelance project :)

Ben Pearson

  -  http://developinginthedark.com

on 30/3/10

Nice one tones. Enjoyed reading how some of our projects are put together (only ever seen them from the PHP side). Its a neat solution combining the best of CakePHP controllers and JQuery callbacks. Also good, to the point demo, not only did I learn about Flex, but that "Chuck Norris watches 60 minutes in 20 minutes" :P

Be careful releasing this info though, I might just start messing around in our Flex code... bringing my tabbing and syntax formatting that I know you love :P

Charles

on 5/4/10

very nice tutorial.

Is there some flex framework to use easier amfphp ? Like yours but not just an example...

blil

on 10/4/10

do u know why if i try to pass a php class to flex I become a this error :SecurityError: Error #2000: Aucun contexte de s?curit? n'est actif.

If php return a string, it's ok... but the class it doesn't like it...

Tony Milne

  -  http://tonymilne.com.au

on 14/4/10

@Charles: There are a couple of decent Flex frameworks out there, like: Cairngorm, Mate and PureMVC, but I don't think they will necessarily make using amfphp any easier for you. There's a good article on choosing a Flex framework that compares those three frameworks.

Have you got something specific in mind that you're trying to put together?

@blil: I don't know French, but the fact that it works for strings and not objects suggests that it is not mapping the flex/php classes properly. Have a look over the following code snippets and see if your code is set up in a similar way. You should have a RemoteClass in your Flex, and a $_explicitType in your PHP.

In Flex:

[RemoteClass(alias="Example")]
[Bindable]
public class Example {
    public var id:int;
    public var foo:String;
    public var bar:String;
}
And in PHP:

class Example {
    var $_explicitType = "Example";

    var $id;
    var $foo;
    var $bar;

    // Php methods here...
}

You should leave a comment:

Some tags are allowed: (a, b, blockquote, code, em, i, u, pre, strong).

who am I?

I live in Melbourne. I work at Inlight Media. I'm passionate about web and software development. I like jQuery, CakePHP, Flex. I can code. I can't draw. I play basketball with the Spiderpigs and the Generals. I love snowboarding in the winter and wakeboarding in the summer. I play computer games too often.