Home  >  

Photo Gallery Mate Framework, With Photo Caching

Author photo
February 1, 2010 | | Comments (9)
AddThis Social Bookmark Button

I have been developing Adobe Flex-based RIA applications for nearly three years. My prominent need has been for capable RIA photo galleries. I observed over time that most Flex-based example photo galleries resourced photos—either locally or remotely—from photo files stashed in folders or folder hierarchy. This approach in rendering photos in a gallery is slow and fraught with photo rendering delays, to say nothing of the difficulty of managing and keeping all the photos located and in order. Simply put, rendering photos from photo files in a folder, or folders, makes it difficult to manage expansion of photo publishing, and yawn, only provides slow and flickering photo gallery rendering.

I started developing Flex-based photo galleries, with the photos resourced from a database, a couple of years ago. Some of this development effort was easy. Other parts were more difficult, such as determining the structure on the photo database, identifying what type and level of photo metadata should be provided, and figuring out how to rapidly return photos—based on photo metadata search data—from the Web application server to the Flex photo gallery client.

My photo gallery development endeavors have taught me a trick or two, plus created some code and some work-arounds to gnawing photo display problems. One work-around requires a bit of photo I/O chicanery, which I’ll get to later.

I decided to write this article to share my photo gallery development experiences. To best do this, I needed a photo gallery example client/server solution especially for my article. The example client/server code package name is SQGallery. The photo repository database name is SQPhoto. They demonstrate some of the techniques I have learned—some were easy while others took noticeable time and effort. The example solution was designed to discuss the code and how it works, while not concentrating on a work of art from a user experience perspective.

I have used the Cairngorm Flex Framework for photo gallery deployments over the past couple of years. Recently, I decided to give the Maté Flex Framework ( ) a try. I like what I found here and plan to stick with the Maté Flex Framework (Maté) for a while. This article also shares with you what I’ve come up with as my first prototype Maté Framework photo gallery.


On the word SQPhoto:
The word SQPhoto is used in this article in three different ways:
  1. SQPhoto (italics) for the MySQL database server photo repository utilizing a photos database table.
  2. SQPhoto for the name of WebORB for PHP Services server-side folder and broadly the PHP code contained within the WebORB application server Services/SQPhoto folder.
  3. SQPhoto for the WebORB for PHP class—when instantiated, the SQPhoto object.

Overview

You can run the SQGallery RIA example client, from your browser using the URL: http://gallery.seaquest.com
Right-click within the SQGallery browser application window, and select View Source from the context menu to view both the Flex client and PHP server source code.
You may want to download both the Flex client and PHP server code while in the View Source window—see the lower left-hand corner for the source code download link.

This photo gallery article and example code deal with server-to-client transfers of photo object arrays. If server-to-client transfers of array of objects are new concepts for you, you might want to check on my two past articles on this topic:

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)
PHP (workstation, not server, deployment preferred)
Web Server (workstation, not server, deployment preferred)
Web Application Server (workstation, not server, deployment preferred)
Web Debugging Proxy (Optional tool. Use is highly recommended)
Example files
  • SQGallery.zip (ZIP, 152 KB)
  • Example Photos Database.zip (ZIP, 5.2 MB) Optionally deployable to your local workstation photo MySQL database repository. Alternately, deploy your own photos to the database repository. "How to" post your photos to the photo database instructions plus PHP posting scripts are contained in the Example Photos Database download.

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 )

