RemoteObject using AMFPHP and Actionscript 3

6 09 2008

In my daytime job i am currently involved with a Flex3/BlazeDS project.The question arises to me quickly if it was possible to use Actionscript 3 RemoteObject classes with a PHP back end. A quick search with Google showed me some examples where Flex mxml in combination with amfphp 1.9 was used. This particular version of amfphp has support for AMF3 messaging protocol and therefore can be used natively with AS3 RemoteObject.

In my example i wanted to do something different by using AS3 RemoteObject classes and creating Channels at runtime, so no server-config.xml is needed during compile time.

For the coming example it is assumed that amfphp 1.9 is installed and running. for the backend service i use a slightly changed HelloWorld.php which can be found in the amfphp examples:

class HelloWorld {
/**
* Say hello!
*
* @param string $sMessage
* @return string
**/
public function say($sMessage) {
$date = getdate();
if (!$sMessage) {
throw new Exception("No message has been given",10001);
}
return 'You said: ' . $sMessage .' on '.$date[weekday];
}
}
?>

I introduced a PHP exception when no message parameter is given.
The next step involves the creation of the RemoteService super class. The constructor method is shown below (download PHPRemoting.zip for full example code).

public function RemoteService( serviceId:String
, serviceDestination:String
, amfChannelId:String
, amfChannelEndpoint:String
)
{
// Create a runtime Channelset for given Channel ID and Endpoinr URI
var amfChannel:AMFChannel = new AMFChannel(amfChannelId, amfChannelEndpoint);
amfChannelSet = new ChannelSet();
amfChannelSet.addChannel(amfChannel);
// Create the remoteObject instance
this.remoteObject = new RemoteObject(serviceId);
this.remoteObject.channelSet = amfChannelSet;
this.remoteObject.destination = serviceDestination;
this.remoteObject.addEventListener(FaultEvent.FAULT,onRemoteException);
}

All new service classes will extend this RemoteService super class and inherit all methods available.

No we are ready to create the service class for the HelloWorld example, this class will be named HelloWorldService and extends the RemoteService super class.

package remoting.services
{
import mx.controls.Alert;
import mx.rpc.events.ResultEvent;
import mx.core.Application;
import remoting.events.RemoteResultEvent;
/**
* Class that extends the RemoteService class, therefore it makes use of the default error handling for
* remote calls.
*/
public class HelloWorldService extends RemoteService {
// Static var with the PHP classname
private static var phpServiceClass:String = "HelloWorld";
//Constructor
public function HelloWorldService(amfChannelId:String, amfChannelEndpoint:String) {
super("helloworldService","amfphp", amfChannelId, amfChannelEndpoint);
}
//
public function say(msg:String):void {
remoteObject.source = phpServiceClass;
remoteObject.say.addEventListener(
ResultEvent.RESULT,handleRemoteMethod);
// call the PHP method
remoteObject.say(msg);
}
// Result handler
protected function handleRemoteMethod(event:ResultEvent):void {
var helloworld:String;
helloworld = event.result.toString();
Application.application.dispatchEvent(
new RemoteResultEvent(RemoteResultEvent.HELLO_WORLD, helloworld));
}
}
}

There is only a resulthandler implemented for the remoteobject call, because the fault handler is already implemented within the RemoteService super class. Important thing is the static var phpServiceClass which contains the name of the PHP class which will be binded to the remoteObject.

Now the plumbing is ready (download PHPRemoting.zip for full example code) it is time to create the Flex application file. This example application has a TextInput box for the message and a Button to call the remote method.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
creationComplete="init();">
<mx:Script>
<![CDATA[
import remoting.events.RemoteExceptionEvent;
import remoting.events.RemoteResultEvent;
import remoting.services.HelloWorldService;
import mx.controls.Alert;
//
private var amfChannelId:String = "my-amfphp";
private var amfGateway:String = "http://localhost/amfphp/gateway.php";
private var service:HelloWorldService;
// Initialization
private function init():void {
this.addEventListener(RemoteExceptionEvent.REMOTE_EXCEPTION, handleRemoteExceptionEvent);
this.addEventListener(RemoteResultEvent.HELLO_WORLD, handleRemoteResultEvent);
// Create a new service instance
service = new HelloWorldService( amfChannelId, amfGateway );
}
// Button action handler
private function clickHandler():void {
service.say(msg.text);
}
// Result handlers
private function handleRemoteResultEvent(event:RemoteResultEvent):void {
Alert.show(event.message);
}
private function handleRemoteExceptionEvent(event:RemoteExceptionEvent):void {
Alert.show(event.message);
}
]]>
</mx:Script>
<mx:TextInput id="msg"/>
<mx:Button label="say something" click="clickHandler();"/>
</mx:Application>

