Using Flex SDK with Mate and PHP

Creating PHP services to enable rich applications with Eclipse PDT

Mate is a lightweight event-driven framework that enables you to build user interfaces (UIs) and services in a Model-View-Controller (MVC) pattern. Learn how to use Eclipse PHP development tools (PDT) and the Flex software development kit (SDK) together to build an application using the Mate framework. This article expands on the existing Mate documentation, as it focuses on using Eclipse PDT as the tool.

Share:

Nathan A. Good, Senior Information Engineer, Freelance Developer

Nathan GoodNathan A. Good lives in the Twin Cities area of Minnesota. Professionally, he does software development, software architecture, and systems administration. When he's not writing software, he enjoys building PCs and servers, reading about and working with new technologies, and trying to get his friends to make the move to open source software. He's written and co-written many books and articles, including Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution Approach, and Foundations of PEAR: Rapid PHP Development.



14 July 2009

Also available in Japanese Portuguese

Adobe® Flash® is an attractive alternative for building rich Internet applications (RIAs). Using Eclipse and the Adobe Flex SDK, you can compile your projects into applications that run in the Flash Player. Mate is a lightweight event-driven framework that brings the power of easily calling remote objects by using invokers. These remote objects may be services written in PHP.

To run the example in this article, you need Eclipse PDT. The rest of the things you need are covered in this article.

Mate and Flex SDK overview

The Flex SDK allows you to build Adobe Flex applications. Flex applications use source files in XML format and ActionScript V3.0. Using the compiler, you can compile these .mxml files and ActionScript files to Adobe Flex applications.

There are two versions of the Flex SDK that you can download:

  • The Adobe Free version that includes the Adobe products that allow you to compile applications and also includes Adobe AIR and other components. The Adobe Free SDK is licensed with the Adobe Flex SDK license (see Resources).
  • The SDK is also provided in an Open Source Flex SDK version licensed under the Mozilla Public License (MPL). It includes a compiler and everything you need to run the example in this article. However, the MPL license may not suit your needs. Check with your legal department to verify that the license works for you.

Additionally, Adobe offers a product called Flex Builder you can download as an Eclipse plug-in or as a full product. For the purposes of this article, download the open source Flex SDK. Download the ZIP file and unpack it to a location easy to remember; in this article, I refer to that location as FLEX_HOME. This article demonstrates how to set up Eclipse with the free SDK so you can build RIAs with just Eclipse, PDT, and the Flex SDK.

Mate is a framework that helps you build applications that follow the MVC pattern. Mate is event-driven, so you create events that are ActionScript classes. You can then map the events to remote object invocation, leaving the details of the code out of your views and model.


Creating the project structures

In this article, a simple time-entry application — called ChronoLog — demonstrates how to build a Flex UI with PHP services. The example requires two projects in your Eclipse workspace: One is a PHP project that is used for the services, and the other is a normal project that includes an Ant file that is set up as an Ant builder. The Ant builder is used to execute the Flex compiler to compile the project that is used for the UI.

To create the services PHP project, select File > New > Project from the Eclipse menu. Select PHP Project, then select Create project from existing source and choose a location under your file server's document root. This allows you the to quickly test the PHP services you create.

To create the UI project, create an empty project using File > New > Project and select Project.

After you create the project for the UI, create a folder called src and another inside it called chronolog. Under that folder, create folders called events, model, views, and maps. The structure will look similar to that below.

Figure 1. The UI project structure
The UI project structure

Downloading and installing Mate

Mate is available for download as a single compiled file with an .swc extension. Download the file from the site and install it by importing it into the libs folder in the UI project. The result should look like Figure 2.

Figure 2. The Mate .swc file in the libs folder
Mate .swc file

Building a simple service

The service is written in PHP and has only two classes: a service class that does the function and a PHP class to which the TimeEntry UI class is mapped.

