Processing AMF 3 PHP Server Object Arrays on the Flex Client Using Object Relational Mapping

In my first RIA Object Relational Mapping article (see box below) you learned how to transfer the application server’s PHP objects from the server to the Flex client. We accomplished this by using Adobe’s AMF 3 messaging protocol for the client-to-server transfer while preserving the object structure on both platforms (a.k.a. “object relational mapping”). We also covered all the basics of AMF 3 messaging protocol, deploying the Flex client with remote server access, review of server platform alternatives, and selection of the WebORB for PHP application server.

There were so many basic concepts to initially cover that our example showed the transfer from server-to-client of only one simple object. Transferring one simple object at time is not the way the real world works. There are typically hundreds of objects to transfer from the server to the client for information display. That’s what makes an RIA (rich Internet application). Right? With what you know so far, you might think that all you need to do is perform hundreds of single object requests from the server, and voila—later rather than sooner—all of your objects from the server will reside on the Flex client.

Making repeated Flex client single-object data requests to the server is not the way to go. Why, you might ask? Well, it’s slow to say nothing about being highly inefficient. Real work means requesting lots of data objects from the server with one request to the server. These requests are returned as an array. Lets see if we can preserve the object mapping as we move an array of objects from the server to the client. This is what the balance of this article is all about—doing “real” server-to-client work.

This article expands on the notion of Adobe Flex client-to-server object mapping per my first O’Reilly Inside RIA article titled AMF3 PHP Server Objects to Flex Client Object Relational Mapping ( http://www.developria.com/2008/04/amf3-php-server-objects-to-fle.html ). You are encouraged to master the AMF 3 messaging protocol and object relational mapping basics discussed in my first RIA article. Occasionally, in this article, I refer to this first article using the notation of “in my first RIA Object Relational Mapping article,” which means navigate to the above URL for details about the basics.

Overview

My first RIA Object Relational Mapping article covers object-relational mapping basics and transferring data objects from the client to the server—while preserving the object’s data structure using object relational mapping.

To make this remote object array data access and resulting data display on the Adobe Flex client, your work requires your understanding of Flex builder code development, web server deployment and administration, PHP code writing and debugging, and MySQL database deployment with installation of data from SQL schemas. “How to” information on all of these topics is readily available elsewhere. I assume you have adequate knowledge for installing all these client and server system elements and know how to deploy and develop with them to your advantage. These details are not covered here.

For some server details, see Server Platform Summary in my first RIA Object Relational Mapping article.

If you are unable to deploy the client and server platforms at this time, I do suggest that you continue reading. You’ll become aware that developing rich clients using Adobe Flex Builder IDE and resourcing information from open-source server is actually straightforward to implement once the client and server platforms are in place and you have some core understanding of client-server remoting from this article.

This article and the accompanying client and server example code show you how to transfer the same Family object—from first RIA Object Relational Mapping article—as arrays of object data from the client to the server. We still need to preserve the server-to-client object mapping.  This article’s client-side discussion is about client-object mapping when the objects are received as an array.

The source of these server data objects is from a MySQL relational database repository. We’ll discuss all the server’s object creation and packaging as an array for transferring to the Flex client using the Adobe AMF 3 protocol.

Using a PHP object on the application server, we’ll read information from the database repository, transform the data into an object array, and send this data on its merry way to the Flex client. The Flex client will understand the object structure of the received data array and be able extract the object’s properties for convenient user viewing.

Following, we review the client and server example code, some RIA debugging tips, and finally how to deploy this article's example code into your Flex client and PHP-based application server. As a basis for moving ahead with the following discussion, first start with a review of the topics Remoting Protocol Summary, Server Platform Summary, and About AMF 3 in my first RIA Object Relational Mapping article.

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)