When no text is provided the PHP class will throw an exception which is shown in the Alert box. Just try it out.


Actions

Information

16 responses

9 10 2008
Kurt

Excellent example and very much appreciated.

3 01 2009
bob

he6L0u hi nice site thx http://peace.com

14 03 2009
Greg

I think that this is a well explained and useful post. I have dl’ed your code and hope to have some time to try it in the near future. Thank you for your time and effort.

24 03 2009
dl

a more easier example would be more helpfull.
For example, how would this component be looks like in as3 ? and how you call it.
Cheers dl

4 04 2009
polyGeek

Thanks for this. I’ve been using the class in Flex Builder which is very easy to use but has obvious limitations. You’re approach with the RemoteService class is much better.

I’ve made some video tutorials on my site at http://polygeek.com/amfphp-video-tutorials for people getting started with . I’d like to make some more video tutorials and encourage people to use this approach. Would you mind if I used your code – or a slight variation of it? Of course credit will be given where it is due.

4 04 2009
Gerton

@polyGeek
No problem. You can use the code wherever you want it.

1 06 2009
shibby

Hi, thanks for this great tutorial.

Using this sample as a base I made my own stuff, but it didn’t work out.
What I was trying to do was to retrieve some data from a MySQL database, put it in an ArrayCollection class to use it has the dataProvider for a DataGrid. The php DAO and VO objects are well done since I tested them with amfphp’s browser, but I can’t get my data to appear on the DataGrid.

I guess I messed something up in RemoteResultEvent… because in the example it was made to get a string or and I want an arraycollection

1 06 2009
shibby

Now I figured out how it works but I get

unknown runtime problem occurred during a remote call : faultCode:Client.Error.MessageSend faultString:’Send failed’ faultDetail:’Channel.Security.Error error Error #2048:

that error and I don’t know why, because the endpoint is given

2 06 2009
Gerton

Hi Shibby,

A quick search on Google revealed that you are facing a “sandbox” security issue. Are you running the swf from the same domain as your gateway url?

6 06 2009
shibby

Hi, thanks for answering…

It was my fault, I hadn’t given the amf endpoint properly so this error was inevitable. Now I fixed it up.

Now another question. What if I want to dispatch an event for a component inside the main Application. I have to do it like

Application.application.component.subcomponent.dispatchEvent(…)

or is there any other way to reference that subcomponent without having to write all the tree…

I’ve tried Application.application.getChildByName(“childname”) but seems like this won’t work when I want to reference the “subcomponent”

Any ideas or guides to recommend?

Thanks a lot.

3 09 2009
visualdialects

This all looks very interesting and am hoping it could be really useful on future projects. Thanks for sharing.

15 01 2010
Wilson

THANK YOU THANK YOU THANK YOU GERTON!!

19 01 2011
Maskime

Have to say :

You did some great piece of work here , everything is simple and well explained.

Thanks a lot.

19 01 2011
Maskime

Next step would be to externalize the endpoint parameter, this way you wouldn’t be bound to build an application for each server you want to deploy on.

6 08 2011
Eric

Please can you show how this would have to be modified to work with ZendAMF? Thanks

8 08 2011
Gerton

Hi,

Read my post “Fileupload using Zend AMF, RemoteObject and Flash 10”.

It is using the same RemoteService AS-class as used here.
The gateway is calling an amfAction method within the messagebroker controller.

Hope this would point you in the right direction

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: