There are three solutions for Flash/Flex remoting in PHP (through the AMF format): AMFPHP, SabreAMF and WebORB. I chose SabreAMF because it isn’t very intrusive and its naming conventions of the classes fits nicely with Zend_Loader’s autoloader.
One problem with SabreAMF is that its documentation is very sparse. There’s one at Adobe but it’s a too complex for starters. The purpose of this article is to get started with getting SabreAMF up and running.
Follow up:
Before we get started, it should be noted that PHP’s error reporting will get in the way if it happens to print those messages in the standard output. Not only won’t you see them, they’ll also screw up the actual AMF messages. So you might want to set the display_errors in your php.ini as stderr or 0 and read the error logs instead.
Let’s start out with the PHP access point first, note that I’ll be using Zend_Loader::registerAutoLoad() to reduce the number of include_once in the code:
PHP:
| date_default_timezone_set( ‘UTC’ ); | |
| $includePath = array( ‘.’, ‘C:/wamp/php/lib’, ‘C:/wamp/php/PEAR’ ); | |
| set_include_path( implode( PATH_SEPARATOR, $includePath ) ); | |
| include( "Zend/Loader.php" ); | |
| Zend_Loader::registerAutoload(); | |
| function OnExec( $service, $method, $data ) { | |
| } | |
| $callbackServer = new SabreAMF_CallbackServer(); | |
| $callbackServer->onInvokeService = ‘OnExec’; | |
| $callbackServer->exec(); |
This is the most basic server but it does well for our purposes. As for the Flex side:
ActionScript:
| <?xml version="1.0"?> | |
| <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" pageTitle="Client"> | |
| <mx:RemoteObject id="ro" destination="Student" endpoint="http://localhost/amftest/amf-serve.php" result="resultHandler( event )" fault="faultHandler( event )"> | |
| </mx:RemoteObject> | |
| <mx:Script> | |
| <![CDATA[ | |
| import mx.collections.ArrayCollection; | |
| import mx.rpc.events.*; | |
| import mx.controls.Alert; | |
| import mx.utils.ArrayUtil; | |
| import mx.rpc.*; | |
| | |
| private function load():void { | |
| ro.getUsers(); | |
| } | |
| private function resultHandler( event:ResultEvent ):void { | |
| Alert.show( event.toString() ); | |
| } | |
| private function faultHandler( event:FaultEvent ):void { | |
| Alert.show( event.toString() ); | |
| } | |
| ]]> | |
| </mx:Script> | |
| <mx:Button click="load()" label="Load" /> | |
| </mx:Application> |
Let’s start off by enumerating the arguments in the OnExec callback function:
$service is the ’source’ of the callee. That is, if you placed a source="ClassFoo" as an attribute in <mx:RemoteObject>, $service will have a value of ClassFoo. Usually, a class with a similar classname is instantiated.$method is the name of the method to be invoked. So if ro.methodName() is called from the Flex side, $method will have the value methodName.$data is an array which contains the parameters to be passed.Now as for the MXML, the main object responsible for the connection is <mx:RemoteObject>:
destination this is a required attribute. However, if the endpoint attribute is specified, this can be ignored (i.e. just place anything) at least if SabreAMF is used. If the endpoint is not specified however, it will look for a ‘channel’ under the specified destination in its channelSet or in the services configuration xml file.endpoint should point to the remote gateway. This is optional but if this is omitted, the endpoint will be a channel in the destination.source the class the ‘callee’ belongs to. Refer to the earlier explanation of $method.result the code to execute upon sucessfully getting the feedback from the server. event:mx.rpc.events.ResultEvent is defined in the scope.fault similar to result but event:mx.rpc.events.FaultEvent is defined instead. Self-explanatory.Trackback URL (right click and copy shortcut/link location)