Web Debugging Proxy (Optional tool. Use is highly recommended)
• Charles (http://www.charlesproxy.com)
• ServiceCapture (http://kevinlangdon.com/serviceCapture)

Example files
FamiliesSource.zip (ZIP, 1MB)

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.

Object Relational Mapping of ActionScript and PHP Classes

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

Figure 1.png
Figure 1. Family Classes, Client and Server

On both sides of our example solution, our “Family” 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 Family object’s data from the WebORB for PHP application server. The WebORB application server will serialize the Family 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 Family 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 “Family” and “Person” 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 the server-to-client object data structure will not map, or you may receive a RemoteObject runtime error on the AMF3 receiver during the AMF 3 receive event processing.

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.

Families 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 Flex Client and PHP Server Example Code 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.

In my first RIA Object Relational Mapping article we purposely provided a very simple application built specifically to demonstrate Flex client/server object-relational mapping. This article’s example code builds on the first article in that the server and client objects are identical to my first RIA Object Relational Mapping article. The first article returns one object from the PHP application server to the Flex client using AMF 3 RemoteObject transfer. We new get a little braver in order to show how to transfer and display an array of objects from the PHP application server to the Flex client.

Figure 2a and 2b shows the result of loading and running the Families application. Figure 2a is the application’s starting display.

Figure 2a.jpg
Figure 2a. Families Flex Client Application Startup

When the getFamilies button is clicked the Family 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 Family 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 2b.

Figure 2b.jpg
Figure 2b. Families Application Result

The above two views are all that occurs with our Families example application. There are lots more issues to discuss, related to the underlying code and how the Families Flex client and application server code works. Next, we’ll dig into the code’s operation to master transferring arrays of objects from the PHP application server to the Flex client via AMF 3 remoting.

The following code discussion sometimes refers to the example code in the Flex Builder client and PHP application server. You may want to first install this code, for easier review, by jumping ahead and performing the steps in the Deploying the Flex Client and PHP Server Example Code section.

Families Flex Client Example Code Review

We’ll start by reviewing the Flex client code in the “index.mxml” module. The mxml code for the Families application’s display is between lines 88 and 108. We won’t be discussing this code except to say that line 91 contains a getFamilies button that, when clicked, requests family data from the WebORB PHP application server. Note also that line 90 contains a Clear button to so you can run the server-to-client remote object transfer again.

Deploying the Flex Client and PHP Server Example Code

In my first RIA Object Relational Mapping article, I covered how to set up a Flex RemoteObject connection to the PHP application server using a MXML RemoteObject (<mx:RemoteObject>). There is another way to create the Flex client code by writing the RemoteObject connection using ActionScript 3. In our Families Flex client code example, we’ll show how to set up the RemoteObject connection using ActionScript 3 code.

Before we delve into this RemoteObject code, I suggest that you make yourself aware of the Adobe documentation on this topic:

  • Adobe® Flex® 3 Language Reference, RemoteObject APIs
  • We'll look at the establishment of our RemoteObject ActionScript 3 code through three separate ActionScript 3 RemoteObject elements. These elements are:

    1. Establishment of the Flex client RemoteObject connection during the Flex client application initialize time.
      • We want the RemoteObject connection to the PHP Web application server to be up and ready before client-to-server messaging is needed.
    2. The ActionScript 3 mouse "click handler" code, which allows the Flex client to request the data from the PHP application server.
    3. The ActionScript event handler to process the requested data from the PHP application server to the Flex client using AMF 3 messaging via the RemoteObject connection.

Initialize the Flex RemoteObject Connection

Note the Flex client application makes a start-up initialize request at line 4 of “index.mxml” to call the initData ActionScript 3 method at line 37. The initData method, lines 37 to 44 in “index.mxml,” Listing 1, provide instantiation of the RemoteObject object and set the RemoteObject object properties. Our RemoteObject connection between the client and server will last for the life of the Flex client application.

Listing 1 is lines 37 to 44 from the “index.mxml” code module

public function initData():void {
	familiesRemote = new RemoteObject();
	// Your PHPClassName.php class must be deployed in the WebORB for PHP /Services folder. 
	// In our case for this client it is: (Web Server Root)/WebORB/Services/MFamiliesDbIO
	familiesRemote.destination = "Families";
	familiesRemote.getFamilies.addEventListener("result", handlerGetFamilies);
	familiesRemote.addEventListener("fault", faultHandler);
}

In the first line in Listing 1, we instantiate our ActionScript 3 RemoteObject object.

Our “Families” Flex Builder project was configured to connect to the WebORB application server located in the “localhost” web server root. These project level connection configuration parameter details are covered in the section Deploying the Flex Client and PHP Server Example Code. The comments, in lines 3 and 4 of Listing 1, identify the path hierarchy in the WebORB for PHP application server running on our “localhost” Web server.

The next RemoteObject property of interest is the destination=“Families” 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. You’ll see the path to the other side of the RemoteObject connection when we get to the Families WebORB Server Example Code Review section.

It is important to note that any Flex client-to-remote application server connection is inexorably linked in form, fit, and function. Accordingly, you must design both elements (client and server) simultaneously. In other words you cannot fully establish the client remoting code without knowledge of the hierarchy and object methods available in the remote application server. You must work to bring these code designs and deployment up together.

Listing 1, lines 6 and 7 establish the event handlers for RemoteObject data received from our PHP application server and secondarily provide a pointer to an ActionScript 3 method to handle received data remote messaging faults.

Adding an event listener, by setting the “familiesRemote.getFamilies.addEventListener("result", handlerGetFamilies)” RemoteObject property establishes the ActionScript 3 event hander to process AMF 3 RemoteObject data from the WebORB PHP application server. Listing 1, line 6 states that if you receive an AMF 3 RemoteObject message from the PHP application server’s “Families” object (Listing 1, line 6), “getFamilies” method (Listing 1, line 6) then pass that message to the Flex client application’s “handlerGetFamilies” method. This is where you will soon see how the received data is bound to pre-defined Flex client objects and processed for display.

The “familiesRemote.addEventListener("fault", faultHandler)” RemoteObject code sets up the ActionScript method to call when the RemoteObject request fails. In our example this ActionScript 3 method is named faultHandler. The method’s task is to display an error dialog containing the RemoteObject communication error message.

Mouse Click Handler Request Data from the Remote Server

Our next requirement is for a way to request data to be sent from the WebORB for PHP server to send data to the client. This is our mouse click handler, which is activated when the user clicks on the getFamilies button, shown above in Figures 2a and 2b.

The ActionScript 3 mouse "click handler" code provides a way for the Flex client to fire a data request to the PHP application server to return the Families data from the server to the client. When the user clicks the getFamiles button, line 91 of "index.mxml", the "handlerClickGetFamilies" ActionScript method, lines 46 to 51 of Listing 2, is called.

Listing 2 is lines 46 to 51 from the “index.mxml” code module

// ------ Handlers ------  
	private function handlerClickGetFamilies():void {  
		CursorManager.setBusyCursor();
		familiesRemote.getMyFamilies();
		trace("handlerClickGetFamilies()");
	}

First, it’s a good idea to set the application’s cursor to busy so that the user is aware that the Flex client is awaiting the server’s response to the client’s data request—line 3 of Listing 2.

The active code in the ActionScript 3 “handlerClickGetFamilies” method is line 4 of Listing 2 where the “familiesRemote” RemoteObject object request call is made to the “getFamilies” object method in the PHP application server. You’ll see how these are linked together (client to server) when we get to our discussion of the Families WebORB Server Example Code Review section. For now, accept that this will link the client and server together and RemoteObject messaging will work.

Line 5 of Listing 2 is an optional debug trace statement that can be used when bringing up of the client-to-server AMF 3 message remoting.

The RemoteObject AMF 3 Received Data Handler

When the AMF 4 RemoteObject connection was initialized, Listing 1, the message “result” event handler was set up in line 42 of “index.mxml” in the Flex Builder project to handle RemoteObject messaging events from the PHP application server.

Our RemoteObject event handler method code is shown in Listing 3. After the transfer of the AMF 3 RemoteObject is complete the Flex client activates a “ResultEvent” event, which calls the “handlerGetFamilies” method to process the received data.

Listing 3 is lines 57 to 75 from the “index.mxml” code module

// Families remote object event handler  
private function handlerGetFamilies(event:ResultEvent):void {
   var i:int = 0;
   var parents:Object;
   CursorManager.removeBusyCursor();
   familiesObjArray = ArrayUtil.toArray(event.result);
   familiesObjArrayCollection = new ArrayCollection(familiesObjArray);
   // Following 'for each' loop remaps the "familiesObjArray" in mx:DataGrid id="familes"
   parentsObjArray = new Array(familiesObjArray.length);
   for each (var family:Family in familiesObjArray) {
      parents = new Object();
      parents.fatherFirstName = family.father.firstName;
      parents.fatherLastName = family.father.lastName;
      parents.motherFirstName = family.mother.firstName;
      parents.motherLastName = family.mother.lastName;
      parentsObjArray[i++] = parents;
   } 
}

Line 5 in Listing 3 removes the busy cursor, which was set by the mouse click handler requesting data from the PHP application server—i.e. server-to-client AMF 3 data transfer is complete.

The “event:ResultEvent” parameter passed into the Listing 3 event handler is an array of “Family” objects. See Figure 1 for the “Family” object data structure. Line 6 transfers the event results into a working and array property named “familiesObjArray.” Figure 3 is a Flex Builder debugger view of the “familiesObjArray” content—an array of Family objects—partially expanded.

Figure 3.jpg
Figure 3. “familiesObjArray” Array of Family Objects

Listing 3, lines 8 to 16, remaps the “familiesObjArray” data for a more convenient DataGrid display rendered by lines 93 to 100 of “index.mxml.”

The balance of the code in “index.mxml” is application support code. I do not discuss the Flex client supporting code in this article.

Families WebORB Server Example Code Review

Our WebORB for PHP application server code server nominally resides in the root of your Web server (the “htdocs” folder with Apache’s HTTP Server and “Inetpub\wwwroot” folder with Microsoft’s IIS). The WebORB for PHP server-side code of interest is deployed in WebORB’s “Services” folder containing a folder named “MFamilies.” For a visual perspective of the WebORB for PHP application server deployment see Figure 6. Application Server Software Deployment Hierarchy.

There are many details to cover on both the server side and client side when discussing AMF 3 RemoteObject messaging. This article is long enough as it is. Accordingly we will not review our PHP Service code in operational detail. I assume the reader is knowledgeable enough with PHP syntax to follow the code’s logic on his or her own.

The—one might say the only—PHP module of interest is the “Families.php” object file in WebORB’s “Services” folder. When the “Families” Flex client makes an AMF 3 RemoteObject request to the WebORB server, it’s the “Families.php” object module that is instantiated by WebORB to perform the data acquisition and AMF 3 remote object transfer to the Flex client.

By now, you are probably wondering where the linkage between the client and server occurs to have the Flex client call the “Families.php” object file. Hang on, and we’ll cover this in some detail in the next section.

“Family.php” and “Person.php” modules are object definitions required by “Families.php” to structure and return an array of objects to the Flex client. See Figure 1. Family Classes, Client and Server for the structure details of these two supporting objects.

When “Families.php” is instantiated by the WebORB application server, the object construction module establishes a database connection to the “Families” MySQL database that supports two tables of data: “parents” and “children.”

After the class instantiation to an object, the “getFamilies” method is called. The method:

  1. Reads the “parents” table data from the “Families” MySQL database.
  2. Reads the “children” table data from the “Families” MySQL database.
  3. Packages each database record into a “Family” object.
  4. Bundles the database record-level “Family” objects into an array.
  5. Returns the array to the WebORB application server for serializing into an AMF 3 data stream, which is returned to the Flex client and de-serialized for display.

The “FamliesTest.php” PHP module is used for stand-alone testing of the “Families.php” object for proper operation prior to sever-to-client RemoteObject messaging. The same is true for the “FamilyTest.php” module. It’s there for stand-alone operation of instantiating the “Family.php” module’s object.

“Famlies.sql” is the MySQL schema data used to populate the MySQL database with server-to-client test data. This MySQL database schema file does not need to reside here. It was simply placed here for convenience of packaging the “Family” code.

RemoteObject Linkage of the Flex Client to WebORB Services PHP Object

The linkage code in the Flex client and server provides a direct connection between the two disparate elements using a RemoteObject connection. At a top-level view, we must:

  1. Provide an addressing scheme between the client and server, as neither element is aware of the other’s existence as they are being developed/deployed.
  2. Provide a mapping scheme where the client’s data request accesses the appropriate PHP method residing in WebORB’s Services—in our environment, the “Family.php” object module.

Client/Server Addressing Scheme

When your Flex Builder project properties are established, we establish where the Flex client is built--and operates--on the Web server relative to where the WebORB for PHP server resides. We then install a custom PHP module in the Flex client folder that points, on a relative data path basis, to the WebORB server. The standard and consistent name for the file for all Flex client builds is “weborp.php.”

The specifics of how to establish this connection are covered in the upcoming section, Deploying the Flex Client and PHP Server Example Code.

Client/Server RemoteObject Messaging Mapping Scheme

Next, let’s discuss how the client-to-server connection mapping is established. Remember our goal is that the “Families” Flex client must connect specifically—and only—to the “FamilyTest.php” module in WebORB’s application server “Services” folder.

Some of the Flex Builder “Families” project parameters discussed next were established when the project’s Flex Builder client and WebORB application server were deployed. For these details see the following section, Deploying the Flex Client and PHP Server Example Code. Also, you might want to follow along with Figure 6. Application Server Software Deployment Hierarchy in order to visualize where these ActionScript 3 RemoteObject parameters are established.

  1. The “Families” Flex Builder project’s “Additional compiler arguments” is set to access WebORB application server’s “services-config.xml” file, as follows:  -services "C:\AMP\Apache\htdocs\WebORB \Weborb\WEB-INF\flex\services-config.xml"
  2. WebORB’s “services-config.xml” file contains a “destination” entry mapping (linking) to our “Families.php” Services object. See step #5, Figure 7, in the Deploying the Flex Client and PHP Server Example Code section to review the XML destination element values. The destination linkage is Families:MFamilies.Families. (“Families” destination name maps to WebORB “Services” folder containing the “MFamlies” folder that contains the “Families” PHP object with a file name of “Families.php”.)
  3. Our “Families” Flex client (running in the Web server root) contains a  file named “weborb.php” that includes to a file in the WebORB application server that provides a relative path linkage between the Flex client and WebORB application server: require_once("../WebORB/Weborb/ORBHttpHandler.php");
  4. The “Families” client’s application module (“index.mxml”) sets the ActionScript 3 RemoteObject destination to “Families.” See line 5 of Listing 1: “familiesRemote.destination = "Families”. Accordingly, the Flex client’s RemoteObject connection is inexorably linked to WebORB’s “Families.php” in the “Services” folder. (Item 2, above Families:MFamilies.Families)

In summary, our Flex client is RemoteObject linked to the WebORB application server via the linkage mappings covered in the above four steps.

Deploying the Flex Client and PHP Server Example Code

The Magic of Server-to-client Object Mapping

Earlier in Figure 1. Family Classes, Client and Server we observed that both the Flex client and WebORB application server used identical structures “Family” and “Person” classes slightly different in syntax to support the local native programming language. The native programming language is ActionScript 3 for the Flex client and PHP for the WebORB application server.

Again, I must state that these identical object structures are not a programming accident. The were purposely and carefully selected to be identical so that disparate platform objects match form, fit, and function when ActionScript 3 RemoteObject is transferred between the server and client.
 
Then later, in Figure 3. “FamiliesObjArray” Array of Family Objects, we noted that the Flex client received the RemoteObject array and magically recognized that the received data was an array of “Family” objects consisting of “Person” and “Children” object properties. Let’s analyze how and why this server-to-client object mapping occurs.

From the “Families.php” class residing in the WebORB application server an array of “Family” objects is serialized as an AMF 3 RemoteObject that is transferred is structured, captured by the Charles Web debugging proxy, as shown in Figure 4.

Figure 4.jpg
Figure 4. AMF 3 Server-to-client RemoteObject Transfer

Figure 4 displays the server-to-Flex client RemoteObject data transfer. Note that the objects returned are a value of “MFamilies.Family” This object value is set by the WebORB application server on the basis of the sequence:

  • The Flex client request to the “getFamiles” method in WebORB’s application server…
  • That, in turns calls the “Families” PHP object module contained the file within WebORB application server located in the folder:  “~/WebORB/Services/MFamilies/Families.php  ….”
  • Identifying that a “Family” object is being returned from the “MFamiles” object container folder, i.e. “MFamilies.Family”

As the above-received AMF 3 data stream is being de-serialized, the Flex client’s remote object recognizes that the 10 returned objects are of a type “MFamilies.Familes” (the folder / PHP file name returning the RemoteObject data).

This object recognition (server-to-client mapping) occurs because of the “Family” and “Person” objects defined within the “Families” Flex Builder project. The ActionScript 3 object definitions are located in the project’s “objmaps” folder and shown in Listing 4.

 
________________________________________
File: Family.as                        

package objmaps {
	import objmaps.Person;
    
	[Bindable]
	[RemoteClass(alias="MFamilies.Family")]
	public class Family {
		
		// Constructor
		public function Family() {}
		
		public var father:Person;
		public var mother:Person;
		public var children:Array;
	}
}
_________________________________________
File: Person.as

package objmaps {

	[Bindable]
	[RemoteClass(alias="MFamilies.Person")]
	public class Person {
		
		// Constructor
		public function Person() {}

		public var firstName:String;
		public var lastName:String;
	}
}

Note in Listing 4 that both object definitions (“Family.as” and “Person.as”) have been set as Bindable Remote Classes, with respective aliases of “MFamilies.Family” and “MFamilies.Person.” When our Flex client receives the AMF 3 RemoteObject data stream array from the WebORB application server, the Flex client identifies the Type = “Object” with Value = “MFamilies.Family” and Type = “Object” with Value = “MFamilies.Person” (Figure 4). Flex respectively binds the received objects to be of type “Family” and “Person” objects (Listing 4).

This is how the magic—well it’s not really magic—of client-to-server object mapping occurs. And the mapping consistently and conveniently works for arrays of AMF 3 RemoteObjects too.

More On RIA Debugging Tips

First review my first RIA Object Relational Mapping article (http://www.developria.com/2008/04/amf3-php-server-objects-to-fle.html). In the section RIA Debugging Tips, there’s a plethora of RIA debugging tips and procedures that I do not duplicate in this article.

I continue to support that it’s mandatory to do standalone testing of objects residing in the WebORB for PHP application server prior to server-to-client integration. What I discuss next is the same procedures as described in my first RIA Object Relational Mapping article. The exception being that 1) the name of the two PHP object test modules are different and 2), of course, the resulting data output is different.

Standalone Testing of the Families PHP Object

The WebORB application server will return an array of “Family” objects to the Flex client. Before returning an array of “Family” objects we must first determine that one “Family” object can be properly instantiated. “Family” objects consist as a set of “Person” objects. Our test here first instantiates necessary “Person” objects and then combines the “Person” objects into a “Family” object.

For our “Family” WebORB PHP server object testing you will find a file named “FamilyTest.php.” See Listing 5. We’ll run this test stub code against the “Person” and “Family” PHP objects using the PHP CLI (command line interface) scripting engine. Our “FamilyTest.php” test stub instantiates a father and mother as “Person” objects, lines 4 and 5 of Listing 5. Following these objects instations, an array of children as an array of “Person” objects is generated, line 6 of Listing 5.

Finally the “Family” object is instantiated using our “Person” objects of father, mother and the children array, line 8 of Listing 5.

require_once("Person.php");
require_once("Family.php");

$father = new Person('Sam', 'Blackburn');
$mother = new Person('Barbara', 'Blackburn');
$children = Array(new Person('Robert','Blackburn'), new Person('Lisa','Blackburn'), new Person('Charles','Blackburn'));

$familyObj = new Family($father, $mother, $children);

echo "-------------------\nFather and Mother Person Objects, and Children as an Array of Person Objects:\n";
echo "\n\$father: "; print_r($father);
echo "\n\$mother: "; print_r($mother);
echo "\n\$children: "; print_r($children);
echo "\n-------------------\nThat get combined into a \"Family\" Object, like this:\n\n";
echo "\$familyObj as Array:\n"; print_r($familyObj);
echo "\n-------------------\nAnd this....\n\n";
echo "\$familyObj as Object:\n"; var_dump($familyObj)

Lines 10 through 17 of Listing 5 output our individual and combined objects shown next. We now know that we can create one “Family” object. The next section, Standalone Testing of the Families PHP Objects, will show you how to verify the proper operation of creating an array of “Family” objects.

Output from running the Listing 5's "FamilyTest.php" code:

-------------------
Father and Mother Person Objects, and Children as an Array of Person Objects:

$father: Person Object
(
    [firstName] => Sam
    [lastName] => Blackburn
)

$mother: Person Object
(
    [firstName] => Barbara
    [lastName] => Blackburn
)

$children: Array
(
    [0] => Person Object
        (
            [firstName] => Robert
            [lastName] => Blackburn
        )

    [1] => Person Object
        (
            [firstName] => Lisa
            [lastName] => Blackburn
        )

    [2] => Person Object
        (
            [firstName] => Charles
            [lastName] => Blackburn
        )

)

-------------------
That get combined into a "Family" Object, like this:

$familyObj as Array:
Family Object
(
    [father] => Person Object
        (
            [firstName] => Sam
            [lastName] => Blackburn
        )

    [mother] => Person Object
        (
            [firstName] => Barbara
            [lastName] => Blackburn
        )

    [children] => Array
        (
            [0] => Person Object
                (
                    [firstName] => Robert
                    [lastName] => Blackburn
                )

            [1] => Person Object
                (
                    [firstName] => Lisa
                    [lastName] => Blackburn
                )

            [2] => Person Object
                (
                    [firstName] => Charles
                    [lastName] => Blackburn
                )

        )

)

-------------------
And this....

$familyObj as Object:
object(Family)#6 (3) {
  ["father"]=>
  object(Person)#1 (2) {
    ["firstName"]=>
    string(3) "Sam"
    ["lastName"]=>
    string(9) "Blackburn"
  }
  ["mother"]=>
  object(Person)#2 (2) {
    ["firstName"]=>
    string(7) "Barbara"
    ["lastName"]=>
    string(9) "Blackburn"
  }
  ["children"]=>
  array(3) {
    [0]=>
    object(Person)#3 (2) {
      ["firstName"]=>
      string(6) "Robert"
      ["lastName"]=>
      string(9) "Blackburn"
    }
    [1]=>
    object(Person)#4 (2) {
      ["firstName"]=>
      string(4) "Lisa"
      ["lastName"]=>
      string(9) "Blackburn"
    }
    [2]=>
    object(Person)#5 (2) {
      ["firstName"]=>
      string(7) "Charles"
      ["lastName"]=>
      string(9) "Blackburn"
    }
  }
}

