BlogSalesforce

How to Define a RemoteObject in Actionscript

By April 10, 2009 September 10th, 2019 3 Comments

For the project I have been recently working on, I wanted to define a set of services in ActionScript that I could use to communicate via AMF to PHP. It turns out that this technique is not well documented around the web. Here’s how I did it.

Important: This example uses Flex 4. You will need to download and install the Flex 4 SDK before this example will work.

Create an AbstractRemoteOperation.as object:

AbstractRemoteOperation.as

package com.caspar.services
{

import flash.events.ErrorEvent;
import flash.events.Event;

import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
        //here is the key object - you need to import THIS exact remote object
import mx.rpc.remoting.mxml.RemoteObject;

    [Event(name="complete",type="flash.events.Event")]
    [Event(name="error",type="flash.events.ErrorEvent")]

    /**
     * Remote operation class used to call any remote object, depending
     * on the parameters supplied. Also will process the result using
     * the response handler for any supplied VO
     */
    public class AbstractRemoteOperation
    {

        /** The remote object performing the request on behalf of this operation. */
        public var ro:RemoteObject = null;

        /**result object - processes the php result and catches all errors**/
        [Bindable]
        public var responseHandler:AMFResponseHandler;

        /**
         * Constructor for the AbstractRemoteOperation.
         * This will never be called except as a super() method by a child object
         * */
        public function AbstractRemoteOperation(destination:String,source:String,endpoint:String, className:Class) : void
{
ro = new RemoteObject();

ro.destination = destination;
ro.source = source;
ro.endpoint = endpoint;
ro.showBusyCursor = false;

                responseHandler = new AMFResponseHandler();
responseHandler.setClassName(className);

}

        protected function handleFault(e:Event):void
        {
        removeEventListeners();
        responseHandler.error = "Internal Error";
        dispatchEvent(new ErrorEvent(ErrorEvent.ERROR));
        }

 /**
         * Check to see if we have a valid object and return it
         */
        protected function handleComplete(e:Event):void
        {
        removeEventListeners();
        responseHandler.handleComplete(e);
        if ( responseHandler.error != "" ){
        dispatchEvent(new ErrorEvent(ErrorEvent.ERROR));
        }
        else {
        dispatchEvent(new Event(Event.COMPLETE));
        }
        }

        protected function removeEventListeners () : void {

        }

    }
}

You’ll see a reference to an AMFResponseHandler object in the code above. This object takes the raw result object and parses it, ensuring that it has the correct object type (in this case a CustomerVO). It also handles either an array of these objects or a single instance of one. It always returns back an array of objects, even if it only has one member, which makes it easier for other parts of the system to use the data in a consistent manner.

AMFResponseHandler.as

package com.caspar.services
{
import flash.events.Event;
import flash.utils.getQualifiedClassName;

public class AMFResponseHandler
{
private var _className:String = "";
private var _error:String = "";
private var _data:Array = [];

public function AMFResponseHandler()
{
}

/**pass in the required class - we need a class name to verify that the class that
 * returned from the AMF call is of the right type eg, Calendar VO
 **/
public function setClassName ( referenceClass:Class ): void {
try {
_className = getQualifiedClassName ( referenceClass );
}
catch (e:Error) {
_className = "";
}
}

public function get error (  ): String {
return _error;
}
public function set error ( error:String ): void {
_error = error;
}

/** always returns an array,even if the result is a single string
 *  this is so we can ensure consistency of output and also so the
 *  result can be strongly typed
 **/
public function get data (  ): Array {
return _data;
}

/**pass in the complete event. This class will process it and output the
 * required array of VO classes or an error string
 **/
public function handleComplete ( e:Event ) : void  {

var eventClassName:String = "";

if ( _className == "" )
{
_error = "Internal Error: No classname set";
}
else
{
//we don't know if we are getting back an array of objects or just the object
if ( e.currentTarget.lastResult is Array ) {
processArray ( e.currentTarget.lastResult );
}else {
processObject ( e.currentTarget.lastResult );
}
}
}

/**pass in the complete event for a session Query. This class will process it and output the
 * required array of VO classes or an error string
 **/
public function handleSessionComplete ( e:Event ) : void  {
try
{
_data = [e.currentTarget.lastResult];
        }
        catch (e:Error) {
        _error = "Could not get a session string";
        }
}

private function processArray ( array:Array ) : void  {

try
{
if ( getQualifiedClassName ( array[0] ) == _className ){

var err:String = array[0].error;

        if ( err == "" || err == null || err == "0" || err == "0/0/0"){
        _data =  array ;
        }
        else {
        _error = err;
        }

    }else{
        _error = "No records match the request";
        }
        }
        catch (e:Error) {
        _error = "No records match the request";
        }
}

private function processObject ( obj:Object ) : void {

try
{
if ( getQualifiedClassName ( obj ) == _className ){

var err:String = obj.error;

        if ( err == "" || err == null || err == "0" || err == "0/0/0"){
        _data =  [obj] ;
        }
        else {
        _error = err;
        }

    }else{
        _error = "No records match the request";
        }
        }
        catch (e:Error) {
        _error = "No records match the request";
        }

}

}
}

