Now that you have the project properly set up, you can create a small Flex application that talks with a PHP script using Zend AMF. Zend AMF enables Flex developers to make remote procedure calls from Flex to a PHP class; it is part of the Zend Framework, an open source project.
After downloading the Zend Framework
archive, extract the files. Next, you have to add the folder library to
your PHP include path. Open the php.ini file and add the path to the library folder to the include_path; on my machine this is looking like this:
include_path = "c:\htdocs\zend_framework\library"
Next you have to save the file and restart the web server. You can read more about installing Zend Framework here. With this, you've completed the "installation" of Zend Framework.
Zend AMF lets you to call methods on PHP classes from your Flex application, but the PHP classes must be inside the server web root.
As you write this PHP code, it would be nice to be able to use Zend Studio for this. The problem is that your project files are not inside of your server root folder (thus if you create the PHP class in the web server root folder, you will not see it in your Flex PHP project). Fortunately there is a simple solution. Eclipse lets you to link an external folder to any project you might have. Create a folder called zendamf_remote inside your web server root. Make sure that you are in the Flex perspective. Right-click on your project name and choose New > Other, select Folder in the wizard, and then click Next. When the new wizard starts, click Advanced and browse for the web server root folder and select the zendamf_remote folder (see Figure 10). Click Finish and you should now see a new folder named zendamf_remote inside your project.

Figure 9. Creating a linked resource
Now let's add the Zend Framework files to the project's PHP Include Path – by doing so you will be able to have access to the PHP code when using Zend AMF. Right click on the project name in the Project explorer, and choose Properties. In the opened window, select PHP Include Path and then choose the Libraries tab, and press the button Add External Folder… . Select the library folder from your Zend Framework library and then click OK (see Figure 10).

Figure 10. Adding the Zend Framework files to the PHP Include Path Libraries
Next, select the PHP perspective in Eclipse (see Figure 11), then right click on the zendamf_remote folder and select New > PHP Class.

Figure 11. Selecting the PHP perspective
When the New PHP Class wizard opens, just type in a file name (MyService.php) and a class name (MyService) and then click Finish (see Figure 12). Repeat this step to create another class called VOAuthor. Last, create inside the same zendamf_remote folder a PHP file called index.php.
First let's add a table with some data to your MySQL database server. You can use this code:
CREATE TABLE `authors_aut` (
`id_aut` int(11) NOT NULL auto_increment,
`fname_aut` varchar(255) NOT NULL,
`lname_aut` varchar(255) default NULL,
PRIMARY KEY (`id_aut`),
UNIQUE KEY `fname_aut` (`fname_aut`,`lname_aut`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
INSERT INTO `authors_aut` VALUES (1, 'Dantes', 'Alighierie');
INSERT INTO `authors_aut` VALUES (2, 'William', 'Shakespeare');
INSERT INTO `authors_aut` VALUES (3, 'Umberto', 'Eco');
INSERT INTO `authors_aut` VALUES (4, 'Niccolo', 'Machiavelli');
What I want to do is to create the PHP code to retrieve all the records from a table from a MySQL database, and the code for updateing one record from the same table. For this, I create the PHP class MyService wich is the class I will call from Flex. This class provides two methods: getData() and saveData(). Then I create the PHP class VOAuthor which acts as a data model for one row from my table. And finally I add the pluming code to index.php for starting the Zend AMF server and configure it to expose my MyService class. Now let's add code to all these files.

Figure 12. Creating a PHP class
The new files are created and opened for editing in Eclipse. Here is the code for MyService class (you need to update the connection information for your specific database setup; to do this, look for the four constants at the top of the class):
<?php
require_once('VOAuthor.php');
//conection info
define("DATABASE_SERVER", "localhost");
define("DATABASE_USERNAME", "mihai");
define("DATABASE_PASSWORD", "mihai");
define("DATABASE_NAME", "flex360");
class MyService {
/**
* Retrieve all the records from the table
* @return an array of VOAuthor
*/
public function getData() {
//connect to the database.
//we could have used an abstracting layer for connecting to the database.
//for the sake of simplicity, I choose not to.
$mysql = mysql_connect(DATABASE_SERVER, DATABASE_USERNAME, DATABASE_PASSWORD);
mysql_select_db(DATABASE_NAME);
//retrieve all rows
$query = "SELECT id_aut, fname_aut, lname_aut FROM authors_aut ORDER BY fname_aut";
$result = mysql_query($query);
$ret = array();
while ($row = mysql_fetch_object($result)) {
$tmp = new VOAuthor();
$tmp->id_aut = $row->id_aut;
$tmp->fname_aut = $row->fname_aut;
$tmp->lname_aut = $row->lname_aut;
$ret[] = $tmp;
}
mysql_free_result($result);
return $ret;
}
/**
* Update one item in the table
* @param VOAuthor to be updated
* @return NULL
*/
public function saveData($author) {
if ($author == NULL)
return NULL;
//connect to the database.
$mysql = mysql_connect(DATABASE_SERVER, DATABASE_USERNAME, DATABASE_PASSWORD);
mysql_select_db(DATABASE_NAME);
//save changes
$query = "UPDATE authors_aut SET fname_aut='".$author->fname_aut."', lname_aut='".$author->lname_aut."' WHERE id_aut=". $author->id_aut;
$result = mysql_query($query);
return NULL;
}
}
?>
Let's create the code for the Value Object, the data model. Select the file VOAuthor.php and paste this code:
<?php
class VOAuthor {
public $id_aut;
public $fname_aut;
public $lname_aut;
}
?>
As you can see, this class is very simple; it just provides the same members as the fields from the table. Finally let's create the code for index.php file. As I said before this is the plumbing code that expose the MyService class to Flex clients with the help of the Zend AMF. Paste the following code:
<?php
require_once('Zend/Amf/Server.php');
require_once('MyService.php');
$server = new Zend_Amf_Server();
//adding our class to Zend AMF Server
$server->setClass("MyService");
//Mapping the ActionScript VO to the PHP VO
//you don't have to add the package name
$server->setClassMap("VOAuthor", "VOAuthor");
echo($server -> handle());
?>
I use an instance of Zend AMF server to create a PHP end point that can be called from Flex. Then I register the MyService class to the server, thus I can call this class from Flex. And finally I map the ActionScript data model (VOAuthor) to PHP VOAuthor data model.
When you use remoting, you get for free the casting of the data to the right type. For example: MyService.getData() method returns an array of VOAuthor PHP objects. However, as you will see later, in Flex the result is an array of VOAuthor ActionScript objects.
Now that you have the PHP code in place, you are ready to create the Flex code that will call the PHP class. What I want to have is a Flex application that has a button to get the data from the server, uses a data grid to display the data, and you can use this data grid to edit any cell but ids. Whenever a cell is edited, the update is send automatically to server to be saved to the database as well.
First, be sure to select the Flex perspective from the top right icons of Eclipse.
The first thing you need to do is to create a configuration file that Flex can use in order to reach the PHP service. For that create the file services-config.xml in the root of the project, and open it. Copy this code inside of it:
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="zend">
<channels>
<channel ref="my-zend"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="my-zend" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://localhost/zendamf_remote/" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>
What it might be different for your configuration is the endpoint node (at the bottom of the file), your URL to the zendamf_remote folder might be different. Set the value accordingly to your setup.
Now you need to tell Flex Builder to use this file when compiling the project. So, right click on the project name in the Project Explorer and choose Properties. Select Flex Compiler and add to the Additional compiler arguments field this: -services "absolute_path_to_services_config.xml" (see Figure 13).

Figure 13. Adding services-config.xml file to the Flex compiler arguments
Then, open the flex_php.mxml file.
You will use a RemoteObject to communicate with the server, so add a mx:RemoteObject tag. You need to set the source attribute to MyService (this is the PHP class name) and the destination to zend – this is the destination created in services-config.xml file. Also give a name to this object by adding an id attribute and set it to myRemote, and set the attribute showBusyCursor to true (this will render the mouse icon to a watch whenever a call is made, until the response from the server is received). The code should look like this:
<mx:RemoteObject id="myRemote" destination="zend" source="MyService" showBusyCursor="true"> </mx:RemoteObject>
Now you need to declare the methods you want to call on the PHP class, and add the listners for fault and result. The code is:
<mx:RemoteObject id="myRemote" destination="zend" source="MyService" showBusyCursor="true" fault="faultListener(event)">
<mx:method name="getData" result="getDataListener(event)"/>
<mx:method name="saveData" result="saveDataListener(event)"/>
</mx:RemoteObject>
Next you need the UI for making the call to the server and display/edit the data. A button and a data grid will do. So, add this code above the remoteObject code:
<mx:VBox top="30" left="100">
<mx:Button label="Get data" click="{myRemote.getData()}" />
<mx:DataGrid id="myGrid" editable="true" itemEditEnd="save(event)"/>
</mx:VBox>
As you can see, the button calls the getData() method on the remoteObject. The data grid has an event listener registered for the itemEditEnd event.
The last step is to create the listeners we declared so far. For this, add a mx:Script tag to your MXML application and define four functions in it:
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import mx.events.DataGridEvent;
import org.corlan.VOAuthor;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.collections.ArrayCollection;
/**
* listener for the data grid's itemEditEnd event
*/
privatefunction save(event:DataGridEvent):void {
//we don't want to update the id of the item
if (event.dataField == "id_aut") {
event.preventDefault();
return;
}
//retrieve the new value from the item editor instance
var dataGrid:DataGrid = event.target as DataGrid;
var col:DataGridColumn = dataGrid.columns[event.columnIndex];
var newValue:String = dataGrid.itemEditorInstance[col.editorDataField];
//retrieve the data model that was edited
var author:VOAuthor = event.itemRenderer.data as VOAuthor;
// if the value wasn't change, exit
if (newValue == author[event.dataField])
return;
//update the model with the new values
author[event.dataField] = newValue;
//call the remote method passing the data we want to be saved
myRemote.saveData(author);
}
/**
* Result listener for get data operation
*/
privatefunction getDataListener(event:ResultEvent):void {
//set the result array as data provider for the data grid
myGrid.dataProvider = event.result as Array;
}
/**
* Result listener for save data operation
*/
privatefunction saveDataListener(event:ResultEvent):void {
Alert.show("The data was saved!");
}
/**
* Fault listener for RemoteObject
*/
privatefunction faultListener(event:FaultEvent):void {
Alert.show(event.fault.message, "Error");
}
]]>
</mx:Script>
Finally, you need to create the ActionScrit Value Object that will act as a data model for the data send from PHP. Right click on the src folder from Flex Navigator, and choose New > ActionScript class. Enter as package org.corlan, and as name VOAuthor and click OK. Now it is time to add the members and some meta-data:
package org.corlan {
[RemoteClass(alias="VOAuthor")]
[Bindable]
publicclass VOAuthor {
publicvar id_aut:int;
publicvar fname_aut:String;
publicvar lname_aut:String;
}
}
The RemoteClass meta-data is very important. This is telling to the ActionScript that the remote class (the one from PHP) that maps this it is called VOAuthor. If you forget this or you misconfigure, you will get generic objects in ActionScript instead of VOAuthor, and associative arrays instead of VOAuthor in PHP.
You are done. There shouldn't be any errors.
Now you are ready to test the code. Start the Flex application by clicking Run in the toolbar. When the application opens in your default browser, click on the Get data button. You should see the data grid populated with some data (see Figure 14).

Figure 14. Testing the application
To edit the items, just double clik on any name and change something. After finishing the editing, just clik somewhere else than the data grid (see Figure 15). The changes will be send to the server. If you don't believe me, just go to the database and see the records.

Figure 15. Editing some cell