Standalone Testing of the Families PHP Objects

For our “Families” WebORB PHP server object you will find a file named “FamiliesTest.php.” See Listing 6. I run this test stub code against the “Families” PHP objects using the PHP CLI (command line interface) scripting engine. The test first instantiates the “Families” object and then returns an array of “Family” objects by using the ““Families” object pointer by calling the “getFamilies” method.

require_once("Families.php");

try {
	$familes = new Families();										// Instantiate the MyFamilies class, and...
	$familyArray = $familes->getFamilies();		// create the  array of Family objects.
	echo "\$familyArray Return:\n";
	echo "  Note: Following is the Family object array of that will be returned to your Flex client.\n\n";
	var_dump($familyArray); 
	echo "\n";
} catch (Exception $exception) {
	printf("%s\n", $exception->getMessage());
}
echo "'FamiliesTest.php' Object Test Call Complete.\n";

Next the “FamiliesTest.php” dumps the data as an array of data (“var_dump” function). Listing 5 shows the test results as an array of “Families” objects. I observe that the data output is as we expect it to be.

Output from running the Listing 6's "FamiliesTest.php" code:

$familyArray Return:
  Note: Following is the Family object array of that will be returned to your Flex client.

array(10) {
  [0]=>
  object(Family)#8 (3) {
    ["father"]=>
    object(Person)#9 (2) {
      ["firstName"]=>
      string(3) "Sam"
      ["lastName"]=>
      string(9) "Blackburn"
    }
    ["mother"]=>
    object(Person)#10 (2) {
      ["firstName"]=>
      string(7) "Barbara"
      ["lastName"]=>
      string(9) "Blackburn"
    }
    ["children"]=>
    array(3) {
      [0]=>
      object(Person)#5 (2) {
        ["firstName"]=>
        string(6) "Robert"
        ["lastName"]=>
        string(9) "Blackburn"
      }
      [1]=>
      object(Person)#6 (2) {
        ["firstName"]=>
        string(4) "Lisa"
        ["lastName"]=>
        string(9) "Blackburn"
      }
      [2]=>
      object(Person)#7 (2) {
        ["firstName"]=>
        string(7) "Charles"
        ["lastName"]=>
        string(9) "Blackburn"
      }
    }
  }
  [1]=>
  object(Family)#13 (3) {
    ["father"]=>
    object(Person)#14 (2) {
      ["firstName"]=>
      string(7) "Richard"
      ["lastName"]=>
      string(5) "Weiss"
    }
    ["mother"]=>
    object(Person)#15 (2) {
      ["firstName"]=>
      string(5) "Alice"
      ["lastName"]=>
      string(5) "Weiss"
    }
    ["children"]=>
    array(2) {
      [0]=>
      object(Person)#4 (2) {
        ["firstName"]=>
        string(5) "Terry"
        ["lastName"]=>
        string(5) "Weiss"
      }
      [1]=>
      object(Person)#12 (2) {
        ["firstName"]=>
        string(4) "Mike"
        ["lastName"]=>
        string(5) "Weiss"
      }
    }
  }
  [2]=>
  object(Family)#17 (3) {
    ["father"]=>
    object(Person)#18 (2) {
      ["firstName"]=>
      string(6) "Joesph"
      ["lastName"]=>
      string(5) "Adams"
    }
    ["mother"]=>
    object(Person)#19 (2) {
      ["firstName"]=>
      string(7) "Shirley"
      ["lastName"]=>
      string(5) "Adams"
    }
    ["children"]=>
    array(1) {
      [0]=>
      object(Person)#11 (2) {
        ["firstName"]=>
        string(8) "Jonathan"
        ["lastName"]=>
        string(5) "Adams"
      }
    }
  }
  [3]=>
  object(Family)#24 (3) {
    ["father"]=>
    object(Person)#25 (2) {
      ["firstName"]=>
      string(4) "Gail"
      ["lastName"]=>
      string(6) "Hayden"
    }
    ["mother"]=>
    object(Person)#26 (2) {
      ["firstName"]=>
      string(4) "Mary"
      ["lastName"]=>
      string(6) "Hayden"
    }
    ["children"]=>
    array(4) {
      [0]=>
      object(Person)#16 (2) {
        ["firstName"]=>
        string(3) "Jim"
        ["lastName"]=>
        string(6) "Hayden"
      }
      [1]=>
      object(Person)#21 (2) {
        ["firstName"]=>
        string(5) "Carol"
        ["lastName"]=>
        string(6) "Hayden"
      }
      [2]=>
      object(Person)#22 (2) {
        ["firstName"]=>
        string(6) "Marcia"
        ["lastName"]=>
        string(6) "Hayden"
      }
      [3]=>
      object(Person)#23 (2) {
        ["firstName"]=>
        string(5) "Doris"
        ["lastName"]=>
        string(6) "Hayden"
      }
    }
  }
  [4]=>
  object(Family)#20 (3) {
    ["father"]=>
    object(Person)#28 (2) {
      ["firstName"]=>
      string(5) "Larry"
      ["lastName"]=>
      string(5) "Lyman"
    }
    ["mother"]=>
    object(Person)#29 (2) {
      ["firstName"]=>
      string(7) "Beverly"
      ["lastName"]=>
      string(5) "Lyman"
    }
    ["children"]=>
    array(0) {
    }
  }
  [5]=>
  object(Family)#31 (3) {
    ["father"]=>
    object(Person)#32 (2) {
      ["firstName"]=>
      string(5) "James"
      ["lastName"]=>
      string(7) "Raphson"
    }
    ["mother"]=>
    object(Person)#33 (2) {
      ["firstName"]=>
      string(4) "Lois"
      ["lastName"]=>
      string(7) "Raphson"
    }
    ["children"]=>
    array(1) {
      [0]=>
      object(Person)#27 (2) {
        ["firstName"]=>
        string(4) "Alan"
        ["lastName"]=>
        string(7) "Raphson"
      }
    }
  }
  [6]=>
  object(Family)#37 (3) {
    ["father"]=>
    object(Person)#38 (2) {
      ["firstName"]=>
      string(4) "Mark"
      ["lastName"]=>
      string(6) "Kendal"
    }
    ["mother"]=>
    object(Person)#39 (2) {
      ["firstName"]=>
      string(6) "Shelly"
      ["lastName"]=>
      string(6) "Kendal"
    }
    ["children"]=>
    array(3) {
      [0]=>
      object(Person)#30 (2) {
        ["firstName"]=>
        string(4) "Gene"
        ["lastName"]=>
        string(6) "Kendal"
      }
      [1]=>
      object(Person)#35 (2) {
        ["firstName"]=>
        string(4) "Earl"
        ["lastName"]=>
        string(6) "Kendal"
      }
      [2]=>
      object(Person)#36 (2) {
        ["firstName"]=>
        string(8) "Margaret"
        ["lastName"]=>
        string(6) "Kendal"
      }
    }
  }
  [7]=>
  object(Family)#43 (3) {
    ["father"]=>
    object(Person)#44 (2) {
      ["firstName"]=>
      string(4) "Jack"
      ["lastName"]=>
      string(5) "Young"
    }
    ["mother"]=>
    object(Person)#45 (2) {
      ["firstName"]=>
      string(5) "Marge"
      ["lastName"]=>
      string(5) "Young"
    }
    ["children"]=>
    array(3) {
      [0]=>
      object(Person)#34 (2) {
        ["firstName"]=>
        string(7) "Matthew"
        ["lastName"]=>
        string(5) "Young"
      }
      [1]=>
      object(Person)#41 (2) {
        ["firstName"]=>
        string(5) "Judie"
        ["lastName"]=>
        string(5) "Young"
      }
      [2]=>
      object(Person)#42 (2) {
        ["firstName"]=>
        string(6) "Harold"
        ["lastName"]=>
        string(5) "Young"
      }
    }
  }
  [8]=>
  object(Family)#51 (3) {
    ["father"]=>
    object(Person)#52 (2) {
      ["firstName"]=>
      string(4) "Bill"
      ["lastName"]=>
      string(5) "Moran"
    }
    ["mother"]=>
    object(Person)#53 (2) {
      ["firstName"]=>
      string(7) "Dorothy"
      ["lastName"]=>
      string(5) "Moran"
    }
    ["children"]=>
    array(5) {
      [0]=>
      object(Person)#40 (2) {
        ["firstName"]=>
        string(5) "Duane"
        ["lastName"]=>
        string(5) "Moran"
      }
      [1]=>
      object(Person)#47 (2) {
        ["firstName"]=>
        string(4) "Jeff"
        ["lastName"]=>
        string(5) "Moran"
      }
      [2]=>
      object(Person)#48 (2) {
        ["firstName"]=>
        string(5) "Helen"
        ["lastName"]=>
        string(5) "Moran"
      }
      [3]=>
      object(Person)#49 (2) {
        ["firstName"]=>
        string(3) "Jim"
        ["lastName"]=>
        string(6) "Fisher"
      }
      [4]=>
      object(Person)#50 (2) {
        ["firstName"]=>
        string(5) "Sally"
        ["lastName"]=>
        string(6) "Fisher"
      }
    }
  }
  [9]=>
  object(Family)#56 (3) {
    ["father"]=>
    object(Person)#57 (2) {
      ["firstName"]=>
      string(3) "Bob"
      ["lastName"]=>
      string(6) "Harris"
    }
    ["mother"]=>
    object(Person)#58 (2) {
      ["firstName"]=>
      string(7) "Sherril"
      ["lastName"]=>
      string(6) "Harris"
    }
    ["children"]=>
    array(2) {
      [0]=>
      object(Person)#46 (2) {
        ["firstName"]=>
        string(5) "Megan"
        ["lastName"]=>
        string(6) "Harris"
      }
      [1]=>
      object(Person)#55 (2) {
        ["firstName"]=>
        string(5) "Ralph"
        ["lastName"]=>
        string(6) "Harris"
      }
    }
  }
}

'FamiliesTest.php' Object Test Call Complete.

We’ve learned that our WebORB application server’s object returns are working as expected. This assures us that the data to be returned from the server to the Flex client is proper as we get ready to perform RemoteObject server to Flex client messaging.

Debugging PHP code when invoked from Flex Client

One of the most frustrating things in PHP is the complete lack of normal debugging tools. As a result, when PHP is invoked from a rich client like Flex, one must get very creative in order to tap into the PHP invocation flow and debug it. Traditional PHP use of echo or print statements do not work because any debug output is not visible because there is no output console available.

For more details on what can be done in the way of clever debugging procedures within the WebORB’s application server see Mark Plller’s blog at: ( http://www.themidnightcoders.com/blog/2008/09/debugging-php-code-when-invoked-from.html ) I think you will find this debugging article a valuable and interesting insight of lesser known debugging procedures.

Deploying the Flex Client and PHP Server Example Code

Figure 6.jpg
Figure 6. Application Server Software Deployment Hierarchy


Note: this “Families” 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 “FamiliesSource.zip” file identified at the start of this article. There are three folders of files to install. One folder is installed inside the WebORB for PHP server; the second folder is a pre-compiled version of the “Families” example; the third folder is the Flex Builder client project.

  1. “MFamilies” folder for WebORB for PHP installs in the “Services” folder   
  2. “Families” - The “Families” folder installs the root of your Web server folder as shown in Figure 6.
  3. “Families Flex Builder Source” folder

3. Copy (or move) the “MFamilies” (not “Families”) folder into the “WebORB /Services” folder as shown in Figure 6.

4. Using the “Families.sql” SQL schema file create the “Families” database, the “children” and “famil”` database tables, load the “Families” database content into their respective tables, and set the MySQL database “Grant” (login) access.

5. 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 addition somewhere in the XML file where the tags reside:

Figure 7.jpg
Figure 7. WebORB’s services-config.xml

6. Copy the “Families” 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 “Families” example before you install the example “Families” Flex Builder 3 project. From your Web browser enter the URL: “http://localhost/Families”. This exercise will tell you if your WebORB PHP Web application server is properly installed and configured. Get this working before performing step number 7.

Next, in step 7, you will establish your “Families” Flex Builder 3 project. Note in Figure 6 that the “Families” Flex client resides outside of the WebORB for PHP application server in the Web server root. For access convenience, the WebORB application server, and Flex client deployment it is desirable to deploy the “Families” flex client in the Web Server root.

The Flex Builder 3 New => Flex Project configuration insists that you build and test your project inside of WebORB’s “~/WebORB/Weborb/WEB-INF/flex” folder. Flex Builder 3 does this to the point of not alloying you to complete your project build configuration until you accept building the Flex client within the above folder path within WebORB. When creating a new Flex Builder 3 project, there’s a way around the unnecessary limitation. Inside the “FamiliesSource” zip file folder is a document called “Configure New Flex Builder 3 Project Notes.” It takes you through the steps to build a Flex client outside the confines of your WebORB application server.

7. In the “FamiliesSource” zip file folder is a folder named “Families Flex Builder Source” folder, which contains the Flex Builder 3 source files for the “Families” example. Using the instructions in the “Configure New Flex Builder 3 Project Notes” document, create your “Families” Flex Builder 3 project and install the “Families Flex Builder Source” files. In particular, from the named “Families Flex Builder Source” folder:

  1. Replace the Flex Builder 3 “index.mxml” file in the Flex Builder project with the “index.mxml” file provided in the “Families Flex Builder Source” folder.
  2. Copy the “objmaps” folder from the Families Flex Builder Source” folder to the “Families” Flex Builder project’s “src” folder. See Figure 8.

Figure 8.jpg
Figure 8. Flex Navigator view of Families Flex Project

 

About this Entry

This page contains a single entry by Pete Mackie published on March 31, 2009 6:00 AM.

New series covering Facebook application development using Adobe Flash was the previous entry in this blog.

jQuery Quickie - Broken Images is the next entry in this blog.

Find content using the provided navigation or look in the archives to find all content.

Authors

Archives

This content archive is licensed under a Creative Commons License.