Alternately you can deploy XAMPP ( http://www.apachefriends.org/en/xampp.html ). The XAMPP package is an easy to install Apache distribution containing MySQL, PHP and Perl. XAMPP is really very easy to install and use—just download, extract and start.

Note: Apple’s OS X Snow Leopard 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. Also you'll need to install the MySQL ( http://dev.mysql.com/downloads ) database server. Download instructions of installation details follow later in this article.


What The Photo Gallery Client Provides

The SQGallery RIA client provides working examples of:

  • Four separate views of photos and photo metadata, plus a fifth view as a help page. The five views are:
    1. Get Photos
    2. Browse Photos
    3. Basic Photo Search
    4. Advanced Photo Search
    5. Search Help
  • Gallery rendering of previously cached photos.

  • Example of a Flex client design and development using the Maté Framework.

  • Use of a Presentation Model patterns for content management for each of the photo views—discussed further at the end of this section under the heading of Maté Views Using a Supporting Presentation Model Pattern.

  • Multiple business logic examples of PHP application server side code. The PHP server-side code provides how-to examples for the selection of photos to render in the first two respective SQGallery photo gallery views.

Following is a brief summary of the SQGallery photo gallery views, how to activate the views, and what they show:

Get Photos
This view renders a range of photos at application startup with no required user intervention. You can then view other ranges of photos by selecting the starting photo number from the Select Photo ID ComboBox and then clicking on the Get Photos button.

Browse Photos
The purpose of this code is to provide example PHP server-side code on how to return a paged range of database records from the application server—in our case an array of SQPhotoVO objects with each object in the requested page containing a photo and related photo metadata.

Basic Photo Search
Render photos in this gallery view based on Words and Exclude Words metadata to search on. Some search parameters are preloaded for you starting photo metadata search conveniences. For further details about photo metadata searching, see the Photo Search Help page in the Search Help view.

Advanced Photo Search
The view provides the same search capability with additional search functions. Provided are: Search Fields: All Fields, Keywords only, or Caption only, and search Match: Any Word, All Words, or Phrases. For further details about advanced photo metadata searching, see the Photo Search Help page in the Search Help view.

Note: We will review the photo metadata server-side PHP to MySQL database search code in the section The Server Side PHP Code.

Search Help
This view provides three help windows navigated via three buttons. Click on the Keywords or Captions buttons for listings of metadata entries to search on using the Basic Photo Search and Advanced Photo Search views. The third button, Photo Search Help, provides a primer on photo metadata search techniques.

The Flex client design and development using the Maté Framework is covered in the section The SQGallery Photo Gallery Maté Framework.

Gallery photo rendering is then discussed in the section The Benefit of Photo Gallery Caching and How It Works.

Finally we’ll discuss the multiple business logic examples of PHP application server-side code in the section The Server Side PHP Code.

Maté Views Using a Supporting Presentation Model Pattern

The idea of Presentation Model patterns to mange each gallery View content—while not a required design concept—is a worthy design consideration. My respective gallery Views knows about the Presentation Model patterns, but the Presentation Model patterns do not know about the Views. The Presentation Models patterns’ purpose is to provide content to the View, when requested, and to fire Maté events to request a new set of photos for a given view. This pattern notion provides a convenient way to change the View’s data resource without affecting the view code. More information about how and why to use View Presentation Managers can be found here: ( http://code.google.com/p/mate-examples/wiki/PresentationModel ).

Three examples of Maté Flex-based applications that use View Presentation Managers patterns are:

The above Cafe Townsend example is a modification of the popular Cairngorm example code ( http://cairngormdocs.org/blog/?p=19 ) to use Mate Framework.
This example is a good Maté mastery-starting place for those of you who are familiar with deploying RIA clients using the Cairngorm Framework.

The Photo Gallery Maté Framework

There’s a lot for me to say about both the client and server side of the SQGallery photo gallery solution. This article starts to turn into a book if I also start writing about Maté Flex and how to use it. I’m going to skip those details by suggesting some references where you can start mastering and applying Maté for your framework development needs. The first InsideRIA reference provides an excellent representation of Maté and how it works. Start there for your basic Maté understanding.

My experience mastering use of the Mate Framework

I’ve used the Cairngorm Flex Framework for development of a few Flex-based RIA applications. I fully understand the Cairngorm, but I had considerable initial trouble understanding how and what I needed to develop in the way of AS 3 classes. My development productivity did get better over time. There was always this gnawing feeling, “am I taking the right Cairngorm development approach?” Consequently my development pace seemed sluggish, at best.

I found mastery and application of using the Maté Flex Framework to happen much more quickly than with Cairngorm. I can suggest a way for you to get started with applying the Maté Framework for your RIA client development. What worked best for me was to load most of the Maté example applications ( http://mate.asfusion.com/page/examples ) into Flex Builder to view their respective operations. Use and application of Maté became obvious once I performed this exercise.

My years of experience are as an imperative programmer / developer (ActionScript, Java, C, et al.) and not a declarative programmer (mxml, xslt, xml, et al.). I’ll take writing ActionScript code over writing mxml declarative statements any day. Maté is very mxml-centric, making a programmer like me longing for writing imperative programming statements.

I was initially uncomfortable with developing using Maté mxml tags. I quickly got over this barrier once I mastered the functionality of the Maté mxml tags and how easy they are to apply. I, rather quickly, became very productive core application wise. My improved programming productivity was most pleasing.

My Maté Framework Debugging Tool

Feedback from my developer peers was that debugging the framework could sometimes be a problem with a good share of the code being Maté mxml tags. Where can you put the Flex debugger breakpoints? I did find this to be the case a couple of times when I killed the operation of my code and had to really work hard to get my code operational again.

Secondarily, I sometimes felt uncomfortable with the groups of Maté handler tags, as shown in Listing 1, (from MainEventMap.mxml) where I could not view the parameters being passed from Maté tag to tag. In this case, I wanted to view the ImageLoadCompleteEvent event’s viewState and photoArray parameters being passed to the PhotoManager class via the first MethodInvoker Maté tag in Listing 1.

<!-- ImageLoadCompleteEvent.IMAGE_LOAD_COMPLETE -->
<EventHandlers type="{ImageLoadCompleteEvent.IMAGE_LOAD_COMPLETE}" debug="false">
	<InlineInvoker method="showEventParams" arguments="{ [event.viewState, event.photoArray] }" />
	<MethodInvoker generator="{ PhotoManager }" method="renderPhotoArrayToCollection" arguments="{[event.viewState, event.photoArray]}"/>
   <MethodInvoker generator="{ ImageLoaderManager }" method="clearLoaderManagerProperties" />
</EventHandlers>

Listing 1: ImageLoadCompleteEvent Event Handler

My debugging solution, from in Listing 1, is to place an <InlineInvoker> Maté tag which calls an AS 3 method in the MainEventMap.mxml module as shown in Listing 2 per the showEventParams AS 3 method. What I do is run to run the Flex Builder project in debug mode with a debug breakpoint in the trace statement of the showEventParams method. I then get a complete Flex Builder debugger view of the event.viewState and event.photoArray, property values.

// These two ActionScript 3 methods are used for Maté tag debugging calls
// by using <InlineInvoker ....... /> Maté tags to call these two methods
private function test (result Object:*):void {
   trace("test(): "+resultObject);
}
		
private function showEventParams(viewState:int, photoArray:Array):void {
   trace("showEventParams (): "+viewState+", "+photoArray);
}

Listing 2: Debugging method calls from Maté InlineInvokers tags

The above is a simple-to-use Maté MXML tag debugging tool, which is invaluable when you need it. To say nothing about the value per mastery of Maté tag operations by viewing their attribute property values.

You’ll find other debugging <InlineInvoker> Maté tags in the SQGallery example code, which are commented out until they are needed for debugging and/or operational analysis.

SQGallery Block Diagram and Summary Code Review

Figure 1 provides a roadmap for reviewing the SQGallery Flex Builder project code. Following the block diagram are brief descriptions of the numbered elements in the block diagram.

SQGallery_Block_Diagram.jpg
Figure 1: SQGallery Maté Client / Server Block Diagram

As you navigate through the following steps for photo gallery requesting and rendering, use the Tags section of the Maté Document page (Maté Flex Framework) URL above to identify the respective Maté functionality.

  1. One of the Views dispatches a user’s event through the Presentation Models using a Maté Dispatcher tag that bubbles up (bubbles=true).
    • Path: com.seaquest.sqgallery.ui.presenters
    • Modules: AdvancedSearchPresentationModel.as, BasicSearchPresentationModel.as, BrowsePhotosPresentationModel.as, GetPhotosPresentationModel.as, HelpPresentationModel.as, MainViewPresentationModel.as
  2. The Event Buss event generators are:
    • Path: com.seaquest.sqgallery.events
    • Modules: ChangeViewEvent.as, GetPhotoDatabaseRecordCount.as, GetPhotosEvent.as, GetPhotosMetadataEvent.as, GetSQPhotoDBRecordCount.as, ImageLoadCompleteEvent.as
  3. The event arrives to an EvantHandlers block in the Event Map that is registered to listen to this event type.
    • Path: com.seaquest.sqgallery.maps
    • Modules: : MainEventMap.mxml
    • The module’s <EventHandlers>....</EventHandlers> MXML tag pairs identify the event handlers
  4. Inside the EventHandlers, a list of actions is executed in order. In this case a service call is made via a Maté ServiceInvolker.
    • Path: com.seaquest.sqgallery.maps
    • Modules: MainEventMap.mxml
    • The module’s <RemoteObjectInvoker>....</RemoteObjectInvoke> MXML tag pairs, starting at line #84, serve as the AS 3 RemoteObject ServiceInvolker.
  5. The ServiceInvolker performs a Flex AS 3 RemoteObject request to the WebORB for PHP application server. WebORB for PHP application server returns an array of the requested SQPhoto objects back to the Maté EventHandlers as an Adobe Action Message Format 3 (AMF 3) data steam. (AMF 3 specification: http://opensource.adobe.com/wiki/display/blazeds/Developer+Documentation )
    • Path: com.seaquest.sqgallery.maps
    • Modules: Module: MainEventMap.mxml
  6. The Image Loader class performs a Flex AS 3 Loader.LoadBytes object method of the photo data for each photo in the returned AS 3 RemoteObject array. The actual photo data, within each SQPhoto object, is in the format of Adobe AS 3 ByteArray data stream.
    • Path: com.seaquest.sqgallery.model.image
    • Modules: ImageLoader.as, ImageLoaderManager.as
    • Operation of the ImageLoader photo cache modules are discussed in more details in the section titled: The Benefit of Photo Gallery Caching and How It Works
  7. The SQGallery client ModelManager is notified that all photos are ready for rendering via a data change notice using a Maté event handler. This action occurs after the Photo Cache (a.k.a. ImageLoader class) AS 3 Loader.LoadBytes processing is complete for all the photos on the returned photo array of objects.
    • Path: com.seaquest.sqgallery.model.manager
    • Modules: PhotoManager.as
  8. Each respective Maté PropertyInjectors MXML tag monitors for photo / photo metadata data changes and pass any or all data changes the appropriate View module PresentationModel module.
    • Path: com.seaquest.sqgallery.maps
    • Modules: MainEventMap.mxml
    • The module’s <Injectors>....</Injectors> MXML tag pairs, starting at line #188, are the Maté PropertyInjectors
  9. The PresentationModel—one for each if the five Views—receives the data from its Maté PropertyInjector tags.
    • Path: com.seaquest.sqgallery.ui.presenters
    • Modules: AdvancedSearchPresentationModel.as, BasicSearchPresentationModel.as, BrowsePhotosPresentationModel.as, GetPhotosPresentationModel.as, HelpPresentationModel.as, MainViewPresentationModel.as
  10. Each View’s model property is bound to its respective PresentationModel. The changed data is rendered in the appropriate View.
    • Path: com.seaquest.sqgallery.ui.views
    • Modules: AdvancedSearch.mxml, BasicSearch.mxml, BrowsePhotos.mxml, GetPhotos.mxml, Help.mxml, MainView.mxml
  11. The photos are rendered in the View by the PhotoRenderer module displays (not shown in the above SQGallery block diagram).
    • Path: com.seaquest.sqgallery.ui.renderers
    • Modules: PhotoRenderer.mxml
    • Note: the header region of PhotoRenderer.mxml describes how this module works and the source of the ideas for this module.

The Benefit of Photo Caching And How It Works

RIA Client Photo Caching Benefit

The principle benefit of the photo caching is the elimination of photo gallery render flickering when scrolling through a collection of photos in a list. The normal operation is to activate photos for display when they arrive in the viewing flex component container—thus causing a flicker delay. Then the photos are removed once they pass out of the Flex component container’s view.

I designed a conceptually simple but elegant photo-caching pair of ActionScript 3 (AS 3) classes to solve the photo render flicker when scrolling photos in a component container. You’ll observe no SQGallery photo gallery flicker when rapidly scrolling any of the four views in SQGallery RIA client.

How the Photo Caching Works

Here we’ll explore the techniques used to cache and subsequently render photos using the PHP server and Flex client in the SQGallery RIA application.

When requested by the user, the WebORB for PHP application server returns an array photo objects with each array element containing an object of type SQPhoto as shown in Listing 3. The actual photo data—not the photo metadata—is returned from the WebORB for PHP application server in the “photoBA” object property as an array of bytes (AS 3 ByteArray). The photo metadata is transferred in the “keywords” and “caption” SQPhoto object properties as AS 3 type String.

class SQPhoto {
    var $photoBA;    # Photo data as AS3 ByteArray data type
    var $photoID;
    var $photoFilename;
    var $photoSize;
    var $photoWidth;
    var $photoHeight;
    var $photoFormat;
    var $keywords;
    var $caption;
 	
    function __construct() {}
  }

Listing 3: The PHP Server Side SQPhoto Class

The Flex application maps the received array of SQPhoto objects each into an array of SQPhotoVO objects, as shown in Listing 4. Note that the “photoBA” property in the SQPhoto class is replaced with the “imageLoader” property as a data type of AS 3 Loader object in the SQPhotoVO class. This AS 3 ByteArray to AS 3 Loader transition process occurs within the SQGallery ImageLoaderManager and ImageManager photo caching classes.

package com.seaquest.sqgallery.model.vos {
    import flash.display.Loader;
 
    [Bindable]
    public class SQPhotoVO {
        public var imageLoader:Loader;// Photo data as AS3 Loader data type
        public var photoID:uint;
        public var photoFilename:String;
        public var photoSize:uint;
        public var photoWidth:uint;
        public var photoHeight:uint;
        public var photoFormat:String;
        public var keywords:String;
        public var caption:String;
     }
}

Listing 4: The Flex Client Side SQPhotoVO Class

This AS 3 ByteArray to Loader translation occurs as part of the Flex client-side photo caching. Next I will discuss the code that performs in photo caching. This code is in the AS classes “ImageLoaderManger” and “ImageLoader” classes located in the SQGallery Flex project source package data path of “com.seaquest.sqgallery.model.image”.

For these received photos to render and display, we must instantiate an AS 3 Loader class and then load each photo’s ByteArray data using a AS 3 “Loader.loadbytes()” class.method respectively, using one “Loader” class instantiation for each remotely received photo from the PHP server’s returned array of SQPhoto objects.

Our need is to complete the caching of each photo’s ByteArray data using AS 3 Loader classes before the photos are rendered in one of the respective views.

Review of the “ImageLoaderManger” and “ImageLoader” photo cache classes is best done from a block diagram, which follows.

Alt Text
Figrue 2: ImageLoader (Photo Cache) Workflow
  1. The <RemoteObjectInvoker> Maté ServiceInvolker tag, which contains a <resultHandlers> inner tag, is called when the array of SQPhoto objects is received (AMF 3 serialized AS 3 RemoteObject) from the WebORB for PHP application server. The <resultHandlers> inner tag then calls the ImageLoaderManager object fireImageLoaders method.
    • Path: com.seaquest.sqgallery.maps
    • Module: MainEventMap.mxml
    • Maté Tags: font face="Courier New, Courier, monospace"><RemoteObjectInvoker> and font face="Courier New, Courier, monospace"><resultHandlers>,/font>, lines #84 thought #95.
    • Note: the parameter call to the ImageLoaderManager object fireImageLoaders method also identifies which view is associated with the return array of SQPhoto objects.
  2. The ImageLoaderManager object fireImageLoaders method instantiates one ImageLoader object for each SQPhoto object array. Each ImageLoader object instantiated shares a common static property loadCounter count of the number of ImageLoader objects instantiated.
    • Path: com.seaquest.sqgallery.model.image
    • Module: ImageLoaderManager.as
  3. The property loadCounter count is decremented each time on of the instantiated ImageLoader object completes its AS 3 “Loader.loadbytes()” operation. All AS 3 Loader operations are complete when the static property loadCounter count has decremented to zero.
    • Path: com.seaquest.sqgallery.model.image
    • Module: ImageLoader.as, lines #53 to #61
  4. The last ImageLoader object to complete fires an ImageLoadCompleteEvent event.
    • Path: com.seaquest.sqgallery.model.image
    • Module: ImageLoader.as, line #59
  5. A Maté EventHandler captures our ImageLoadCompleteEvent event. The EventHandler then calls the SQGallery PhotoManager class for subsequent rendering in the appropriate view.
    • Path: com.seaquest.sqgallery.maps
    • Module: MainEventMap.mxml, lines #183 an #184

By now, your question might be why not just instantiate the ImageLoader objects, one a time? Then when the AS 3 Loader operation is complete for the last instantiated ImageLoader object assume that all AS 3 Loader operations are complete. The answer is that the completion order of the AS 3 Loader operations for each SQPhoto object, in the array, is indeterminate. Loader object completion does not follow the order in which they were instantiated. The last object instantiated may very well be the first one to complete its AS 3 Loader operation.

So how do I know this be a fact? I learned it the hard way by watching the operation of the ImageLoader objects using the Flex Builder debugging services.


The Server Side PHP Code

A good share of the SQGallery RIA client/server solution occurs on the WebORB for PHP server side. The photo metadata search results actions actually occur within the MySQL database server engine. The PHP classes first set up the search criteria to drive the photo metadata searching. Next I’ll briefly discuss these operations and guide you on how to best master operation of how the WebORB for PHP Services PHP classes operate.

MySQL Photo Repository

Listing 5 shows the SQL schema for the SQPhoto database photos table. The actual photo byte array data resides in the photo field as a mediumblob data type. The remaining files in the photos table contain the supporting photo metadata. The SQGallery Flex client does not use all of the photo metadata. For example, I do not display the photo size, width, height, or format. You can extend the code as appropriate for your needs. By viewing the code, you can see how I generate and transfer the photo metadata from the WebORB server to the SQGallery Flex client.

CREATE TABLE `photos` (
   `photoID` int(4) NOT NULL,
   `photoFilename` varchar(26) NOT NULL,
   `photo` mediumblob NOT NULL,
   `photoSize` int (4) unsigned default NULL,
   `photoWidth` smallint(5) unsigned default NULL,
   `photoHeight` smallint(5) unsigned default NULL,
   `photoFormat` varchar(12) default NULL,
   `keywords` text,
   `caption` text,
   UNIQUE KEY `photoID` (`photoID`),
   FULLTEXT KEY `keywords` (`keywords`),
   FULLTEXT KEY `caption` (`caption`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Listing 5: SQPhoto.sql Database Schema File

SQPhoto metadata searching builds on the MySQL database server text search functions, which index the text in defined database fields. Therefore the MySQL database server partially defines the search capability. For a basic search, Search Fields defaults to all fields and the Match field to any word. Also, a search using exclude words requires the match mode of any word. WebORB’s PHP Service classes automatically generate this setting. You can use commas, spaces or both as delimiters for the search terms and optional exclude words you enter.

One key limitation to note: searching on words less than four characters long does not produce results.

Notice the two FullText SQL keys in Listing 5. These entries tell MySQL to build searchable indexed keys of the text contained in both the keywords and caption fields of the photos database table.

For more information on MySQL‘s query statement syntax for full-text searching, I suggest that you read section 11.8, Full-Text Search Functions, in the MySQL 5.1 Reference Manual ( http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.htm ). Study the syntax and examples in:

  • 11.8. Full-Text Search Functions
    • 11.8.1. Natural Language Full-Text Searches
    • 11.8.2. Boolean Full-Text Searches
    • 11.8.3. Full-Text Searches with Query Expansion
    • 11.8.4. Full-Text Stop words
    • 11.8.5. Full-Text Restrictions
    • 11.8.6. Fine-Tuning MySQL Full-Text Search

But if you only want to know about the processes to transfer photos from the server to the client, you can certainly skip any study of MySQL full-text searching.

Debugging and Evaluating WebORB Services SQPhoto PHP Classes

In this section, I’ll discuss the server-side SQPhoto PHP classes that resides in the WebORB Services folder. I always provide PHP test modules for my PHP classes. I discuss my reasons for doing this in the article, “AMF3 PHP Server Objects to Flex Client Object Relational Mapping” ( http://www.insideria.com/2008/04/amf3-php-server-objects-to-fle.html ), in the section titled RIA Debugging Tips.

Pay particular attention to the article’s discussion of using the PHP command line interface (CLI) scripting engine to run stand-alone PHP test scripts against my WebORB Services PHP Service classes.

An Overview of the SQPhoto PHP Classes

In WebORB’s Services/SQPhotos folder, you will find five PHP classes supporting the server side of the SQPhoto RIA solution:

  1. DBAccess: Shared MySQL database access code used by the GetSQPhotos and SearchSQPhotos classes.

  2. GetSQPhotos: Performs SQL SELECT queries on the photos table of the MySQL SQPhoto database, and packages an array of SQPhoto objects. Then the WebORB application server performs AS 3 RemoteObject data serialization of the SQPhoto object array and remote transfer to the SQGallery Flex client.

  3. SearchSQPhotos: Provides two object methods for basic and advanced MySQL full-text searching of the keyword and caption photo metadata in the photos table. As the GetSQPhotos object, the WebORB application server then performs data serialization of the SQPhoto object array and remote transfer to the SQGallery Flex client.

  4. SearchQuery: Search query generation class supporting the SearchSQPhotos class.

  5. SQPhoto: Object property definition class used by the GetSQPhotos and SearchSQPhotos classes to return photo and photo metadata to the Flex client as serialized data.

The two core I/O PHP classes GetSQPhotos, with one method, and SearchSQPhotos, with two methods, provide the base code for reading and packaging the photos into an array of SQPhoto objects for return to the Flex client. Typically I would have placed all three methods in one PHP class, but thought it best to split out the functionality for code review and analysis. GetSQPhotos responds to a simple photo request, while SearchSQPhotos allows for slightly more involved photo searching.

The WebORB application server serializes the array of photos into an AMF3 streaming format.

GetSQPhotos PHP Class

I typically open my database connection at PHP object instantiation time; see the __construct method. First, I need to have a database connection already running when I call a method to do database I/O. That way, if the database connection fails for any reason, I know about it before performing any I/O work in the object’s methods. Second, when more than one method in the object requires database I/O, this allows a shared common database connection.

The single getSQPhotosByPhotoId method in the GetSQPhotos class selects the array of photos from the SQPhoto database. The database query’s photoID parameter defines the first photo of the selected sequence of photos, up to LIMIT photos, as shown in Listing 6.

if (!$result = $this->mysqli->query("SELECT * FROM photos WHERE photoID>='photoID' LIMIT $this->maxPhotos")) {
    $msg=self::errorPrefix.self::queryError2;
    $this->mysqli->close();
    Throw new Exception ($msg);
}

Listing 6: : Query Selecting Photos from the SQPhoto Database

Note that the database query shown in Listing 6 will throw an exception if the query fails for any reason. PHP exceptions and their respective error messages return to the WebORB application server, which sends an AMF3 exception stream to the Flex client for handling — typically by an Alert dialog.

All my PHP object code throws exceptions where I/O problems can take place. It’s important to always notify the Flex client when something serious occurs in server operations. Never leave the user hanging in their client view when this happens.

Listing 5 shows code from the getSQPhotosByPhotoId method. It reads one photo at a time from the SQPhoto database and packs the photo and photo metadata into an SQPhoto object. Then, right at the end of the while loop, it installs each respective SQPhoto object into the sqPhotoArray object for return to the Flex client.

while ($row = $result->fetch_assoc()) {
    $sqPhoto = new SQPhoto();
    $sqPhoto->photoFilename = $row['photoFilename'];
    $sqPhoto->photoBA = $row['photo';
    $sqPhoto->photoSize = $row['photoSize'];
    $sqPhoto->photoWidth = $row['photoWidth'];
    $sqPhoto->photoHeight = $row['photoHeight'];
    $sqPhoto->photoFormat = $row['photoFormat'];
    $sqPhoto->keywords = $row['keywords'];
    $sqPhoto->caption = $row['caption'];
    $sqPhotoArray[] = $sqPhoto;
}

Listing 7: Code from getSQPhotosByPhotoId method

I suggest that you use your PHP CLI scripting engine to run the PHP test script getSQPhotos.php, The test scripts is found in the tests folder of your download zip file, from the command line. This will allow you to observe and evaluate the operation of the GetSQPhotos class

SearchSQPhotos PHP Class

The basicSQPhotoSearch and advancedSQPhotoSearch methods, which are the two object methods of the SearchSQPhotos WebORB’s services class, perform photo selection and packaging into a SQPhotos object. The code here is nearly identical to the code in the getSQPhotosByPhotoId method in the GetSQPhotos class.

The biggest difference with these two methods is that they also dynamically generate the SQL query statements to search photo keyword and photo caption metadata with the MySQL full-text search engine.

It’s beyond the scope of this article to explain how and in what SQL format these SQL full-text queries generate. But run the photo search server scripts from the following two PHP scripts at your command line using the PHP Command Line Interface (CLI) scripting engine:

  • basicSQPhotoSearchTest.php
  • advancedSQPhotoTest.php

The test scripts allow you to easily play around with the text of the parameter that calls the photo search and review the results the text generates. If you also wish to observe the SQL full-text queries in more detail, uncomment the lines starting with #Test in the SearchSQPhotos class and run the PHP test scripts again, while examining the full-text search section of the MySQL Reference Manual cited above.

MySQL’s SQL full-text search query can become a very powerful tool for providing meaningful and compelling RIAs. This technique can search for more than just photo metadata. With some research and experimentation, you can expand my example into something even more compelling.

The Dilemma: PHP Photo Data as a String is Not an AS 3 ByteArray Data Type

The array of SQPhoto objects received from a PHP server present a problem, as PHP and Flex disagree as to their data type. PHP insists that photos have String data type format and allows no other data type, even if force-cast. Flex prefers, and actually insists on, receiving photos as ActionScript3 (AS3) ByteArrays. Simply put, PHP photo String and Flex photo ByteArray objects are not compatible in any way. I have yet to see a PHP application server that can properly return photos to the Flex client via AMF3 messaging. In the SQGallery application, I have developed WebORB application server update code that dynamically converts PHP photo String to AS 2 AMF ByteArray data streams for transfer to the Flex client.

Author's Update, June 1, 2010
My blog companion article, discussed next, describes how and why you need to modify the WebORB for PHP internal PHP code so that you can transfer photos from the PHP server to the Flex client, arriving as AS 3 ByteArray data type. I recently identified a new way perform this photo data transfer by replacing the WebORB for PHP application server with Zend's Zend Framework application server. Zend Framework supports photo data transfers without requiring internal code modification of PHP code within the framework. See my InsideRIA article Flex 4 / PHP Data-Centric Photo Transfers for details on how to replace WebORB for PHP with Zend Framework.
Fully understanding the above PHP String to AS 3 ByteArray data type issue requires more explanation than this article space allows.
The companion article on my blog, Adobe AMF 3 Transfer of Photo Data From a PHP Application Server To a Adobe Flex Client, (Pete's blog: http://www.seaquest.com/ ) explains what you’ll need to implement the data type translation of photos from a PHP server to a Flex client with code changes to the WebORB for PHP application server.
The blog article provides a download link for the WebORB for PHP code changes, which includes the code change documentation.

Debugging and Evaluating WebORB Services SQPhoto PHP Classes

I would never think of deploying application server Service 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.

I always build application server side test stubs so I can 100% verify the operation of all my server side Service objects before attempting to getting the AMF 3 RemoteObject remote messaging working. This is because if the client / server messaging is not working I like to start out knowing that (at least standalone) the application server Service objects are 100% operational. Why simultaneously debug both sides wondering if the client or the server is the issue?

I have provided the PHP test stub code to verify the operation of all the PHP server side Services objects. in the case of our SQGallery RIA photo gallery solution. This PHP code resides in the ~/WebORB/Services/SQPhoto/tests folder in six PHP script files. Run the tests from your command line using your PHP CLI (not CGI) scripting engine. You’ll gain two benefits:

  1. You come away knowing that your application server side code is 100% operational
  2. More importantly, you will learn how my PHP Service objects work by looking at the code and observing its output.

Summary

The journey of this article has been down two paths, the SQGallery photo gallery and the use and application of the Maté Flex Framework for RIA client side development. Furthermore, the SQGallery photo gallery journey split into two additional trails of photo caching and rendering, and the photo database repository on the WebORB for PHP data side, along with some server-side ByteArray data type issues.

This is a lot of topics to talk about in a blog level article—it’s not a book. I worked to cover just enough of each of these subjects so that you can further move towards developing RIA applications using your own mastery of development issues.

I hope that the topics discussed here will be beneficial towards your RIA development endeavors.

The concepts discussed here are easily transferable to other application servers, if your client / application server remoting is to ColdFusion or BlazeDS (the server-based Java remoting and web messaging technology), or to .Net.

Additionally, if PHP-based Web application servers are not your preference, then the other members of the WebORB application server family can be deployed on the application server side:

  • WebORB for Java
  • WebORB for Rails
  • WebORB for .NET

An equally capable server-side PHP application server is the ‘Zend Amf Server’ component of the Zend Framework ( ).


An Important Notice: Our Wildlife Photos
Michael Wilhelm ( ), my wildlife photographer friend, graciously supplied me with the wildlife photos used for this SQGallery example photo-rendering application. Both Michael and I ask you not to use these photos for any purpose other than demonstrating RIA photo rendering applications.Please do not use the photos in the download package for commercial purposes.

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

Comments

9 Comments

Amy Blankenship said:

Thanks, Pete!

I love your tutorials, as they always provide everything needed to understand the concept you're covering.

teddy said:

Great article,
another input for me for handling cache images.

Thanks, Pete.


Sharedtut said:

Very intense tutorial but good walking, thank you for taking the time to write.

Thomas Burleson said:

Pete,
Nice article. I especially enjoyed your thoughts regarding the issues and transitions from Cairngorm to Mate. Recently I developed a major extension to Mate. That extension delivers i18n (multi-language) features: called the l10nInjection framework. This can be used as part of Mate or as a standalone library with any other MVC framework.

I would very interested in having you use that framework in the PhotoGallery app. With l10nInjection you can very easily add Spanish, German, Chinese (etc.) support to any Flex app.

Check out my blog for details. And give me a shout if you need any feedback.

http://github.com/ThomasBurleson
http://www.gridlinked.info/

Thanks again,
ThomasB

Pete Mackie said:

Thomas,

Thank you for your comment. I appreciate your words.

Your Mate extension is certainly a worthwhile one, which I'm glad to that you made us aware of. Presently I'm busy writing a new InsideRIA article on how to connect Flash Builder 4 clients to remote PHP services using the Zend Framework application server. Accordingly I will leave any Photo Gallery extension updates to the article readers.

Pete Mackie

Kathleen Erickson said:

Thanks for posting this helpful tutorial Pete. Mind if we add a link to it on our website? Also, feel free to link back the other flavors of our WebORB product to our website. We very much appreciate evangelists like you!

Cheers,
Kathleen

@Kathleen
A link from your Web site would be great!
Pete

seder said:

thank you very much for keep improving this essential tool for wpf developers ! müzik
indir

Thomas said:

I love your tutorials, as they always provide everything needed to understand the concept you're covering. Thomas from http://www.nmeds.com/

@Thomas

Thanks for your kind words. I try to be through with the "how to" details.

Pete

Leave a comment


Type the characters you see in the picture above.


Tag Cloud

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.