I was recently working in a project that needed a webservice, I quickly turned to the oh so great AMFPHP project. It’s easy to use, well built and it doesn’t send XML but AMF objects instead, so you don’t have to do any parsing.
So, to start with, we’ll setup our AMFPHP service. Download the latest version from the site and extract the ‘amfphp’ folder in the root of the website you’re working on. Now, go to the ‘services’ (inside amfphp) folderand create a new php file and let’s name it ‘mySite.php’. Edit the file and add this in it:
<?php class mySite { const pass = '9sdEWHf2jdFJcd@'; // Web service password public function test($p, $msg) { if($p == self::pass) { return $msg; } return false; } } ?>
To make sure it works, go to your amfphp service browser (http://yousite.com/amfphp/browser) and select your service (mySite). You should see a list of possible functions to call at the top, but we only have one and it’s currently selected. To test, enter ’9sdEWHf2jdFJcd@’ in the ‘p’ field and whatever message you want in the ‘msg’ field. Press the ‘call’ button and you should see the response. If any of this didn’t work, you probably have a syntax error in the php code.
Now, this is all fine and dandy, but how do you connect to it from within your little flash application?
First, you need the flash remoting classes installed. This will make you connect to the web service. These are not installed by default when you install flash, this is extra.
After you’ve done that, you just need to create a new class in your actionscript project called AMFConnection.as and then copy/paste the following code in:
/* * AMFConnection.as * * Author: Michel Boudreau m dot boudreau at driip dot com */ import mx.utils.Delegate; import mx.services.Log; import mx.remoting.Service; import mx.remoting.PendingCall; import mx.rpc.RelayResponder; import mx.rpc.FaultEvent; import mx.rpc.ResultEvent; import mx.remoting.debug.NetDebug; import mx.events.EventDispatcher; /** * Sends and receives data from a web service using http/https requests. * * @see mx.remoting.Service * @see mx.events.EventDispatcher */ class AMFConnection extends EventDispatcher{ /** The callback function to be saved and used later when the server responds back. */ private var callback:Function; /** * The loading boolean let's different parts of the class know if we're currently * waiting for a response from the server */ private var isLoading:Boolean; /** The queue of calls waiting to be sent after the precedent call is received */ private var callQueue:Array; /** interval id number for the timeout of a webservice call */ private var timeout:Number; /** the timeout callback function to be used if the webservice call times out */ private var timeoutCallback:Function; /** holds the amounts of retries before it stops **/ private var retry:Number; /** our web service object **/ private var service:Service; /** stores the current method we're calling **/ private var method:String; /** store WS password **/ private var password:String; /** The event dispatcher functions **/ public var addEventListener:Function; public var removeEventListener:Function; public var dispatchEvent:Function; /** * AMFConnection class constructor * * <br/><br/> * Usage: {@code "var ws:AMFConnection = new AMFConnection( 'http://localhost/ws/gateway.php', * 'serviceName' * );"} * * @param _address The URL of the web service to connect to * @param _service The service name on which to call * @param _service [optional] Set the password of the WS, it will be set as the first argument * to every call */ public function AMFConnection(_address:String, _service:String, _password:String) { this.retry = 0; this.isLoading = false; this.callQueue = new Array(); this.password = _password; // Initialize EventDispatcher EventDispatcher.initialize(this); // ** DEV ONLY ** // NetDebug.initialize(); var log:Log = new Log(Log.VERBOSE); log.onLog = function(txt) { trace(txt); } // ** DEV ONLY ** // // Connect to gateway var responder:RelayResponder = new RelayResponder(this,"onResult","onFault"); this.service = new Service(_address, log, _service, null, responder); } /** * Calls the specified method within the service object. * * <br/><br/> * Usage: {@code "ws.call( 'serverMethod', * Delegate.create(this, this.onCallback), * ['someData', 'moreData'], * Delegate.create(this, this.onTimeout * );"} * * @param _method the server method to call * @param _callback the function to callback after a response is received from the server * @param _data the data to be sent to the server * @param _timeout The function to call when a timeout occurs * @return Void */ public function call(_method:String, _callback:Function, _data:Array, _timeout:Function):Void { if(!this.isLoading) { // save callback and timeout this.callback = _callback; this.timeoutCallback = _timeout; this.isLoading = true; // Make sure no other calls can be made until result is received // Make sure that _data is an array if (_data == undefined) { _data = new Array(); } this.method = _method; // Store method for later // Shift in password if there is one if (this.password != undefined) { _data.unshift(this.password); } // Call function this.service[_method].apply(null, _data); // set webservice timeout clearInterval(this.timeout); this.timeout = setInterval(this, 'onTimeout', 30000); }else{ // Place info in queue to be called when loading is complete this.callQueue.push({operation:_method, callback:_callback, data:_data, timeout:_timeout}); } } /** * Sends the information back to the callback function after data has been received * * @param _event The event object that's returned * @return Void */ private function onResult(_event:ResultEvent):Void { this.isLoading = false; this.retry = 0; // call callback this.callback.call(null, _event.result); // clear timeout clearInterval(this.timeout); this.dispatchEvent( { type:this.method } ); this.method = ''; // Go through queue if(this.callQueue.length > 0) { var obj:Object = this.callQueue.shift(); this.call(obj.operation, obj.callback, obj.data, obj.timeout); } } /** * If the service connection fails, go to next call in queue * * @param _event The event object that's returned * @return Void */ private function onFail(_event:FaultEvent) { trace('Gateway Connection Error: ' + _event.fault.faultstring); this.isLoading = false; this.retry = 0; delete this.callback; clearInterval(this.timeout); // Go through queue if(this.callQueue.length > 0) { var obj:Object = this.callQueue.shift(); this.call(obj.operation, obj.callback, obj.data, obj.timeout); } } /** * When the web service call times out, call the timeout callback function then proceed * through the queue * * @return Void */ private function onTimeout():Void { // clear interval clearInterval(this.timeout); this.isLoading = false; this.retry = 0; // call timeout callback this.timeoutCallback.call(); // Go through queue if(this.callQueue.length > 0) { var obj:Object = this.callQueue.shift(); this.call(obj.operation, obj.callback, obj.data, obj.timeout); } } }
Almost done. Now you just need to instanciate the class and call the method on your web service and run the app.
import AMFPHPConnection; var service:AMFConnection = new AMFPHPConnection('http://yousite.com/amfphp/gateway.php', 'mySite', '9sdEWHf2jdFJcd@' ); service.call( 'test' , function(result:Object){trace(result);}, ['Hello World!'], function(){trace('timed out.');} );
And that’s it. You should see ‘Hello World’ in your output window. You can send anything from PHP to Actionscript. If you send an array from PHP, the ‘result’ object is going to be an array. Simple as that.
Now, some of you might look through the AMFConnection class and think “Why do I need all of this?”. You probably don’t if you just need to do one call, but this class was built because I needed a wrapper class that would do everything I needed in a little class. It does method callbacks, a call queue and a timeout; it’s perfect for a UI where the user can click several buttons that all do something on the backend.
Copyright © Thinking in Code. All Rights Reserved. Powered by Wordpress
digging the snow dude. this is some clean programming.
it’s very different from the work i do in numerical modeling, but no less complex. if you get tired of being a flash guru, there’s always a need for finite element tools. boeing would pay you a mint.
got the link from the LICD forum.