Using AMFPHP (Open Source Flash Development) Part 6

Displaying value objects in Flex

Although you have created the ProductVO on the server, you now need to make it in ActionScript 3 for the server object to be mapped to. Right-click the product project, and select New > ActionScript File. Name the file ProductVO, and click Finish to see the new file. Copy the following code into the file to finish creating the class:

tmp9d3-21_thumb[2][2]

The class is syntactically equivalent to the PHP of the same name. The variable names are the same and need to be in the same case to work properly. There are two unique ActionScript 3 meta tags in this class. The first is bindable, which makes the class work like the bindable tag that you used in the previous example. The second tag is the RemoteClass tag, which defines what the remote server will call when the object comes in. It is mandatory that this tag and the $_explicitType value in PHP are the same.

Creating the application

To consume the ProductVO value object, you will need to create a new Flex application in the product project. Create a new MXML application by right-clicking the product folder and selecting New > MXML Application. Name the new file productClassmap as you did when you created productUpdate. mxml. Remember to right-click productClassmap in the Navigator panel and select Set as Default Application to run it as the default application. The following is the code for productClassmap.mxml. For this example, I have removed the method calls and buttons for updating, deleting, and adding new products. This should make the tutorial simpler. At the end of the section, I will discuss how to implement those features. Let’s look at the fully implemented ProductClassmap.mxml file:


tmp9d3-22

 

 

 

tmp9d3-23

When you run the application, it should look similar to the following screenshot.

tmp9d3-24

So, what has changed in order to implement class mapping? For one, you were able to get rid of a lot of code in order to get the data into the application. But let’s go from top to bottom to see what has changed. For starters, the RemoteObject now connects to ProductService getProductVO when the application starts. The DataGrid tag has been updated to have a bound DataProvider called DP, which will be used to populate the DataGrid in the getProductsHandler method. Also, in the DataGrid columns definition, you have changed the names of the dataFields to match the naming convention of the ProductsVO.as class file rather than the table names on the server. Inside the Script section of code, you start with three new imports (ProductVO, ArrayCollection, and ArrayUtil), which will be used later to display the returned data. There are now two Bindable objects: the first is the dp DataProvider that was also bound to the DataGrid, and the second is product, which will be a single instance of ProductVO. The faultHandler is the same as before utilizing the alert function. GetProductsHandler has been changed to convert the PHP array into an ArrayCollection. In the previous example, you already had an ArrayCollection because of AMFPHP’s built-in casting of result sets. Once the result set is converted into an ArrayCollection, you update the DataProvider for the DataGrid. This will make the DataGrid populated with data. The changeHandler for the DataGrid has a subtle update that completes the class mapping. This is the part where we take the selected element in the ArrayCollection and map it to a ProductVO in Flex. The variable product is now an instance of ProductVO. Because of binding product to the TextInput, the data is now displayed on the right side of the user interface.

It is also possible to use class mapping from the Flash client to the server. To do this, you can create an array of productVOs and send them to the server. Then on the server you cast the array as a ProductVO. Sending class mapping back to the server does not have as many benefits as server to client. In closing, you can add the addProduct, updateProduct, and removeProduct methods back into this example easily because all the code will be the same as the previous example.

In this section, you have learned the basics of how to easily get complex objects back into ActionScript. Class mapping can greatly improve the rate at which you can produce functional code, and it aids in forcing the separation of the presentation tier from the data provider. Next, I will cover how to fix issues when you inevitably run into them.

Debugging

The following steps should allow you to figure out any issue with your AMFPHP application. Corrupt PHP installations, service errors, and client-side ActionScript errors are the three main areas you should focus on when trying to debug an AMFPHP application. By narrowing your efforts systematically through each of these areas, you will be able to quickly resolve issues and not waste time tracking something that is not broken.

Narrowing it down

