There are a variety of methods we can use to communicate between flash and our server side web applications, including XML and HTTP POST/GET. However a much more robust methods exists–Action Message Format (AMF). AMF uses binary encoded messages. Because of this the messages are compressed which makes AMF the fastest way to transfer data. Another advantage to using AMF is that we can share objects and methods between Flash and our server technology. This post shows how we can communicate between Flex builder 3 and PHP using AMF. We will be using the Zend framework to accomplish this.

Firstly we need to download the PHP zend framework. Once it has finished downloading unzip the package and copy the directory "library > Zend" to a directory on a PHP enabled server. For this example we have a folder called amf on a development server where we are storing all of the files.

Continuing on with the example we will create three PHP files and save them to our ‘amf’ directory. The first file is called ‘DataModel.php’ and contains the following code:

<?php
 
class DataModel
{
	public $id;
	public $firstName;
	public $lastName;
}
 
?>

This is a simple class file used to store a persons name. This class might relate to a row of data in a database. Later on we will create the same class in Flex Builder and establish a link between the two so that we can share instances of this object between Flex and PHP.

Our second file is called ‘Services.php’:

<?php
 
 
class Services
{
	public function retrieveData()
	{
		$data = array();
 
		$model1 = new DataModel();
		$model1->id = 1;
		$model1->firstName = "Fred";
		$model1->lastName = "Smith";
		$data[] = $model1;
 
		$model2 = new DataModel();
		$model2->id = 2;
		$model2->firstName = "Jill";
		$model2->lastName = "Smith";
		$data[] = $model2;
 
		return $data;
	}
}
 
?>

The Services class contains only one function, which creates two instances of the DataModel class. For a production project we might use this class to connect to a database and parse rows of data into DataModel objects. This class will also be available to us in Flex, however we will use only one instance and assign it to an MXML Remote Object.

Our last php file will be called ‘index.php’ and contains the following code:

<?php
 
set_include_path("");
require_once "Zend/Loader.php";
Zend_Loader::registerAutoload();
 
// ---- 
// ---- Zend AMF Server ---- /
// ----
 
$server = new Zend_Amf_Server();
//Allows our Flex/Flash project to use the AMFServiceController class
$server->setClass('Services');
// Map the ActionScript class 'DataModel' to the PHP class 'DataModel':
$server->setClassMap('DataModel', 'DataModel');
$response = $server->handle();
echo $response;
 
?>

This is the root file that will be called by Flex and sets up our classes for use with AMF. Most of the real work here is abstracted by the Zend Framework. We simply need to create an instance of Zend_Amf_Server and add our classes. The line:

$server->setClass('Services');

will create an instance of the Services class and allow us to call it’s methods from Flex whereas the line:

$server->setClassMap('DataModel', 'DataModel');

Tells the AMF service to create a link between our PHP DataModel class and our Flex DataModel class (we will create this later), so that we can share instances of the class betwwen the two technologies.

In order to test our implementation so far we can navigate to this endpoint file. In this example the files are located in a directory called amf running on a development server. The url is: http://localhost/amf/. After navigating to the url a short message appears that says ‘Zend Amf Endpoint’. This means everything is working properly.

Next we need to create a Flex Builder project and communicate with our Zed AMF server. Firstly when we create our project we need to ensure that we choose PHP as our Server technology. We can create an AIR or Web based application. This example uses a web application and is called simply Amf.

Next we need to specify the location of our php files locally and remotely.

With our Flex project created the next step is to create an XML file which will be used to configure our Zend AMF server. In this example the file is called ’services-config.xml’ and located in the projects ’src’ folder.

The file contains the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service id="zend-service"
            class="flex.messaging.services.RemotingService"
            messageTypes="flex.messaging.messages.RemotingMessage">
            <destination id="zend">
                <channels>
                    <channel ref="zend-endpoint"/>
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    <channels>
        <channel-definition id="zend-endpoint"
            class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://localhost/amf/"
                class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
    </channels>
</services-config>

The only node that should ever be changed is:

<endpoint uri="http://localhost/amf/"
                class="flex.messaging.endpoints.AMFEndpoint"/>

The ‘endpoint’ attribute needs to be changed to the url of the Zend AMF server. Before we can move on to setting up our MXML file we need to add a setting to our compiler which will tell the project to use our ’services-config.xml’ file. Add -services "services-config.xml" as an additional argument.

Our root MXML file ‘Amf.mxml’ contains the following code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
				layout="absolute"
				creationComplete="init();">

	<mx:RemoteObject id="zendAmfServices"
	    fault="faultHandler(event)"
	    showBusyCursor="true"
	    source="RoundTrip"
	    destination="zend">

		<mx:method name="retrieveData" result="resultHandler(event)"/>

  	 </mx:RemoteObject>

  	 <mx:Script>

  	 		import mx.utils.ObjectUtil;

  	 		import mx.rpc.events.ResultEvent;
  	 		import mx.rpc.events.FaultEvent;

  	 		private function init():void
			{
				zendAmfServices.retrieveData();
			}

	  	 	private function faultHandler(event:FaultEvent):void
			{
				trace(event.message);
			}

			private function resultHandler(event:ResultEvent):void
			{
				var data:Array = event.result as Array;

				for each(var item:DataModel in data)
				{
					trace( ObjectUtil.toString(item) );
				}
			}

  	 </mx:Script>

</mx:Application>

Here we create a remote object and create a link to our ‘retrieveData()’ PHP method. The object will call an ActionScript function ‘faultHandler()’ if something goes wrong or ‘resultHandler()’ if the communication is successfull. In order to call our php method we can use the following line of code:

zendAmfServices.retrieveData();

where zendAmfServices is the id of our MXMLRemoteObject and
retrieveData() is our php method. Before we can run this project we need to create an ActionScript version of our
DataModel class and link it to our PHP version. The code for the class contains:

package
{
	[RemoteClass(alias="DataModel")]
	[Bindable]
	public class DataModel
	{
		public var id:int;
		public var firstName:String;
		public var lastName:String;
	}
}

The line:

[RemoteClass(alias="DataModel")]

 Maps this class to the PHP version. FInally we are ready to run the project! The results can be seen below:

Here we can see that the properties of our two DataModel objects have been output to the console in Flex. This means that we have successfully communicated with our PHP classes and transfered two PHP Objects from our server to our client side Flex application, preserving both the Class structure and instnace variable data.