AbstractRemoteOperation is useless unless you extend it to perform some action. In this example, we extend the class so that it calls “getCustomers” at the PHP end (I’ll cover setting up the PHP part of this equation later). It appears that it is not currently possible to dynamically define a service name at present – I’ve had to set up one of these objects for each service that I want to call.

GetCustomerOperation.as

package com.caspar.services
{

import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.mxml.Operation;

    /**
     * Class that that represents the GetCustomerOperation method
     */
    public class GetCustomerOperation extends AbstractRemoteOperation
    {
    /**
         * Use the remote object to call the php GetClientStaffOperation method
         * */
        public function GetCustomerOperation(destination:String,source:String,endpoint:String, className:Class) : void
{
super(destination,source,endpoint,className);

ro.operations = {?"getCustomers": new Operation (null,"getCustomers")};
ro.initialized(this, "getCustomers");

//use weak references so we don't need to remove the event listeners
ro.getCustomers.addEventListener(ResultEvent.RESULT,handleComplete, false , 0 , true);
                ro.getCustomers.addEventListener(FaultEvent.FAULT, handleFault, false , 0 , true);
}

        public function execute ( ): void {
        {
        ro.getCustomers.send(  );
        }
    }
}

Finally, in the controller code of your app, you instantiate this service object and call it, adding the appropriate event handlers. Controller Snippet:

     /**
      * get all customers
      */
     public function getCustomers( ) : void {
var o:GetCustomerOperation = new GetCustomerOperation("destination", "source", "http://myserver.mydomain/myAMFendpoint/index.php);
o.addEventListener(Event.COMPLETE, handleGetValueListsComplete);
        o.addEventListener(ErrorEvent.ERROR,handleGetValueListsError);
        o.execute();
     }

And there you have it – all the Flex code you need to call a remote zendamf PHP endpoint and handle the response.

Caspar Harmer

Caspar Harmer

Caspar is a New Zealander working for Soliant from far-off Wellington. He loves exploring new technologies and solving problems. Caspar also loves getting into the outdoors; he runs, mountain bikes and does a lot of orienteering when he can fit it in.

3 Comments

  • Avatar Geoff says:

    Hey, thanks for these examples. I was having a heck of a time getting remoting to work as pure as3. Most of the examples on the web are MXML, which was driving me nuts.

  • Avatar collin says:

    I’m getting syntaxt errors on

    ro.operations = {?”getCustomers”: new Operation (null,”getCustomers”)};

    is this some sort of ternary operation?

    and getting syntax error on

    var o:GetCustomerOperation = new GetCustomerOperation(“destination”, “source”, “http://myserver.mydomain/myAMFendpoint/index.php);

    Why aren’t you passing the className as the last paramter?

    Is is possible that you upload a sample flex project containing this? I’m trying to create unit tests for my remoting in actionscript and can’t find any examples that work out there.

    Thx,
    Collin

  • Avatar rah says:

    I must quote this post inside my blog site. It may possibly? So you et an account in Facebook?

Leave a Reply