Before writing the services classes, download and install the required AMFPHP files. To run this example, simply install the amfphp folder into your PHP project, as shown below.

Figure 3. The amfphp folder
The amfphp folder

The service class is shown in Listing 1. The service class simply writes out the values as a small XML file in a temporary location. On your computer, you may have to modify this location (in bold) so it can be successfully written. You should change it to the name of a file that can be read and written to by your Web server.

Listing 1. The amfphp/services/ChronoLogManager.php file
<?php
require_once('./vo/TimeEntry.php');
/*
 * A service for managing time entries.
 */
class ChronoLogManager
{

    public function saveTimeEntry($entry)
        {

        $myFile = "/tmp/time.xml";
        $fh = fopen($myFile, 'w') or die("can't open file");

        $stringData = "<projects>";
        $stringData .= "<entry project=\"$entry->project\" " .
                    "time=\"$entry->time\" user=\"$entry->username\" />";
        $stringData .= "</projects>";

        fwrite($fh, $stringData);
        fclose($fh);

        }

}

?>

The service-side model object, TimeEntry.php, is shown in Listing 2. AMFPHP requires the value objects to be stored in the services/vo folder, so the relative path name of the PHP file from the PHP project's root is amfphp/service/vo/TimeEntry.php. AMFPHP requires that the class names and file names (minus the extension) match.

Listing 2. The amfphp/services/vo/TimeEntry.php file
<?php
class TimeEntry
{
    var $_explicitType = 'model.TimeEntry';

    public $username;
    public $project;
    public $time;
}
?>

One advantage of using a class as a parameter object instead of many different parameters is that if any more fields are added to the time entry field, you can simply add a new field to the object. One disadvantage is that any problems you encounter while using frameworks for messaging are likely to occur with complex types. Sometimes, simple types (string, integer, boolean) are easier to use because they avoid problems.


Using a model object

A model object is an ActionScript class that holds data in the application and maps to a remote object (TimeEntry.php) in the PHP services tier. You can use the object as an argument to a method — or the result of a method — without building arrays to pass data between the UI and services.

Normally, when building UIs in one technology and services in another, you must write or find a framework that serializes the classes to some format both technologies understand. XML is often used because it is usually easy to find utilities in the modern programming languages that read and write from XML.

In this application, AMFPHP is used to map the Flex objects to the remote PHP objects. Adobe Message Format (AMF) is Adobe's format for serializing and deserializing objects. One advantage of using the AMF is that it allows you to connect the objects without having to write your own serialization and deserialization code between the UI and the services. There are a couple frameworks for connecting Flex to PHP via AMF, including one from Zend (see Resources).

The model object for TimeEntry, which contains the information used for each time entry field, is shown in Listing 3. Save it in the src/chronolog/model folder of the UI project.

Listing 3. The src/chronolog/model/TimeEntry.as file
package model
{
    [Bindable]
    [RemoteClass(alias='TimeEntry')]
    public class TimeEntry
    {
        private var _username : String;
        private var _project : String;
        private var _time : String;
        
        public function TimeEntry()
        {
        }
        
        public function get username() : String
        {
            return _username;
        }
        
        public function set username(value : String) : void
        {
            _username = value;
        }
        
        public function get project() : String
        {
            return _project;
        }
        
        public function set project(value : String) : void
        {
            _project = value;
        }
        
        public function get time() : String
        {
            return _time;
        }
        
        public function set time(value : String) : void
        {
            _time = value;
        }

    }
}

Aside from the RemoteObject attribute declared in the class, this is just like any other ActionScript class you would create to support your application.


Building an event

Mate is an event-driven framework, so you create many events while using Mate. A Mate event is an ActionScript class that extends from the base flash.events.Event class. A string constant identifies the specific event, and you can have one or more constants in each event class. I use this ability to group events according to their purpose in the business domain. For instance, in the ChronoLog example there is a TimeEntryEvent class. It uses the constant SAVE, which represents an event that should trigger a function that saves the time entry. As the project grows, more events in the same class might include GET or DELETE.

Name your events using business terms and map them to business functions. Do not create an event class called ButtonEvent and add constants called SAVE_CLICKED. In doing so, you use poor naming to implicitly limit the reuse of your event. If the users change their minds and a button is changed to a link, it presents a problem with events that are too tightly tied to the UI.

An example of the TimeEntryEvent ActionScript class is shown in Listing 4. In addition to adding the SAVE constant, the default for the bubbles parameter in the constructor is changed to true. I add an argument for the event as a public variable of type TimeEntry.

Listing 4. The src/chronolog/events/TimeEntryEvent.as file
package events
{
    import flash.events.Event;
    
    import model.TimeEntry;

    public class TimeEntryEvent extends Event
    {
        public static const SAVE : String = 'TimeEntryEvent_SAVE';
        
       public var entry : TimeEntry;
            
        public function TimeEntryEvent(type:String, bubbles:Boolean=true, 
            cancelable:Boolean=false)
        {
            super(type, bubbles, cancelable);
        }
        
    }
}

Building a view

Aside from the ActionScript class, the rest of the files in the UI project are Flex components. These components are placed in files with an .mxml extension. The MXML files are well-formed XML files, so I associate them in Eclipse with the XML editor to take advantage of the XML editor's features, such as formatting and tag closing. To create the MXML file, select File > New > File and give it the appropriate name.

For the UI, the main application file (main.mxml) contains only the reference to the main EventMap and to the view. The source for the main.xml file is shown in Listing 5. The main.mxml file is saved in the src/chronolog folder of the UI project.

Listing 5. The src/chronolog/main.mxml file
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
    xmlns:maps="maps.*" 
    xmlns:views="views.*">
<mx:ViewStack>
    <views:DetailView id="detailView" />
</mx:ViewStack>
</mx:Application>

The view detailView is a Flex component that extends the Flex Panel object. The entire contents of the view are shown below.

Listing 6. The src/chronolog/views/DetailView.mxml file
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" 
    width="100%" 
    height="100%" 
    xmlns:mate="http://mate.asfusion.com/">
<mx:Script>
    <![CDATA[
        import com.asfusion.mate.events.ResponseEvent;
        import mx.controls.Alert;
        import model.TimeEntry;
        import events.TimeEntryEvent;
        
        [Bindable]
        public var entry : TimeEntry;
       
        private function save() : void
        {
            entry = new TimeEntry();
            entry.username = 'jdoe';
            entry.project = projectInput.text;
            entry.time = timeInput.text;
        }
        
        private function handleResult(event : ResponseEvent) : void
        {
            Alert.show('Success!');
        }
            
        private function handleFault(event : ResponseEvent) : void
        {
            Alert.show(event.fault.toString());
        }
        
    ]]>
</mx:Script>
    <mx:HBox>
        <mx:FormItem label="Project Number">
            <mx:TextInput id="projectInput" />
        </mx:FormItem>
        <mx:FormItem label="Time">
            <mx:TextInput id="timeInput" />
        </mx:FormItem>
        <mx:Button label="Save" click="save()" />
    </mx:HBox>
</mx:Panel>

The view contains two fields and a button. The fields are the project number and a value representing the time worked. A user name, which is also used in the time entry field, is hard-coded. As the application grows, the user name comes from data acquired when the user logs into the application. Save the view as an MXML file in the views folder as DetailView.mxml.


Building the EventMap

A component that extends Mate's EventMap is used to map the events to actions. This is where the events are "wired" up to remote objects. In addition, you can use the EventMap to have events call other events when they're complete, set values on local objects, and initiate methods locally.

In particular, chaining events is powerful. By chaining events, you can avoid hard-coding many interactions to make the project more resilient to changing business needs. For instance, if the users want the screen to change to a different view after they've successfully saved data, you can create a NavigateEvent that makes this change. The TimeEntry.SAVE event can dispatch the NavigateEvent. That way, if users change their minds later, you can simply update the EventMap to reflect the new requirements.

An example of the MainEventMap is shown in Listing 7. It is simply an .mxml file created in the maps folder.

Listing 7. The src/chronolog/maps/MainEventMap.mxml file
<?xml version="1.0" encoding="utf-8"?>
<mate:EventMap 
    xmlns:mate="http://mate.asfusion.com/" 
    xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
    import events.TimeEntryEvent;
    ]]>
</mx:Script>
  <mate:EventHandlers type="{TimeEntryEvent.SAVE}">
    <mate:RemoteObjectInvoker destination="amfphp" 
                source="ChronoLogManager" 
                method="saveTimeEntry" 
                arguments="{event.entry}">
      <mate:resultHandlers>
        <mate:ServiceResponseAnnouncer type="result" />
      </mate:resultHandlers>
      <mate:faultHandlers>
        <mate:ServiceResponseAnnouncer type="fault" />
      </mate:faultHandlers>
    </mate:RemoteObjectInvoker>
  </mate:EventHandlers>
</mate:EventMap>

In the EventMap, the RemoteObjectInvoker contains the information used to map the event of type TimeEntryEvent.SAVE to the correct method (saveTimeEntry) on the remote object (ChronoLogManger). The RemoteObjectInvoker entry also specifies the arguments — the event's entry field as noted by {event.entry}. The destination, amfphp, is the ID of the destination specified in the services-config.xml file.

After creating the EventMap, include it in the main application, as shown below.

Listing 8. The MainEventMap in the main.mxml file
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="absolute" 
    xmlns:maps="maps.*" 
    xmlns:views="views.*">
 <maps:MainEventMap id="eventMap" /> 
<mx:ViewStack>
    <views:DetailView id="detailView" />
</mx:ViewStack>
</mx:Application>

Dispatching the event in the view

Using Mate, events are dispatched in many ways. You can use the dispatcher that comes in each component. You can also use Mate's Dispatcher, which is what is used in the ChronoLog application. A benefit of using the Dispatcher is that it allows you to easily set parameters on the event to local values, such as text input, without having to write any code in ActionScript to do it. Also, with the Dispatcher, you can set the methods executed when the event is complete.

The Dispatcher is shown in bold below.

Listing 9. The Dispatcher shown in the src/chronolog/views/DetailView.mxml file
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal" 
    width="100%" 
    height="100%" 
    xmlns:mate="http://mate.asfusion.com/">
<mx:Script>
    <![CDATA[
        import com.asfusion.mate.events.ResponseEvent;
        import mx.controls.Alert;
        import model.TimeEntry;
        import events.TimeEntryEvent;
        
        [Bindable]
        public var entry : TimeEntry;
        
        private function save() : void
        {
            entry = new TimeEntry();
            entry.username = 'jdoe';
            entry.project = projectInput.text;
            entry.time = timeInput.text;
            saveDispatcher.generateEvent();
        }
        
        private function handleResult(event : ResponseEvent) : void
        {
            Alert.show('Success!');
        }
            
        private function handleFault(event : ResponseEvent) : void
        {
            Alert.show(event.fault.toString());
        }
        
    ]]>
</mx:Script>
    <mx:HBox>
        <mx:FormItem label="Project Number">
            <mx:TextInput id="projectInput" />
        </mx:FormItem>
        <mx:FormItem label="Time">
            <mx:TextInput id="timeInput" />
        </mx:FormItem>
        <mx:Button label="Save" click="save()" />
    </mx:HBox>
		
    <mate:Dispatcher id="saveDispatcher" generator="{TimeEntryEvent}" 
            type="{TimeEntryEvent.SAVE}">
        <mate:eventProperties>
            <mate:EventProperties entry="{entry}" />
        </mate:eventProperties>
        <mate:ServiceResponseHandler result="handleResult(event)" 
            fault="handleFault(event)" />
    </mate:Dispatcher>
		