If you follow these steps and are still confused, use the AMFPHP mailing list or forums hosted on SourceForge (http://sourceforge.net/projects/amfphp/), and review the examples. Ifyou are able to get to step 3 with a simple HelloWorld.php example, I can assure you that AMFPHP is working properly. When you post to the mailing list or forum, please let us know how far you got in this process before you ran into issues.

1.  With a web browser, go to the remoting URL: http://localhost/amfphp/gateway.php.

The response should be as follows: amfphp and this gateway are installed correctly. etc…..

If this is not the case, it is a corrupt PHP installation.

2.  With a web browser, go to the URL of the service that is failing: http://localhost/amfphp/ services/HelloWorld.php. If there is blank response, the PHP interpreter was able to compile the class. If not, it is a service error.

3.   Test the same service through the AMFPHP Service Browser. Pass the parameters to the method, and you should get the expected result. If not, look into the PHP class to see why it is not handling your input, because you have a service error.

4.  Use a proxy client such as Charles (http://www.xk72.com/charles/) or Service Capture (http://kevinlangdon.com/serviceCapture/) so that you can see all the traffic between

Flash Player and the services. Make sure the requested data is being sent as you anticipated and that the result set is being returned as anticipated. This shows that the inputs and outputs are correct!

If you get through these four steps but you are still having problems, your issues are in the ActionScript. Reviewyour code to make sure your inputs    and outputs are correct. This is  a good  time to hard-code the input to the service call and trace all  data that is returned from the  service. For example, rather than the following dynamic code:

tmp9d3-25_thumb[2][2]

use static text to make the call:

tmp9d3-26_thumb[2][2]

Dealing with a corrupt PHP installation

Your services and Flash/Flex will not work if the PHP installation is corrupt or missing modules. The PHP requirements for the installation of AMFPHP are a minimal PHP install. However, PHP installations and upgrades can be botched, which inevitably stops your services. If PHP is not working properly, you will most commonly receive a 500 error when it tries to connect to one of the services. This is because PHP had a premature end-of-script error.

Try the following steps to debug the installation:

1.    Check to make sure you have a current version of PHP installed. As of AMFPHP version 2.0, there is no longer support for PHP 4.4.*, and PHP 4 was discontinued at the end of 2007, so you will need to upgrade to PHP 5 for all future releases.

2.    Check your version and modules installed by uploading a PHP info page into your web server’s document root. A PHP info page is simply a PHP file with the following code:

<?php

phpinfo();

?>

Open a web browser, and go to the uploaded file. You should see a similar page as the following screenshot with the version of PHP at the top.

tmp9d3-27

A PHP info page is critical for debugging the PHP installation and also your services. When you browse to your PHP info page, validate that it works. If it does, PHP is running but may not be configured right. If it does not, fix the PHP errors that the server throws.

3.    The most common PHP installation errors are improper permissions set on folders/directories that PHP uses. AMFPHP requires the ability to create a session variable and access the tmp directory. To debug this issue, you will want to look at your PHP error logs for messages pertaining to why the script ended prematurely.

4.    Use the HelloWorld example service to see whether AMFPHP is really not working or whether your services are not working. Refer to the installation process where you uploaded the HelloWorld.php file into the services directory, then went to the file in a web browser, and finally opened the service in AMFPHP’s Service Browser. Ifyou get the expected response from each test, you should start looking at your services.

Dealing with service errors

First accept that your code could have bugs under certain conditions. Old versions get uploaded, and services can stop working when administrators upgrade PHP without all the previous modules. With this in mind, it is critical to be able to isolate issues quickly.

1.    It is best to debug PHP classes with PHP tools. Stop playing with AMFPHP, the browser, and your proxy tool, and get connected to the server!

2.    When working on PHP, make sure you have error logging enabled. Add the ini_set values to the top of your class file if you do not have server-wide logging. Follow these steps to add logging to your PHP installation.

Unless you have your own "dedicated" server, you are most probably sharing the same hardware with a few thousand other “virtual” domains. For this reason, it is all too natural that your hosting provider will deny you access to the systemwide php.ini file. Whatever value you enter there is going to affect all the virtual domains running on that machine! Production server administers usually have a similar view to changing php.ini values.

3.    If you are not able to edit the php.ini file, you may still be able to get error logging working. In the gateway.php file located in your amfphp directory, add the following code right after the <?php at the start of the file:

tmp9d3-28_thumb[2][2]

4. You can then use a browser to go to the gateway.php page and in most cases see the error in the browser. If the gateway.php resolves and you still get errors when you call a service, you will need to use a debugging proxy in order to view the service errors. This may or may not work properly depending on your PHP installation because your administrator could disable your ability to do this.

For more information on PHP debugging, walk through the great presentation at http:// talks.php.net/show/debugging/.

5.    Run the class in your services folder directly from a web browser by typing the entire path into the browser (http://localhost/amfphp/services/YourService.php). You should not receive any errors if the classes can be compiled by the PHP interpreter. If you do see errors, resolve them!

6.    If you do not see any errors, you are dealing with a runtime error. Open the class file, and add an instantiation of the object to the bottom of the class in the same file. Call the method that failed in AMFPHP with the exact parameters you were trying to send to the remoting method from the AMFPHP Service Browser or your Flash application. In the following example, I instantiate the HelloWorld class and call the method say with the same data that you were sending from Flash in the examples. Adding the instantiation of the class will allow you to use a browser and go directly to the class URL to test the file. This does break AMFPHP, so make sure you remove it when you are done debugging.

tmp9d3-29_thumb[2][2]

I highly recommend you use some kind of IDE that allows you to debug your PHP code quickly. I enjoy using the Eclipse PDT project (http://www.zend.com/en/community/pdt) because I can use one IDE for Flex, Flash, and PHP development. This toolkit has a debugger that makes the world a better place!

In the end, your services are just PHP classes. AMFPHP cannot help you write better PHP code. PHP best practices such as unit testing and development environments will only increase your chance of success.

Dealing with ActionScript errors

If you are looking at ActionScript, I assume you have made it through the first four steps of the “Narrowing it down” section and are still having issues. At this point, you are sure your services work fine in AMFPHP. ActionScript errors can be tricky to find. Little changes can create malformed data as inputs to the remote service such as removing bindings or a space before one of your dynamic variables. It is also easy to actually be receiving data from your service call but not handling it or displaying it. Your data can be returned in the ResultEvent, but you may have unknowingly nested the data.

I always recommend having a dummy project that just has service calls to your remote methods handy for testing your services so that you are not lost in your own code. If you are using MVC, it is easy to place trace statements in your inputs and responses in your service locator.

1.    Make sure you have a NetStatusEvent handler and a SecurityErrorEvent handler defined for the service you are calling. If you are getting errors, you can find them in these handlers.

2.    Revert to a HelloWorld example. It is amazing how many people still use the wrong remoting URL or forget the www or https. Remember that your browser must be on the same URL as the NetConnection URL, or your service will not work.

3.    Hard-code the input parameters that you used in testing your services into the service call. Also, trace the inputs at the service call to make sure they are what you meant to send. Are they the same? If this works, you need to track all your method calls and figure out why your inputs are corrupt.

4.    Place a trace statement in the Responder method to make sure that it is being called when the client gets data back. If it is not, double-check that you have the right method name specified as the responder for your NetConnection.

5.    If the method is being called, trace all the data that is being returned. Sometimes your service may not have been implemented in the way that you thought you would get the data back. Iterate through the returned object until you find the right data. You may need to update your return value in your service to return the data in the expected format.

AMFPHP without question is one of the most efficient ways to send data to and from the server. I hope that these examples show that it is quick and easy from a developer perspective. Like all technologies and like most open source projects, AMFPHP is always being updated for additional functionality and efficiencies. I encourage you to visit http://www.amfphp.net and get involved in the mailing lists and forums available for support. Ifyou are like me and fall in love with this framework, I encourage you to download the source code and start aiding this great community.

The AMFPHP project would not have been possible without the contributions of the following people:

■    Alessandro Crugnola (documentation)

■    Christophe Herreman (MethodTable class)

■    Cowen (documentation and programming on 0.9b)

■    Justin Watkins (most of the programming on 1.0)

■    Patrick Mineault (programming and documentation on 1.0)

■    Thomas Craigen (beta testing and documentation on 0.9b & 1)

■    Wolfgang Hamann (original AMF reverse engineering)

Next post:

Previous post: