Home  >  

AMF3 PHP Server Objects to Flex Client Object Relational Mapping

Author photo
AddThis Social Bookmark Button
RIAs Are Hot, Even More So With Adobe’s AMF

But what should I deploy? Where do I start as a developer? Your help is here!

Rich Internet Applications (RIAs) are web applications, which provide the features and functionality of traditional desktop applications. RIAs by definition are client/server based. Your client is written using Flex Builder, which compiles to Flash. You have numerous server platform choices, each with respective benefits and tradeoffs. Many times your server platform is pre-established, often dictated by the enterprise where you are deploying RIA solutions. Other times the server choice is not defined. The choice is up to you, the developer. Flex remoting (client/server messaging) provides several network protocol alternatives with varying messaging format.

For any Flex-based RIA solution deployment, your client platform is defined. Preliminarily, during the RIA design phase, you must also identify and select your server platform and Flex remoting protocol for client/server messaging.

Do you need to know where to start will all of the above platform, networking, and messaging issues? If yes, then read on.

Overview

This article first provides summaries of the Flex networking protocols, the server platform alternatives, and Adobe’s AMF 3 (Action Message Format) remote messaging protocol. We then use an example set of client and server code to demonstrate the key concepts necessary to deploy a Flex-based RIA client/server solution. We explain how and why client and server objects—though remote from each other—are unified to the same object structure and content by the use of what is called object relational mapping.

This article also assists with your server platform and remoting protocol selection. We are not discussing all server platform and remoting protocol alternatives. Instead, our approach is to demonstrate a basic and simple solution that will provide the knowledge for you to deploy on many server choices. Requirements

In order to make the most of this article, you need the following software and files:

Adobe Flex Builder 3 (includes the Flex 3 SDK)
• Try - 60 days (http://www.adobe.com/cfusion/tdrc/index.cfm?product=flex)
• Buy ( http://www.adobe.com/go/buyflexbuilder_std )

PHP (Workstation, not server, deployment preferred)
• PHP 5.x Scripting Language ( http://www.php.net )

Web Server (Workstation, not server, deployment preferred)
• Apache HTTP Server ( http://httpd.apache.org )
• Alternately Microsoft IIS (Preinstalled with Windows XP Professional)

Web Application Server (Workstation, not server, deployment preferred)
• WebORB for PHP from Midnight Coders (http://www.themidnightcoders.com/weborb/php)

Example files
MyFamilySource.zip (ZIP, 945K)

Note: For Windows development, you can install the WampServer (Apache, PHP, MySQL on Windows) as an all-in-one development server package. ( http://www.wampserver.com/en )

Note: Apple’s OS X operating system provides the Apache Web server and PHP. You still need to install the WebORB for PHP application server into the Apache Web server root folder. Installation details follow later in this article.

Remoting Protocol Summary

Flex-based client/server remoting can communicate over a number of network protocols including HTTP/HTTPS, RTMP sockets, and binary sockets. Over these network protocols are the respective messaging formats such as REST (XML), SOAP, and AMF. We will not talk about these networking protocols or the REST and SOAP formats here as each protocol’s basic details are covered in Adobe’s LiveDocs Adobe Flex 3 Help online documentation ( http://livedocs.adobe.com/flex/3/html/help.html ). Navigate to Data Access and Interconnectivity / Accessing Server-Side Data with Flex.

For our upcoming object relational client/server example, we’ll use Adobe’s AMF 3 (Action Message Format) remoting protocol over HTTP/S. A brief overview of using the AMF 3 messaging protocol is covered in the above-mentioned Adobe Flex 3 Help in the content path: Flex 3 Developer's Guide / Data Access and Interconnectivity/ Accessing Server-Side Data with Flex / Using RemoteObject components.

Server Platform Summary

Following is a partial list summary of available Application Servers (a.k.a., remoting and web messaging server) supporting AMF 3 RemoteObject client/server messaging.

Java Application Servers
• Adobe LiveCycle® Data Services, Enterprise Suite http://www.adobe.com
• Adobe Open Source BlazeDS
http://opensource.adobe.com/wiki/display/blazeds/BlazeDS
• WebORB for Java www.themidnightcoders.com

Adobe ColdFusion Application Server http://www.adobe.com

PHP Application Servers
• WebORB for PHP http://www.themidnightcoders.com
• AMFPHP http://amfphp.sourceforge.net
• SabreAMF http://www.osflash.org/sabreamf

Microsoft .NET Application Server
• WebORB for .NET http://www.themidnightcoders.com

Ruby on Rails Application Server
• WebORB for Ruby on Rails http://www.themidnightcoders.com

For our object relational client/server example, we’ll use Midnight Coders WebORB for PHP with our server-side objects written in PHP code. Our Flex client-side objects will be written as ActionScript 3 objects. You’ll learn a client/server technique called object relational mapping where you define object relations written in two disparate programming languages that are explicitly mapped to each other in form and content. This object mapping provides data type transfer independent of the client and server and each side’s native programming language.

An excellent and more detailed discussion of the object mapping topic is found in Adobe’s LiveDocs BlazeDS Developer Guide - Beta 1 online documentation ( http://livedocs.adobe.com/blazeds/1/blazeds_devguide/ ). Navigate to the page BlazeDS Developer Guide - Beta 1 / Messaging / Serializing Data / Serializing between ActionScript and Java / Explicitly mapping ActionScript and Java objects. The discussion is related to Java objects on the server side. You will soon learn that whether our remoting is Java or PHP objects the messaging works exactly the same. Read the LiveDocs page on how its done with Java and you will later see how it’s done in this article with PHP. Note that remote object relation-mapping techniques are exactly the same regardless of the server’s native development code.

I should point out that the Java-based LiveDocs referenced above mentions the use of object introspection and reflection to gather public fields on the messaging class. The exact same technique is used internally within our WebORB for PHP application server example. Because PHP an interpreted language, the WebORB PHP source code is available for evaluation if you are so inclined to review how the object reflection occurs. By far, you don't need to know what is going on at this level to use WebORB’s object relational mapping. I only point this information out for the technically curious.

About AMF 3

We have identified that AMF 3 will be our RemoteObject (Flex programming term) messaging protocol. Before jumping into our example code, you should understand what the AMF 3 protocol is and how it works.

AMF 3 is an Adobe proprietary protocol that serializes data, nominally objects, for transfer and then conveniently deserializes the data on the respective server or client receiver. There is a much more detailed discussion of data serialization in Adobe’s LiveDocs BlazeDS Developer Guide - Beta 1 online documentation ( http://livedocs.adobe.com/labs/blazeds/html/help.html ). Navigate to the page BlazeDS Developer Guide - Beta 1 / Messaging / Serializing Data / Serializing between ActionScript and Java. Once again the discussion is Java-centric. When we get to our example PHP code we will observe that PHP objects will be AMF 3 serialized in a similar manner.

While I mention that AMF 3 is an Adobe proprietary protocol, Adobe recently open-sourced the AMF 3 protocol details. For those wanting more details related to the AMF 3 serialization structure, you can find the AMF 3 protocol specification on the Adobe Open Source BlazeDS Web site (http://opensource.adobe.com/wiki/display/blazeds/BlazeDS ). Select the Documentation menu item and then on that page click on the BlazeDS Developer Documentation link ( http://opensource.adobe.com/wiki/display/blazeds/Developer+Documentation ). And finally, from this page, click on the link to the AMF 3 specification under the Specifications heading.

Advantages of AMF 3
• AMF 3 RemoteObject transfers are fast and efficient. AMF 3 objects are compressed using zlib.
• Data streaming via single data requests
• Object-oriented serialization and data transfer. Native data types and custom classes are supported. You can serialize any object with the only exception being ActionScript displayObjects. You can easily map serialized objects back to custom class instances. The example code included with this article demonstrates how this is done.
• Data independence: you can easily map data types between the client and server
• AMF 3 protocol is now in the public domain— The AMF 3 messaging end points will be able to optionally extended by the Flex developer community. The public community cannot extend the AMF3 protocol
• AMF 3 reads and writes are supported by all the RemoteObject application servers identified above in the Server Platform Summary section.

Disadvantages of AMF 3 • Choosing the appropriate application server platform may require selection research and evaluation. Each server platform provides many benefits and tradeoffs both technically and economically.
• It’s a little more difficult to kick-start AMF 3 RPC client/server development and establish remote debugging techniques. The development task becomes much easier after a couple of RPC application deployments.

Object Relational Mapping of ActionScript and PHP Classes

Figure 1 shows the ActionScript and PHP classes that respectively reside on the Flex client and WebORB PHP server. Each class is written in the native development language, ActionScript for the client and PHP for the server.

On both sides of our example solution, our “MyFamily” class consists of an object data structure containing a father, mother, and array of children. These three properties’ data types are of Person type consisting of firstName and lastName properties of type string, where the children property is an array of type string. Note that the PHP class does not define the data types because PHP is a type-less language that propagates the data to the appropriate type internally.

The type-less nature of the PHP class makes class inspection less obvious that the firstName and lastName Person class properties are of type string and that father, mother and the children array are of type Person. We’ll see how this looks in the next section as we review the code.

Our code example Flex client will request the MyFamily object’s data from the WebORB for PHP application server. The WebORB application server will serialize the MyFamily PHP object into AMF 3 and transfer the serial stream to the remote Flex client as an ActionScript RemoteObject. The Flex client detects the AMF 3 receipt through ActionScript event processing. The Flex client receives the data, and de-serializes and maps the data to the MyFamily.as ActionScript object structure shown in the left-hand column of Figure 1.

Before jumping into reviewing the code’s operation we need to discuss one important design and development practice. The client and server MyFamily classes are disparate from each other. That is, each side is incapable of detecting the other side’s differences in data structure or data types. If the data structure and data type do not 100% match, then you receive a RemoteObject runtime error on the AMF3 receiver during the AMF 3 receive event processing.

fig1.png
Figure 1. MyFamily Classes

When performing code refactoring, which affects the respective client or server class data structure or data type, be sure to also immediately make the change in the opposite side’s class. Failure to keep these classes in sync creates unnecessary runtime errors creating a distracting debug cycle where the actual task at hand is getting real development work done.

MyFamily Example Code Review Summary

If you prefer, you can first install both the example Flex client and PHP server example code. The installation details follow in the Deploying the Example section.

We have two sets of example code to review. One set for the Flex client, with the second set residing on the WebORB for PHP application server. The code sets work in unison. We’ll cover them separately and link their operations together.

First lets start by saying this is purposely a very simple application built specifically to demonstrate Flex client/server object-relational mapping. Figure 2 shows the result of running the MyFamily application. On the left is the application’s starting display. When the getFamily button is clicked the MyFamily Flex client requests the family information from the WebORB for PHP server. The server serializes the family information in AMF 3 and returns the serial stream to the MyFamily Flex client. Upon AMF 3 receipt an ActionScript 3 event is created, which deserializes the AMF 3 stream and displays the family data as shown in the right side of Figure 2.

That’s really about all that happens with the MyFamily example application. There are lots more issues to discuss on how the MyFamily Flex client and application server code works. Next, lets dig into the code’s operation.

fig2.png
Figure 2. MyFamily Application Result

MyFamily Flex Client Example Code Review

We’ll start by reviewing the Flex client code in the “main.mxml” module. The mxml code is for the MyFamily application’s display is between lines 51 and 71. We won’t be discussing this code except to say that line 52 contains a button that, when clicked, requests family data from the WebORP application server.

The “main.mxml” code lines 41 to 49 providing the RemoteObject ( http://livedocs.adobe.com/labs/flex3/langref/index.html ) connection request for family data residing on the application server is shown in Listing 1.

<!-- Remote Object -->    
<mx:RemoteObject
	id="remoteTestMapping"
	destination="MyFamily"
	showBusyCursor="true"
	fault="faultHandler(event)">  
	<mx:method name="getMyFamily" result="handlerGetMyFamily(event)"/>
</mx:RemoteObject>
<!-- End Remote Object -->

There are two significant attributes in the mx:RemoteObject element. First, the id=“remoteTestMapping” attribute provides a calling point of reference to access the connection. You’ll soon see next how this id attribute is used. The second attribute of interest is the destination=“MyFamily” value. The destination value is the name of the PHP object we wish to access on the WebORB for PHP application server. Essentially this is our information repository address on the application server.

The mx:method element’s two attributes within the mx:RemoteObject element (in Listing 1) provide the two final parameters for the access to and reply form the WebORB for PHP application server. The first attribute, name, is the name of the “MyFamily” PHP object’s method to access for the required family information. We are going to call the getMyFamily method of the PHP “MyFamily” object residing in the remote application server.

The fault attribute identifies the ActionScript method to call when the RemoteObject request fails. In our example this method is named faultHandler. Its task is to display an error dialog containing the communication error message.

The mx:method MXML element, a child of the mx:RemoteObject element, is where the RemoteObject call to the WebORB PHP sever is defined. The attribute “name=getMyFamily” is the method to call within the PHP object “MyFamily” defined previously by the destination="MyFamily" attribute of the mx:RemoteObject element. The second mx:method MXML element attribute result="handlerGetMyFamily(event) is the name of the ActionScript method defined to receive the AMF 3 serialized data response from the application server after the getMyFamlyPHP method returns the AMF 3 serial data stream to the MyFamily Flex client.

In summary the mx:RemoteObject element defines our connection to the application server, where to obtain the desired information on the server, and what should process the AMF 3 receive data event.

Listing 2 is lines 23 to 25 from the “main.mxml” code module.
private function handlerClickGetFamily():void {    
 	remoteTestMapping.getMyFamily();
}

When the getFamily button—line 52 in the “<!-- Display -->” section of the “main.mxml” module—is clicked the handlerClickGetFamily ActionScript method is called. This method then calls the mx:RemoteObject (Listing 1)—using the id=“remoteTestMapping” as a calling reference—with a request to access the getMyFamily PHP method in the “MyFamily” object.

In the mx:RemoteObject element in Listing 1 we observed that the handlerGetMyFamily ActionScript method was configured as the event processor to handle receipt of AMF 3 serial stream of family data from the application server.

private function handlerGetMyFamily(event:ResultEvent):void {
 	// Note: two ways of casting the event to a MyFamily object            
 	//       myFamilyObject = MyFamily(event.result);
 	myFamilyObject = event.result as MyFamily;
 	trace("Break!");
}    
The handlerGetMyFamily method receives the AMF 3 serial stream of family data as an event of type ResultEvent ( http://livedocs.adobe.com/labs/flex3/langref/index.html ). The “event.result” value is assigned to the global ActionScript property “myFamilyObject”, which is of type “MyFamily” object. Now here is where all the AMF 3 data deserialization and storage assignment takes place. A lot is going on here, and by looking at the assignment of the “event.result” to “myFamilyObject” it’s not really obvious what’s happening. Let’s delve into this notion a little further to master what’s going on.

We’ve cast the “event.result” assignment to “myFamilyObject” to be of data type “MyFamily” using the ActionScript syntax of “event.result as MyFamily” (Listing 3).

Note: There are two ActionScript syntactical ways to cast the “event.result” assignment to the “myFamilyResult” property. We’ve shown both ways with the first alternative syntax commented out, but noted for your reference.

Well, all of this looks fine. But how does the event assignment know the structure of the “event.result” so that it can be deserialized and parsed into our “MyFamily” object? The event casting provides the object structure information in Listing 4.

ActionScript Module: MyFamily.as
package {
 	import Person;
     
 	[Bindable]
 	[RemoteClass(alias="MFamily.MyFamily")]
 	public class MyFamily {
  		public var father:Person;
  		public var mother:Person;
  		public var children:Array;
  	 }
}
ActionScript Module: Person.as
package {
 	
 	[Bindable]
 	[RemoteClass(alias="MFamily.Person")]
 	public class Person {
  		public var firstName:String;
  		public var lastName:String;
  	}
}
In our two ActionScript classes, we use the [RemoteClass(alias=" ")] metadata tag to create an ActionScript object that maps directly to our server’s PHP object—or any other type of application server object for that matter. All of the application servers listed in the Server Platform Summary section perform AMF 3 object serialization the same way results-wise. The ActionScript class to which data is converted must be defined within the Flex client file for it to be used dynamically at run time. The way this is performed is by casting the result object, as the following example shows: var result:MyClass = MyClass(event.result) or var result:MyClass = (event.result) as MyClass.

You’ll note in Listing 4, that the “MyFamily” class is bound to the object alias of “MFamily.MyFamily” object and the Person data types defined in the Person class are bound to the “MFamily.Person” object that were originally serialized by the WebORB for PHP application server and transferred to the MyFamily Flex client.

The received AMF 3 data stream event is being deserialized into the “myFamilyObject”; the structure of the received data is being guided by the two class definitions shown in Listing 4. The AMF 3 data stream structure is fully tagged as to the object method (getMyFamily) and fully parameterized per the complex object structure being deserialized by the MyFamily Flex client. The actual AMF 3 data structure is displayed in Figure 3. Serialized AMF 3 Structure of the MyFamily Data.

fig3.png
Figure 3. Serialized AMF 3 Structure of the MyFamily Data

All that is left to answer is how does the “myFamilyObject” data property become displayed within the application? Notice in Listing 5 that the “myFamilyObject” data property in the “main.mxml” module is “Bindable”.

// A global variable (MyFamily object)
[Bindable]
private var myFamilyObject:MyFamily;   
Observe that all of the “mx:TextInput” elements in the section of the MyFamily Flex client in the “main.mxml” module are respectively bound to the “myFamilyObject” data property. When “myFamilyObject” changes values, so does the display.

MyFamily WebORB Server Example Code Review

We’ve seen how the MyFamily Flex client requests, receives (via an ActionScript event), deserializes, and displays the MyFamily family’s data.

Discussion of the internal operation of WebORB for PHP is beyond the scope of this article. Details about the WebORB for PHP setup and operation can be found at the Midnight Coders web site ( http://www.themidnightcoders.com ). We will discuss how and where the “MyFamily” PHP is deployed and configured. You may want to reference Figure 6 below, WebORB for PHP site layout, during this discussion.

Flex client-accessible PHP classes are placed in the WebORB application “Services” folder per: Web Server Root Folder/WEBORB/Services folder. You can optionally place your PHP classes within a folder hierarchy within the “Services” folder. For our “MyFamily” example we elected to place the MyFamily PHP class within the “MFamily” parent folder. We nominally set up this way to reduce clutter within the “Services” folder for server maintenance purposes and for deploying from development servers to production servers.

Listing 6 shows the “MyFamily” PHP class. The class gets instantiated by the WebORB for PHP application server when the “MyFamily” Flex client makes an information request for family data. The class instantiation to an object calls the PHP class “__construct” method and assigns the family data to the object’s family properties.

In our “MyFamily” example, the family data is hard-coded into the class instantiation for example demonstration purposes. In a typical application this data would come from a dynamic information repository such as a relational database.
<?php
require_once("Person.php");

class MyFamily {
 	var $father;
 	var $mother;
 	var $children = array();
 	
 	function __construct() {
  		$father = array('firstName'=>'Robert', 'lastName'=>'Jones');
  		$mother = array('firstName'=>'Betty', 'lastName'=>'Jones');
  		$children = array(
  			array('firstName'=>'Jim', 'lastName'=>'Jones'), 
  			array('firstName'=>'Shirley', 'lastName'=>'Smith'), 
  			array('firstName'=>'Sally', 'lastName'=>'Jones')
  			);
  		$this->father = new Person($father);
  		$this->mother =  new Person($mother);
  		foreach ($children as $child) 
  			$this->children[] = new Person($child);
  	}
 	
 	public function getMyFamily() {
  			return($this);
  	}
}
?>
When the “MyFamily” Flex client makes a call to the WebORB application server it calls the “getMyFamiy” method of the MyFamily PHP object. This “getMyFamiy” method returns an object pointer to the class to the WebORB application.

PHP provides an object reflection API that provides the ability to interrogate an existing class or object to identify their structure and contents. Through object reflection, via the object pointer passed to it, WebORB for PHP acquires the MyFamily object’s properties, serializes the data into an AMF 3 stream, and returns the serial stream back to the MyFamily Flex client where the event processing, discussed earlier, goes to work.

Listing 7 shows the person class, used to instantiate the respective father, mother, and children array object properties in the MyFamily PHP class.
<?php
class Person {
 	var $firstName;
 	var $lastName;
 
 	function __construct($person) {
  		$this->firstName = $person['firstName'];
  		$this->lastName = $person['lastName'];
  	}
}
?>
Recall that the Flex client’s mx:RemoteObject element in the “main.mxml” module established the application server’s object access with the object via the attribute of destination=“MyFamily” and its method call by the MXML element mx:method name="getMyFamily". We need a way to map this Flex client call to locate and instantiate the “MyFamily” PHP object to subsequently call the “getMyFamily” method to return the AMF 3 data stream to the client.

We set up the Flex client’s RemoteObject request to the PHP “MyFamily” object call mapping in the WebORB’s “remoting-config.xml” configuration file. See step 4 in the following Deploying the Example section for details on where “remoting-config.xml” is located in the WebORB for PHP server environment. Note in step 4 we added the following lines into the XML configuration file:
	<destination id="MyFamily">
		<properties>
        			<source>MFamily.MyFamily</source>
   		</properties>
   	  </destination>
The above XML mapping configuration identifies for the WebORB server that when a RemoteObject remoting request is received from the “MyFamily” Flex client, for the MyFamily destination, that this PHP class can be found in the Services folder (default). In the Services folder is a folder named “MFamily” containing the “MyFamily” PHP object we want to instantiate. In summary the path is: Your Web Server Root/WEBORB/Services/MFamily/MyFamily.php

RIA Debugging Tips

This debugging discussion assumes you are familiar with using the Flex Builder debugger. If you have not yet mastered using the Flex Builder debugger, then you should visit Adobe’s LiveDocs Adobe Flex 3 Help ( http://livedocs.adobe.com/flex/3/html/help.html ) and navigate to the page Using Flex Builder 3 / Programming Flex Applications / Running and Debugging Applications. There are four topics here:

• About running and debugging applications
• Running your applications
• Managing launch configurations
• Debugging your applications

The Flex Builder debugger soon becomes your friend the first time you launch a client/server-based RIA application.

Sometimes in Flex support forums I see messages something like, “I developed and configured my RIA client and server solution. It doesn’t work. Nothing happens, what should I do?” The support forum help request also typically carries a tone of desperation, “oh what to do, where do I turn?” This dilemma is created by not having a client/server debugging plan in place. “Hey the person who wrote the RIA example code I used did not tell me that I would have to debug its operation.” In fairness, I guess that we should not expect the newbie Flex-based RIA solution to have a debugging plan in place.

I’ll share with you how I go about debugging an RIA client/server solution, and more importantly, how to develop a plan so you have an idea of where to start when the first fire-up of an RIA client /server solution doesn’t.

RIA client and server applications operate disparately on an asynchronous basis. The common thread between the two applications is data messaging using a common streaming data packet defined in Adobe’s AMF 3.

When one of the two RIA client/server applications request a read or write of data to the other, we expect that operation to occur. But what if the operation does not occur? Is the problem in the RIA client or server, or perhaps even both?

Many times, especially on the server side, the problem is something as basic as a missing semicolon “;” or curly bracket “}” program statement delimiter. The server side operational problems are more invisible because, by design, the server is designed to operate standalone without a user interface.

The application servers identified in the previous Server Platform Summary section all provide utilities to check their operation. There’s not much in the way of tools to assist you with evaluating the operation of the server objects that you develop. When developing the server-side PHP, Java, or .NET objects, you should at the same time develop test stub code (a.k.a. test suite) to test the stand-alone operation of your object before it is deployed inside your application server.

For our “MyFamily” WebORB PHP server object you will find a file named “MyFamilyTest.php.” See Listing 8. I run this test stub code against the “MyFamily” PHP objects using the PHP CLI (Command Line Interface) scripting engine. The test first instantiates the “MyFamily” object and then returns the “MyFamily” object pointer by calling the “getMyFamily” method.
<?php
require_once("MyFamily.php");

$myFamily = new MyFamily();
$myFamilyObj = $myFamily->getMyFamily();

echo "---------------\n";
echo "\$myFamilyObj: "; print_r($myFamilyObj);
echo "\n---------------\n";
echo "var_dump(\$myFamilyObj): "; var_dump($myFamilyObj)
?>
Next the “MyFamilyTest.php” dumps the object as an array of data ( “print_r” function ) function and object layout ( “var_dump” function). Listing 8 shows the results of the two variable dumps of the of the object pointer. I observe that the data output is as we expect it to be.
Output from running the Listing 8's "MyFamilyTest.php" code:
$myFamilyObj: MyFamily Object
(
    [father] => Person Object
        (
            [firstName] => Robert
            [lastName] => Jones
        )

    [mother] => Person Object
        (
            [firstName] => Betty
            [lastName] => Jones
        )

    [children] => Array
        (
            [0] => Person Object
                (
                    [firstName] => Jim
                    [lastName] => Jones
                )

            [1] => Person Object
                (
                    [firstName] => Shirley
                    [lastName] => Smith
                )

            [2] => Person Object
                (
                    [firstName] => Sally
                    [lastName] => Jones
                )

        )

)

---------------
var_dump($myFamilyObj): object(MyFamily)#1 (3) {
  ["father"]=>
  object(Person)#2 (2) {
    ["firstName"]=>
    string(6) "Robert"
    ["lastName"]=>
    string(5) "Jones"
  }
  ["mother"]=>
  object(Person)#3 (2) {
    ["firstName"]=>
    string(5) "Betty"
    ["lastName"]=>
    string(5) "Jones"
  }
  ["children"]=>
  array(3) {
     [0]=>
     object(Person)#4 (2) {
       ["firstName"]=>
       string(3) "Jim"
       ["lastName"]=>
       string(5) "Jones"
     }
    [1]=>
    object(Person)#5 (2) {
      ["firstName"]=>
      string(7) "Shirley"
      ["lastName"]=>
      string(5) "Smith"
    }
    [2]=>
    object(Person)#6 (2) {
      ["firstName"]=>
      string(5) "Sally"
      ["lastName"]=>
      string(5) "Jones"
    }
  }
}
I would never think of deploying application-server objects without first testing them standalone using some form test stub to exercise their operation. This way you are assured that there is a reasonable chance that your application server’s newly-deployed object is operational when you make your desired read or write test from your Flex client.

Another good idea is to not wait until your entire client and server code is fully operational before testing your RemoteObject operations. Test your AMF remoting messaging early. It might be best to start by simply receiving your AMF code stream at the client before even starting to work on the results display.

If you don’t yet have your data results display code working, use your Flex Builder debugger to view the AMF 3 results returned from the application server. Refer back to the previous Listing 3, which is the server return AMF 3 event server. Note the ActionScript trace statement at the last line of the “handlerGetMyFamily” method. I’ll insert a debugging breakpoint here to observe the family data results returned from the application server. It will look like Figure 4.

fig4.png
Figure 4. Flex Builder Debugger View of the MyFamily Data

If you need more detail per the structure of the application server’s AMF 3 family data, you can expand the data view shown in Figure 4. The example of the received AMF 3 family data is shown in Figure 5.

fig5.png
Figure 5. Expanded View of Figure 4 Debugger Output

All of the above ActionScript RemoteObject testing can be well before your Flex client is complete. Check the data received for proper content and structure well before building all the results display code.

Again, the Flex debugger is your friend. Depend on it frequently instead of guessing what is wrong by starting at your AMF 3 remoting code.

You may feel that the application server’s object that you wrote is working, as it should, but you are not seeing the results you expect on the Flex client. Your first sense might be a short-term panic! Is the problem on the server or how the data is received on the Flex client? You know that data is streaming across the network, in our case from the server to the client. You know the data is a stream of information in the AMF 3 format. You think it would sure be nice to “sniff” the network to observe the data streaming between the client and the server. Well, you can observe the network!

Your application server will typically log actions and errors when operating. With some application servers you can insert logging code within your objects or the core server’s objects. This way you can run your remoting tests and then view the server’s log file. Many times this will provide adequate information that identifies what the problem is.

There are two “Web debugging proxy” utilities named Charles ( http://www.xk72.com/charles/ ) and Service Capture (http://kevinlangdon.com/serviceCapture/ ) respectively. Both of these debugging proxies allow you, as the developer, to view all of the HTTP traffic between your workstation and the Internet (that is your Flex client and your application server, even if your server resides on the same workstation). This includes requests, responses ,and the HTTP headers (which contain the cookies and caching information).

Both of the debugging proxies are capable of optionally displaying the AMF 3 serialized data stream in a human-readable format. Figure 3. Serialized AMF 3 Structure of the MyFamily Data is an example of the human-readable display of the serialized data captured from the network connection between the client and the server. This display can be invaluable information at times.

Both “Web debugging proxy” utilities are nominally priced and provide limited time trial evaluations. I suggest that you evaluate their use and capability with the idea of acquiring one of the debugging proxy utilities. Personally, I don’t use my debugging proxy utility often. But when I do, I realize that it’s once again saved countless time in guessing what data is streaming between my Flex client and application server.

In summary, following are the client/server remoting debugging tips you should master and practice:

• Master the use of your Flex Builder debugger in order to observe the reading and writing of AMF 3 data on your Flex client.

• Isolate and locally test your respective client and server remoting code for proper operation using your test stub code (a.k.a. test suite). Divide and conquer—make sure each side of the solution is working before attempting to make both sides communicate with each other. This one step alone can eliminate a lot of grief when attempting to get client/server asynchronous remoting operational.

• Test your client/server remoting messaging early in your project’s development and often thereafter.

• If your application server provides logging services, take advantage of using the data log to identify server operation issues. If possible insert server log debug statements to observe server operation.

• Acquire and use a Web debugging proxy utility to intercept and review the network transfer of client/server remoting.

Deploying the Example
fig6.jpg
Figure 6. Application Server Software Deployment Hierarchy

Note: this solution deploy section assumes that you have already pre-installed your AMP server (Apache or MS IIS Web server), MySQL (optional), and PHP scripting engine.

1. Download and install WebORB for PHP into your (nominally Apache) web server root folder. Follow the WebORB for PHP installation and configuration instructions found in the Midnight Coders Web site at Getting Started with Flex and WebORB for PHP ( http://www.themidnightcoders.com/weborb/php/gettingstarted.htm ). Place the WEBORB root folder in your Web server root folder as shown in Figure 6. Test WebORB for PHP operation by entering the following in your Web browser: http://localhost/WEBORB/

2. Download and unzip the “MyFamilySource.zip” file identified at the start of this article. There are two folders of files and one Zip file to install. One folder is the Flex builder client project; the second folder is installed inside the WebORB PHP server; the third folder is a pre-compiled version of the MyFamily example.
a. MFamily folder for WebORB for PHP install.
b. WebServerRoot folder containing MyFamly Flex generated application folder. Place MyFamily folder in the root of your Web server folder as shown in Figure 6.
c. MyFamly.zip folder for Flex Builder 3 install.

3. Copy (or move) the MFamily (not MyFamily) folder into the WEBORB /Services folder as shown in Figure 6.

4. Configure the MyFamily Flex RPC endpoint in the “remoting-config.xml” file. This XML file is located in the folder path of WEBORB/Weborb/WEB_INF/flex/remoting-config.xml, as shown in Figure 6. Make the following tag entry somewhere in the XML file where the tags reside:

	<destination id="MyFamily">
		<properties>
        			<source>MFamily.MyFamily</source>
   		</properties>
   	  </destination>
5. Copy the MyFamily example Flex client application to your Web server root folder as shown in Figure 6.
Note: At this time you can run and evaluate the MyFamily example before you install the example MyFamily project. From your Web browser enter: http://localhost/MyFamily/main.html This exercise will tell you if your WebORB PHP Web application server is properly installed and configured. Get this working before performing step number 6.

6. Remove the “MyFamily.zip” file from the MyFamilySource folder and unzip the file, which creates a MyFamily folder. Import the MyFamily folder into Flex Builder 3. Use the File menu, Import menu item. (The Flex Builder MyFamily project properties match my development environment on a Macintosh OS X computer. You will need to edit the Flex Builder data path project properties to match your development environment and web site path hierarchy. )

Read more from Pete Mackie. Pete Mackie's Atom feed

Comments

11 Comments

funkyboy said:

Very interesting and exhaustive post. Chapeau!

Evert said:

I wanted to point that AMF3 is generally not compressed.. some 'Externalized Objects' can be, but 99% of the time objects are not of this type..

Also, it's important to note that even though the AMF3 serialization spec is open to the public, its only 1 aspect of the remoting protocol.. There's much more to it, and thus far there's no official spec.

Jonnie said:

Amazing Article, I have been looking for something like this for a while now, Thank You!

-Jonnie

Cemaprjl said:

Hi. Do you know why not either service capture not either charlie do not capture amf requests/responses to weborb php services?
i've checked that in weborb service browser in Flex samples -> remoting (amf3) -> basic invocation (mxml or as3),
checked at my localhost test site - but there is nothing yet been captured.
they captured amfphp requests, captured correctly all other requests - http, java, xml e.t.c

Pete Mackie said:

No, I do not know why neither Service Capture nor Charles are capturing AMF 3 RemoteObject transfers. These two proxy utilities have both consistently worked well for me for over a year to monitor data transfers between Flex clients and WebORB for PHP servers.

Crytal Lake said:

Figure #6 is the best!

Martin Moschitz said:

Error Handling?

how is this done, can you modify the message send to the Fault Handler? Whats the recommended way of sending Errors from within PHP to the caller in Flex?

Thx,
martin

Pete Mackie said:

You handle errors by throwing an exception along with a message. Here's a example from Families.php in my other article at: http://www.insideria.com/2009/03/amf3-php-server-objects-to-fle-1.html

if (!$parents = $this->mysqli->query("SELECT * FROM parents LIMIT 100")) {
$msg=self::errorPrefix.self::queryError;
// Free query result set
$parents->free_result();
$this->mysqli->close();
throw new Exception($msg);
}

re: can you modify the message send to the Fault Handler?

Yes, you can return any message the you desire, through the Exception($msg) fault handler call.

Smin Rana said:

Master Article

Ryan said:

Whats the recommended way of sending Errors from within PHP to the caller in Flex? I want to add some interesting front end UI to a web dating site. Flex seems like an interesting choice.

Pete Mackie said:

Ryan,

The recommended--and actually the only way--to return error messages from the PHP server to the Flex client is by throwing a PHP exception along with a message. For more details, see my reply comments above, which starts with "You handle errors by throwing an exception along with a message," dated April 20, 2009 5:03 AM.

Leave a comment


Tag Cloud

Question of the Week: Dream App

If you had an unlimited budget and unlimited resources what application would you build and why would you build it?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.