</mx:Panel>

Calling the service

To call the service, you need to set up the PHP class in the AMFPHP service configuration file in your services-config.xml file. The services-config.xml file contains the endpoint URL of the service that works for the AMF-supporting framework. The example services-config.xml file is shown below.

Listing 10. The src/services-config.xml file
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service id="amfphp-flashremoting-service" 
            class="flex.messaging.services.RemotingService"
            messageTypes="flex.messaging.messages.RemotingMessage">

            <destination id="amfphp">
                <channels>
                    <channel ref="my-amfphp" />
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    <channels>
        <channel-definition id="my-amfphp"
            class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://localhost/chronolog/amfphp/gateway.php" 
                class="flex.messaging.endpoints.AMFEndpoint" />
        </channel-definition>
    </channels>
</services-config>

Notice that you need to change the URL for the gateway used by AMFPHP to whatever works for your environment.


Building the project

When all the Flex files are set up, an Ant builder uses the mxml.jar file that comes with the Flex SDK to compile the project. The Ant file is shown below.

Listing 11. The build.xml file
<?xml version="1.0"?>
<project name="chronologUI" basedir="." default="build">
    <property name="flex.home" value="/home/ngood/bin/flex3-sdk" />
    <property name="mxmlc.jar" value="${flex.home}/lib/mxmlc.jar" />
    <property name="project.home" value="${basedir}" />
    <property name="project.src" value="${project.home}/src" />
    <property name="build.out" value="${project.home}/bin" />
    <target name="build">
        <java jar="${mxmlc.jar}" fork="true" failonerror="true">
            <jvmarg value="-Xms256m"/>
            <jvmarg value="-Xmx256m"/>
            <arg value="-compiler.source-path=${project.src}" />
            <arg value="+flexlib=${flex.home}/frameworks" />
            <arg value="-compiler.library-path+=${project.home}/libs/Mate_08_8_1.swc" />
            <arg value="-file-specs=${project.src}/chronolog/main.mxml" />
            <arg value="-locale=en_US" />  
            <arg value="-services=${project.src}/services-config.xml" />
            <arg value="-compiler.strict=true" />
            <arg value="-warnings=false" />
            <arg value="-output=${build.out}/chronolog.swf" />
        </java>
    </target>
</project>

After the build.xml file is added to the project, add an Ant Builder by selecting the chronologUI project from the Project Explorer and selecting Project > Properties. Click New from the Properties window. Select Ant Builder from the list. On the next screen (see Figure 4), click Browse Workspace to find and select the build.xml file. The builder setup automatically uses the default target, so you can click Finish to close the browser. For a more thorough explanation of creating your own builders for projects, see Resources.

Figure 4. Creating the Ant builder
Creating the Ant builder

Now that the builder has been added to the project, it will run when you select Project > Build from the menu in Eclipse.

Because this example uses AMFPHP, the AMF directory must be there for the supporting AMFPHP framework. More information about how to set up and install AMFPHP is in Resources.


Running the example

After you build the UI project, put the chronolog.swf file under your Web browser's document root and navigate to it in your browser. It should look like the example below.

Figure 5. The completed application running
The completed application running

When you enter data and click Save, the services layer writes the data to a tiny XML file in the location specified in the service.


Summary

Using the Flex SDK, Mate, and PHP you can build rich Web applications. With a few tweaks to your Eclipse project setup, you can use the Flex SDK to build Flex applications in Eclipse with the use of Flex Builder, although the WYSIWYG UI editing and debugging features of Flex Builder make building Flex applications a lot easier.

Using Eclipse PDT and AMFPHP, you can build services that can be consumed by your Flex applications. Remoting — using AMF — allows you to quickly write events that invoke methods on remote objects from Flex.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=412154
ArticleTitle=Using Flex SDK with Mate and PHP
publish-date=07142009