Accessibility

Flex Article

 

Flex quick start guide for PHP developers


Judah Frangipane

Judah Frangipane

www.drumbeatinsight.com

Comments
Created:
30 April 2007
User Level:
Beginner
Products:
Flex

Note: This article was created based on Flex 2. Minor changes in the description and code may be necessary before it can be applied to Flex 3.

As a PHP and HTML developer you may be wondering, "How do I start using Flex?" Adobe Flex is a very powerful set of tools but "...with great power comes great responsibility."

This article shows you how to perform common tasks in Flex that PHP developers do every day. HTML examples demonstrate the difference between HTML and MXML code. Each section is broken down into a stand-alone example that you can run on its own. Where PHP is used, the code is displayed. All the code and examples are available in the included project file samples (download them from the Requirements section). I will start with the basics and then move on to more advanced topics, while keeping the code basic for learning purposes. I hope this guide will show you how easy it is to get started using Flex.

Requirements

To make the most of this article, you need the following software and files:

Flex Builder 2

Sample files:

Contents

Submitting a form using the GET method to PHP

In HTML, to submit a form using the get method, you use the following:

<form name="input" action="mypage.php" method="GET">
   Username: 
   <input type="text" name="user"/> 
   <input type="submit" value="Submit"/>
</form>

This results in submitting the form to the URL in the form's action attribute, redirecting to it.

To submit a form in Flex using the get method, you use the following code:

SubmitUsingGet.mxml:
           
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Submit form using get method" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   
   <mx:HTTPService id="form1" url="http://www.flexcapacitor.com/examples/php/show_request.php" method="GET" resultFormat="text" result="{textarea1.text = String(event.result)}">
      <mx:request>
         <username>{username.text}</username>
      </mx:request>
   </mx:HTTPService>
   
   <mx:TextInput id="username" x="10" y="71"/>
   <mx:Button x="178" y="71" label="Submit" click="form1.send()"/>
   <mx:Label x="10" y="101" text="Result"/>
   <mx:TextArea x="10" y="118" width="234" height="188" id="textarea1"/>

</mx:Application>

Then you can use the following sample PHP page to return the form information submitted to the PHP page:

show_request.php:


<?php

   // send a response back to the client
   print "You submitted the following form information:\n";
   foreach ($_REQUEST as $k => $v) {
      print "   $k = $v\n";
   }

?>

This example uses the HTTPService class. See the following excerpt from the Adobe LiveDocs documentation:

You use the <mx:HTTPService> tag to represent an HTTPService object in an MXML file. When you call the HTTPService object's send() method, it makes an HTTP request to the specified URL, and an HTTP response is returned. Optionally, you can pass parameters to the specified URL. When you do not go through the server-based proxy service, you can use only HTTP GET or POST methods. However, when you set the useProxy property to true and you use the server-based proxy service, you can also use the HTTP HEAD, OPTIONS, TRACE, and DELETE methods.

You can specify the information to send to the request object on the server. The request object is a property of the HTTPService class. Inside the request, you specify individual parameters to send to the server. In this case, you use the databinding expression shorthand notation to specify a reference to your text input, username. See the following excerpt from the Adobe LiveDocs documentation:

Using the curly braces syntax is the simplest way to pass data between objects in an application. When you use this syntax, you put curly braces ({ }) around a binding source as the value of a destination property.

You can use ActionScript expressions in curly braces as well. Note that you are not limited to sending data from form elements that exist inside a form tag.

In this example, you submit your form to a PHP page that iterates through the form values and sends them back to the client. The HTTPService class can receive an HTTP response without reloading the page. The resultFormat contains the value that indicates how you want to deserialize the result returned by the HTTP call. In the HTTPService tag you set the resultFormat to text. By default, resultFormat returns an object. By specifying event listener functions in the result and fault events, you can handle the data returned in the response. In this example you display the response from the server in a textarea.

Read more in the LiveDocs documentation:

Submitting a form using the POST method to PHP

Submitting a form using the post method is the same as submitting a form using the get method, except you change the method attribute value to post instead of get. In Flex to submit a form using the post method, you use the following code:

SubmitUsingPost.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Submit form using post method" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   
   <mx:Script>
      <![CDATA[
         import mx.rpc.events.FaultEvent;
         import mx.rpc.events.ResultEvent;
         public function handleResult(event:ResultEvent):void {
            textarea1.text = "Response from HTTPService call:\n " + String(event.result);
         }
         public function handleFault(event:FaultEvent):void {
            textarea1.text = "Fault Response from HTTPService call:\n " + event.fault.toString();
         }
      ]]>
   </mx:Script>

   <mx:HTTPService id="form1" url="http://www.flexcapacitor.com/examples/php/show_request.php" method="POST" result="handleResult(event)" fault="handleFault(event)" resultFormat="text">
      <mx:request>
         <username>{username.text}</username>
      </mx:request>
   </mx:HTTPService>

<!-- Visual Items -->
   <mx:Label x="10" y="101" text="Result"/>
   <mx:TextArea x="10" y="118" width="234" height="188" id="textarea1"/>
   <mx:TextInput id="username" x="10" y="71"/>
   <mx:Button x="178" y="71" label="Submit" click="form1.send()"/>

</mx:Application>

show_request.php:

<?php

   // send a response back to the client
   print "You submitted the following form information:\n";
   foreach ($_REQUEST as $k => $v) {
      print "   $k = $v\n";
   }

?>

In this example you have changed the method to POST. You also added event listener functions inside an ActionScript 3.0 script block to handle the result and fault events. When you get a response or result from the server, the result function specified in the result event is executed. If the call fails—for example, because you specified an incorrect URL—then the function specified in the fault event is executed.

The response from the server is sent in the event.result property inside the result function. By default, the event.result is an object. You usually need to convert the object to the type of data you specify in the resultFormat using a method such as String. To specify the type of data that the server should return, set the resultFormat in your HTTPService tag. This property can be an object, array, XML, E4X, flashvars, or text depending on the result type specified in the resultFormat attribute. In this example, you set this attribute to text because you want to treat the response from the server as a string.

You can access the response data outside the function using the HTTPService lastResult property—or, in other words, with myService.lastResult. The lastResult property is the same as the result property but it is not set until after the result function has finished executing. The lastResult property can be very convenient because it will always contain the result from the most recent service call. Components can be bound to this value and be automatically updated to contain the most recent value.

Notice that ActionScript is very similar in syntax to JavaScript. In fact they are both based on the same ECMA specification. Declaring event listeners in this way gives you more flexibility. Using the following sample PHP page from the previous example, you can display the information you submitted to your PHP page.

Read more in the LiveDocs documentation:

Submitting a form to Google using the GET method

It's easiest to create something in a controlled environment, so in this next section, you'll create an example to submit a form to Google. In your environment, you would submit to your own PHP to retrieve a string or XML in response.

To submit a form in Flex to Google, you can use the following code:

SubmitFormToGoogle.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Submit search to Google" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   
   <mx:HTTPService id="form1" url="http://www.google.com/search" method="GET" resultFormat="text" result="{textarea1.text = String(event.result)}">
      <mx:request>
         <q>{search.text}</q>
      </mx:request>
   </mx:HTTPService>
   <mx:Label x="10" y="101" text="Result"/>
   <mx:TextArea x="10" y="118" width="234" height="188" id="textarea1"/>
   <mx:TextInput id="search" x="10" y="71"/>
   <mx:Button x="178" y="71" label="Submit" click="form1.send()"/>

</mx:Application>

In the example you submit your form using the get method. The HTTPService class can receive an HTTP response in return without reloading the page. You display the response from your Google search in a textarea. You could extend this to display the search results in a List or DataGrid component.

Note: Although this code works locally, this will not work when uploaded to a server due to cross-domain security issues. To work around this for the remote site (Google in this case), add a cross-domain policy file allowing your SWF file to access it. A cross-domain file is an XML file in the root of the remote server that specifies that any SWFs from the specified domains can access its content. If no cross-domain file exists or the domain your SWF file is running from is not listed, then your application cannot access it. An alternative that many developers use is a proxy page on the site, although other more efficient methods are available to retrieve data from another server (listed at the end of this article).

Note: Although the response contains the search results from Google, and you could try to convert the results to XML, it will most likely fail as most XHTML web pages are not valid XML. If you wanted to get valid XML search results from Google, it would be better to use the Google API.

You will most likely not use this approach with a server outside of your domain. It would be better to use any of the other methods listed at the end of this article for communication with remote servers.

Read more about using a PHP proxy page in the article, PHP Proxy for Flash Cross-Domain Security problems. Also refer to the following resources:

Populating a list with XML from the server

More than likely you will submit your form to the server and it will return XML data. The HTTPService class can receive and cast the response into many different data types including object, array, XML, E4X, flashvars, and text data types. If you specify the return type as E4X, you can take advantage of the advanced sorting, filtering, and reference features E4X offers for XML data. From the Adobe LiveDocs documentation:

The ECMAScript for XML specification defines a set of classes and functionality for working with XML data. These classes and functionality are known collectively as E4X. ActionScript 3.0 includes the following E4X classes: XML, XMLList, QName, and Namespace.

The methods, properties, and operators of the E4X classes are designed with the following goals:

The following example converts the response from the form you submit to the server into E4X, places the result in a TextArea, and binds it to a List component:

PopulateListWithXML.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Populate List with XML" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>

   <mx:HTTPService id="form1" url="http://www.flexcapacitor.com/examples/php/show_xml.php" method="POST" result="{textarea1.text = String(event.result)}" resultFormat="e4x">
      <mx:request>
         <firstname>{firstname.text}</firstname>
         <lastname>{lastname.text}</lastname>
      </mx:request>
   </mx:HTTPService>
    
    <mx:XMLListCollection id="listCollection" source="{form1.lastResult..row}"/>
   
    <mx:Binding source="{listCollection}" destination="list1.dataProvider"/>
    <mx:Binding source="list1.selectedItem.@label" destination="label1.text"/>
    
   <mx:TextInput id="firstname" x="10" y="59" text=""/>
   <mx:TextInput id="lastname" x="10" y="89" text=""/>
   <mx:Button x="178" y="89" label="Submit" click="form1.send()"/>
   <mx:TextArea x="10" y="140" width="234" height="188" id="textarea1"/>
   <mx:Label x="252" y="119" text="List Component" id="label1"/>
   <mx:Label x="10" y="119" text="Results" id="label0"/>
   <mx:List x="252" y="140" id="list1" width="208" height="188" labelField="@label"/>

</mx:Application>


show_xml.php:

<?php
   print "<?xml version='1.0' encoding='ISO-8859-1' ?>";
   print "<rows>";
   print " <row label='".$_REQUEST['firstname']." ".$_REQUEST['lastname']."'/>";
   print " <row label='user 2'/>";
   print " <row label='user 3'/>";
   print "</rows>";
?>

In this example, I changed the result data type to XML with E4X support by setting the resultFormat in the HTTPService class to E4X. I then use the binding tag to link or bind the XML to the list component. The code uses the E4X syntax in the binding tag to filter the XML to get the desired nodes.

Note: The labelField property of the List component lets you define where the row label comes from. When you use XML you need to specify the label field using E4X syntax. Notice the "@" symbol in front of the attribute name. This specifies that "label" is an attribute of the node.

Read more in the Adobe LiveDocs documentation:

Navigating to another URL or targeting a frame

In HTML you navigate from page to page. HTML uses a document paradigm. One document is loaded and links point to other documents. In Flex you have one application that changes states rather than a page that navigates to another page (see the section Changing states in Flex). These both have their advantages but there are times when you will want to navigate away from the page you are on or load a frame with a new page.

Use the following code to navigate to another URL in HTML:

<a href="mypage2.php">Go to Page 2</a> 

In Flex to you can navigate to a URL by using the navigateToURL function. The navigateToURL loads a new URL in a frame or window. From the documentation:

The navigateToURL() method loads a document from a specific URL into a window or frame or passes variables to another application at a defined URL. You can use this method to call JavaScript functions in the HTML page that encloses a Flex application.

To do this, create a URLRequest object to specify the URL to navigate to. From the documentation:

The URLRequest class captures all of the information in a single HTTP request. This object defines the URL target, variables, method (POST or GET), window, and headers for the request.

To navigate to a URL in Flex:

NavigateToURL.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Navigate to a different URL" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>


   <mx:Label x="10" y="78" text="Open in a new window"/>
   <mx:Button x="10" y="104" label="Go to Google" click="navigateToURL(new URLRequest('http://www.google.com'))"/>

   <mx:Label x="203" y="78" text="Open in current window"/>
   <mx:Button x="203" y="104" label="Go to Google" click="navigateToURL(new URLRequest('http://www.google.com'),'_self')"/>
   
</mx:Application>    

To target a specific frame or window, you specify its name in the second parameter of the navigateToURL method.

Read more in the Adobe LiveDocs documentation:

Changing states in Flex

Changing states does not mean moving from Minnesota to Florida. In HTML you can show or hide certain elements on a page. You change its state from visible to invisible.

In Flex you have similar behavior that is much more powerful. When you change to a new state in Flex you can add or remove components, set properties, change the behavior of a button, trigger effects, trigger transitions, and more. Flex calls this overall behavior "changing states." From the documentation:

You can use Adobe Flex Builder 2 to create applications that change their appearance depending on the task that the user is performing. For example, the base state of the application could be the home page and include a logo, a sidebar, and some welcome content. When the user clicks a button in the sidebar, the application dynamically changes its appearance (its state), replacing the main content area with a purchase order form but leaving the logo and sidebar in place.

In Flex, you can add this kind of interactivity with view states and transitions. A view state is one of several views that you define for an application or a custom component. A transition is one or more effects grouped together to play when a view state changes. The purpose of a transition is to smooth the visual change from one state to the next.

In this example, you will change the state of the canvas component. In HTML you show or hide an element on the page using the following code:

 <label> 
    Show Hidden Element <input type="checkbox" name="checkbox" value="checkbox"
    onclick="document.getElementById('element').style.display= (this.checked) ? 'block' : 'none'"/> 
</label> 

<div id="element" style="display:none;border:1px solid red;">I am now visible</div>

In Flex to show or hide a different state you would use this code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Change states" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   <mx:CheckBox id="checkbox0" x="10" y="59" label="Show Different State" labelPlacement="left"
      click="{currentState = (checkbox0.selected) ? 'view3' : '';}"/>
   <mx:Canvas id="canvas1" width="400" height="75"
      borderStyle="solid" borderColor="gray" backgroundColor="#f6f6f6" x="10" y="85">
      <mx:Button id="button1" x="178" y="36" label="Search" click="{Alert.show('Call basic search function with button1')}"/>
      <mx:TextInput x="10" y="36"/>
      <mx:Label id="searchLabel" x="10" y="10" text="Basic Search"/>
   </mx:Canvas>

   <mx:states>
      <mx:State name="view3">
            <mx:AddChild relativeTo="{canvas1}">
                <mx:ComboBox id="combobox1" dataProvider="['first name','last name']"/>
            </mx:AddChild>
            <mx:SetProperty target="{combobox1}" name="x" value="178"/>
            <mx:SetProperty target="{combobox1}" name="y" value="36"/>
            <mx:SetProperty target="{searchLabel}" name="text" value="Advanced Search"/>
            <mx:SetProperty target="{button1}" name="x" value="289"/>
            <mx:SetEventHandler target="{button1}" name="click" handler="{Alert.show('Call advanced search function using same button1 instance.\n\nWe can change the behavior with states!')}"/>
      </mx:State>
   </mx:states>
      
   <mx:CheckBox id="checkbox" x="10" y="192" label="Show Different View in the ViewStack" labelPlacement="left"
      click="{viewstack1.selectedChild = (checkbox.selected) ? view2 : view1;}"/>
   
   <mx:ViewStack x="10" y="218" id="viewstack1" width="400" height="50" borderStyle="solid" borderColor="gray" backgroundColor="#f6f6f6">
      <mx:Canvas id="view1" label="View 1" width="100%" height="100%">
         <mx:Label text="First Name" x="10" y="10"/>
         <mx:TextInput text="John" x="82" y="10"/>
      </mx:Canvas>
      <mx:Canvas id="view2" label="View 2" width="100%" height="100%">
         <mx:Label text="Last Name" x="10" y="10"/>
         <mx:TextInput text="Smith" x="82" y="10"/>
         <mx:Button x="250" y="10" label="Submit"/>
      </mx:Canvas>
   </mx:ViewStack>

   <mx:Script>
      <![CDATA[
         import mx.controls.Alert;
      ]]>
   </mx:Script>
   
</mx:Application>

    

In this example you changed the state of the canvas container when the user selects the "Show Different State" option. Change the basic search form to an advanced search form by adding a combobox and moving the search button over. When you make these changes you also change the click event of the button so that it calls the advanced search function instead of the basic search function.

In this example you also have shown you the ViewStack container for comparison. The checkbox in this example displays a second state in the ViewStack component when it is checked. When it is deselected, it displays the original state. Each child of the ViewStack is a container component. From the documentation:

In Adobe Flex, layout containers provide a hierarchical structure to arrange and configure the components, such as Button and ComboBox controls, of a Flex application.

A layout container defines a rectangular region of the Adobe Flash Player drawing surface and controls the sizing and positioning of the child controls and child containers defined within it. For example, a Form layout container sizes and positions its children in a layout similar to an HTML form.

Inside each container, you can display different views or states to the user. The main difference between a ViewStack component and defining states in your application is that a ViewStack component will switch to show a set of different components, while states will let you manipulate or remove the components you already have or add new components.

Note: Containers with multiple views, such as the ViewStack and Accordion, do not immediately create all of their descendants, but only those descendants that are visible in the initial view. Flex defers the instantiation of descendants that are not initially visible until the user navigates to a view that contains them.

You can use the container's creationPolicy property to create all controls in all views of the navigator container. This setting causes a delay in larger application's startup time but results in quicker response time when first switching to the view at runtime. When using states you can use the creationPolicy attribute of the addChild tag to control when the child component is created.

The States API is very powerful and can do many more things than I've described here. Read more in the Adobe LiveDocs documentation:

 

Downloading a file

The FileReference class lets you add the ability to upload and download files. The upload and download behavior is no different than in HTML. In HTML you would download a file by using the following code:

<a href="http://www.test.com/myfile.zip" >Download</a>

In Flex you would download a file using this code:

FileDownload.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Download File" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   
   <mx:Button x="10" y="75" label="Download HTML Component" click="{download()}"/>
   
   <mx:Script>
      <![CDATA[
         public function download():void {
            // pass in url to file or php proxy
            // create a new file reference instance
            var request:URLRequest = new URLRequest("http://www.drumbeatinsight.com/examples/html/HTMLComponent1.0.0.zip");
            var fileRef:FileReference = new FileReference();
            fileRef.download(request);
         }
      ]]>
   </mx:Script>
</mx:Application>


You can do much more with the FileReference class including specifying the filename and extension, specifying a URL, passing URL parameters to the URL, and more. Read more in the Adobe LiveDocs documentation:

Uploading a file to PHP

The FileReference class also lets you handle uploads. This class offers many advantages over traditional HTML file uploads including a single dialog box for multiple file upload, progress information, and file upload complete events, file upload filter types, and more. In HTML you would use the following code to upload a file:

<form method="post" enctype="multipart/form-data" action="upload.php"> 
   File: <input type="file" name="filename"/> <input type="submit" value="Upload"/> 
</form> 

To upload a file in Flex you would use the following code.

FileUpload.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="File Upload" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   
   <mx:Button x="10" y="59" label="Upload" click="{upload()}"/>
   
   <mx:Script>
      <![CDATA[
      import flash.events.DataEvent;
      
      public var fileRef:FileReference = new FileReference();
      
      public function upload():void {
         // listen for the file selected event
         // listen for the upload complete event
         fileRef.addEventListener(Event.SELECT, selectHandler);
         fileRef.addEventListener(Event.COMPLETE, completeHandler);
         fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA   , uploadCompleteHandler);
         
         // browse for the file to upload
         // when user selects a file the select handler is called
         try {
             var success:Boolean = fileRef.browse();
         }
         catch (error:Error) {
             trace("Unable to browse for files.");
         }
      }
      
      // when a file is selected you upload the file to the upload script on the server
      public function selectHandler(event:Event):void {
          var request:URLRequest = new URLRequest("upload.php")
          try {
             // upload file
              fileRef.upload(request);
              textarea1.text = "uploading " + fileRef.name + "...";
          }
          catch (error:Error) {
              trace("Unable to upload file.");
          }
      }
      
      // dispatched when file has been given to the server script. does not receive a response from the server
      public function completeHandler(event:Event):void {
          trace("file uploaded complete");
      }
      
      // dispatched when file has been uploaded to the server script and a response is returned from the server
      // event.data contains the response returned by your server script
      public function uploadCompleteHandler(event:DataEvent):void {
          trace("uploaded... response from server: \n" + String(event.data));
          textarea1.text += event.data as String;
      }
      
      ]]>
   </mx:Script>
   
   <mx:TextArea x="10" y="89" width="327" height="134" id="textarea1"/>

</mx:Application>


file_upload.php:

<?php
   // you send messages back to the client
   // and then move the file from php's temporary upload directory to your local directory
   // Filedata is the default name used in uploading
   echo "\nReceiving upload...\n";
   echo "temporary file name = " . $_FILES['Filedata']['tmp_name']."\n";
   echo "file name = " . $_FILES['Filedata']['name']."\n";
   echo "file size = " . $_FILES['Filedata']['size']."\n";
   echo "attempting to move file...\n";
   move_uploaded_file($_FILES['Filedata']['tmp_name'], "./".$_FILES['Filedata']['name']);
   echo "file moved\n";
?>


Note: Filter the files that you receive on the server before using this example to prevent someone from uploading a script. An example of this is available in the Adobe LiveDocs Help documentation: Working with file upload and download.

Read more in the Adobe LiveDocs documentation:

 

Login example application

Most likely you will have an application that requires users to authenticate their credentials on the server to see certain information. Typically you use a login form to access secure data. When a user logs in they should be able to access and see additional information.

In this example you will create a simple login application. A visitor will be able to see the home page. Once they have logged in, they will be able to see an additional view. In addition, a user that is logged in will be able to access additional data from the server. The application will also timeout if there is no keyboard or mouse activity for 10 seconds. When this happens, you automatically log out the user and change to the visitor state. Because of the nature of the Flex framework, if the user logs back in they will not lose any data since you keep it in memory until the application is closed. Very nice!

Here is the Flex code:

LoginApplication.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">

   <mx:Label x="10" y="10" text="Login Application" fontSize="20" fontWeight="bold"/>
   <mx:HRule y="49" right="10" left="10"/>
   
   <mx:Script>
      <![CDATA[
      // import the classes you are going to use
      import mx.controls.Alert;
      import mx.events.FlexEvent;
      import mx.managers.SystemManager;
      import mx.rpc.events.FaultEvent;
      import mx.events.ItemClickEvent;
      import mx.collections.ArrayCollection;
      import mx.rpc.events.ResultEvent;
      
      // store the user access level after user logs in
      private var userAccess:String = "";
      // define roles to compare against
      private var roles:String = "user";
      
      // these are the menus that you use to show the user.
      // Bindable lets you bind to this variable
      // ArrayCollections are a very powerful Array with additional features you can use later
      [Bindable]
      private var guestMenu:ArrayCollection = new ArrayCollection(["home"]);
      [Bindable]
      private var userMenu:ArrayCollection = new ArrayCollection(["home","user"]);
      private var timeoutTotal:Number = 0;
      private var timeoutLastCall:Number;
      public var timeout:Number = 10000; // timeout after ten seconds
      public var sessionExpired:Boolean = false;
      public var enableTimeout:Boolean = true;
      private var user2:String = "";
      
      // you could convert this into a reusable class
      // you are not going to for simplicity
      private function timeoutHandler(event:FlexEvent):void {
         // get current time
         var curTime:int = getTimer();
         var timeDiff:int = 0;
         if (isNaN(timeoutLastCall)) {
            timeoutLastCall = curTime;
         }
         
         timeDiff = curTime - timeoutLastCall;
         timeoutLastCall = curTime;
         
         // if time has passed since the idle event you assume user is interacting
         // reset time total - otherwise increment total idle time
         if (timeDiff > 1000) {
            timeoutTotal = 0;
         }
         else {
            // update time
            // the status field will not be updated unless the application is idle
            // it is only display a countdown for learning purposes
            timeoutTotal += 100;
            status.text = "Timeout in " + String(Number((timeout - timeoutTotal)/1000).toFixed(0)) + " seconds";
         }
         
         
         // if the total time of inactivity passes your timeout
         // and the session already hasn't expired then logout user
         if (timeoutTotal > timeout && !sessionExpired) {
            // logout user
            // or set flag
            sessionExpired = true;
            status.text = "timeout threshold has been reached";
            sessionTimeoutHandler();
         }
      }
      
      // when the application times out due to inactivity you call this function
      private function sessionTimeoutHandler():void {
         logout();
         var message:String = "Session Expired due to inactivity!\nPlease log back in to resume";
         Alert.show(message, "Session Expired", Alert.OK);
         // remove idle listener
         var sysMan:SystemManager = Application.application.systemManager;
         sysMan.removeEventListener(FlexEvent.IDLE, timeoutHandler);
      }
      
      // this is the function that receives a response from the server after clicking submit
      // event.result contains the string response from the server
      // you check if the user has access to any of the roles
      private function handleLogin(event:ResultEvent):void {
         userAccess = event.result as String;
         trace("handleLogin result data = "+userAccess);
         
         if (userAccess.indexOf(roles)>-1) {
            // login success
            // hide failed login message, set login form to success state, show user menu
            loginFailedText.visible = false;
            loginStack.selectedChild = loginSuccess;
            linkBar.dataProvider = userMenu;
            sessionExpired = false;
            viewStack.selectedChild = viewStack.parentApplication[String(userMenu.getItemAt(1))];
            var sysMan:SystemManager = Application.application.systemManager;
            if (enableTimeout) {
               sysMan.addEventListener(FlexEvent.IDLE, timeoutHandler);            }
         }
         else {
            // show failed login message, show guest menu
            loginFailedText.visible = true;
            linkBar.dataProvider = guestMenu;
         }
      }
      
      // this function is run when a user clicks a menu item
      // if you wanted you could make this more robust here
      // check if the session has expired on the server, etc
      // if it fails you can move the user back to the guest view or alert them to log in again
      private function handleLinkBar(event:ItemClickEvent):void {
         viewStack.selectedChild = viewStack.parentApplication[String(event.label)];
      }
      
      // handles when user manually destroys the session
      private function handleLogout(event:ResultEvent):void {
         textarea1.text = "You have manually destroyed the session. Try to get data from the server.";
      }
      
      // handles logging out for other functions
      private function logout():void {
         loginStack.selectedChild = loginForm;
         loginFailedText.visible = false;
         linkBar.dataProvider = guestMenu;
         viewStack.selectedChild = viewStack.parentApplication[guestMenu[0]];
         username.text = "";
         password.text = "";
      }
      
      // handles when something goes wrong with your service call
      private function handleFault(event:FaultEvent):void {
         // for stream error 2032 see http://www.judahfrangipane.com/blog/?p=87
         trace("fault = "+event.message);
         loginStack.selectedChild = loginForm;
         errorText.visible = true;
         errorText.text = "Could not connect to the server. Check the url. \nFault " + event.fault;
         linkBar.dataProvider = guestMenu;
         viewStack.selectedChild = viewStack.parentApplication[guestMenu[0]];
      }
      ]]>
   </mx:Script>
   
   <mx:Label id="loginFailedText" text="Login failed!" fontWeight="bold" color="#000000" right="10" y="10" visible="false"/>
   
   <mx:HTTPService id="loginService" url="http://www.flexcapacitor.com/examples/php/login.php" method="POST" resultFormat="text" 
      result="{handleLogin(event)}" fault="{handleFault(event)}">      <mx:request>
         <username>{username.text}</username>
         <password>{password.text}</password>
      </mx:request>
   </mx:HTTPService>
   
   <mx:HTTPService id="logoutService" url="http://www.flexcapacitor.com/examples/php/logout.php" resultFormat="text" 
      result="{handleLogout(event)}" fault="{handleFault(event)}"/>
      
   <mx:HTTPService id="getDataService" url="http://www.flexcapacitor.com/examples/php/secure_data.php" resultFormat="text" 
      result="{textarea1.text = String(event.result);}" fault="{handleFault(event)}"/>
   
   <mx:ViewStack id="loginStack" y="61" right="10" height="30" width="400" paddingLeft="5">
      <mx:HBox id="loginForm" label="Login Form" verticalAlign="middle">
         <mx:Label text="Username"/>
         <mx:TextInput id="username" width="80" borderStyle="solid" text="user"/>
         <mx:Label text="Password"/>
         <mx:TextInput id="password" width="80" displayAsPassword="true" borderStyle="solid" text="password"
            enter="{loginService.send()}"/>
         <mx:Button label="Submit" click="{loginService.send()}"/>
      </mx:HBox>
      <mx:HBox id="loginSuccess" label="Login Success" verticalAlign="middle" horizontalAlign="right">
         <mx:Label text="Welcome user, you are logged in!" id="welcomeText"/>
         <mx:Button label="Logout" click="{logout()}"/>
      </mx:HBox>
   </mx:ViewStack>
   
   <mx:ViewStack id="viewStack" right="10" left="10" top="100" bottom="20">
      <mx:Canvas id="home" label="home" width="100%" height="100%" backgroundColor="#f6f6f6">
         <mx:Label x="10" y="10" text="Guest View"/>
         <mx:Label x="10" y="36" text="This view is visible to everyone"/>
         <mx:Text visible="false" left="10" right="10" x="10" y="62" text="Label" color="#ff0000" fontWeight="bold" id="errorText"/>
      </mx:Canvas>
      <mx:Canvas id="user" label="user" width="100%" height="100%" backgroundColor="#f6f6f6">
         <mx:Label x="10" y="10" text="User View"/>
         <mx:Label x="10" y="36" text="This view is visible only to logged in users. "/>
         <mx:Button x="10" y="62" label="Get Authenticated Data" id="getUserData" click="getDataService.send();"/>
         <mx:Button x="180" y="62" label="Destroy Session" id="destroySession" click="logoutService.send()"/>
         <mx:TextArea x="10" y="92" width="312" height="150" id="textarea1"/>
         <mx:Text x="330" y="62" text="Get data that is only available if you are part of the "user" group. Destroy the session and test it again to see authenticated data is no longer available." width="295"/>
      </mx:Canvas>
   </mx:ViewStack>
   
   <mx:LinkBar id="linkBar" x="10" y="63" dataProvider="{guestMenu}" itemClick="handleLinkBar(event)" backgroundColor="#ffffff" backgroundAlpha="0.41">
   </mx:LinkBar>
   <mx:Label y="21" id="status" right="20"/>

</mx:Application>

login.php:

<?php
   // send a response back to the client
   //print "\n You submitted the following form information:\n";
   foreach ($_REQUEST as $k => $v) {
      //print "\n   $k = $v";
   }
   
   if( $_REQUEST["username"]=="user" && $_REQUEST["password"]=="password") {
      //echo "Login successful";
      session_start();
      $_SESSION['group'] = 'user';
      echo $_SESSION['group'];
   }else{
      echo "failed";
   }
?>

secure_data.php:

<?php
   session_start();
   
   if ($_SESSION['group']=="user") {
      print "<?xml version='1.0' encoding='ISO-8859-1' ?>";
      print "<rows>";
      print "<row>";
      print "<firstname>john</firstname>";
      print "<lastname>smith</lastname>";
      print "</row>";
      print "<row>";
      print "<firstname>jane</firstname>";
      print "<lastname>smith</lastname>";
      print "</row>";
      print "</rows>";
   }
   else {
      echo "Session expired...";
   }
?>

logout.php:

<?php
   session_start();
   @session_destroy();
   $_SESSION['group'] = '';
   echo "success";
?>



In this example, you have created two ViewStack components. The first contains your login form. When the user logs in they are taken to the logged in view. The other ViewStack component contains the application content. The first view is the home page view. Every user can see this page. The second view is the user view. When the user has logged in successfully, a second navigational menu appears and the user view appears. Users can switch back and forth between views.

The second view is a form that gets data from the server. When a user clicks the Get Authenticated Data button, a service call is sent to the server. If the user has a successfully logged in session on the server they will receive sample data. If the session does not exist on the server, a message is sent back asking the user to log in again.

There is one more thing added  to this application: a client-side timeout mechanism. Once the user logs in you listen for the Application IDLE event. If the application has been idle for longer than your timeout value (in this example you've set it to 10 seconds), you log out the user, move the user back to the visitor state, and show the user a message that he or she is logged out. If the user logs back in, he/she will see all the form data because the form data is not destroyed when the user switches views (states). On some applications you may want to clear the form data if it becomes irrelevant. With Flex these type of choices are up to you.

Note: Notice that the script block is at the top. I do this because as you add components to the Design view, Flex Builder adds those component definitions at the end of the MXML file. In MXML, the order in which you add components is the order in which they are stacked in the z-index coordinate space. So if you add two images into your MXML code, the image tag towards the bottom of the file is added after and on top of the first image. 

There is more going on in this example than in the previous examples. This section has covered the main aspects of this topic, but additional comments have been placed in the code. Also, read more in the Adobe LiveDocs documentation:

Populating a DataGrid with XML from PHP

A common task is populating a DataGrid with XML data. In this example you will submit data to the server, and display the returned XML in a DataGrid.

Here is the Flex code:

PopulatingDataGridWithXML.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="#f6f6f6" backgroundGradientColors="[#f6f6f6, #bbbbbb]">
   
   <!-- Script -->
   <!-- Our result handler functions get any value returned from the server -->
   <mx:Script>
      <![CDATA[
         import mx.collections.ArrayCollection;
         // you import the event classes for strong typing
         import mx.rpc.events.ResultEvent;
         import mx.rpc.events.FaultEvent;
         
         
         public function handleResultXML(event:ResultEvent):void {
            // the result object is your xml root
            lastResultValue.text = "Result:\n" + event.result;
            // you get the row nodes of your result object
            // the data of the dataprovider populates the component
            myDataGrid.dataProvider = event.result.row;
         }
         
         // this function is called when you get an error from the server
         public function handleFault(event:FaultEvent):void {
            lastResultValue.text = "Fault: " + event.fault.faultDetail;
         }
      ]]>
   </mx:Script>
   
   <!-- Data Communications -->
      <!-- The url is the page you post to -->
      <!-- In the request object you add your name and value pairs -->
      <!-- The curly brackets surrounding "username.text" get the value of username.text -->
      <!-- Note: The curly brackets are also used for databinding where supported -->
   
   <!-- Note: We set the resultFormat to E4X to automatically convert your return string to an XML object with E4X support -->
   <mx:HTTPService id="myServiceXML" url="http://www.flexcapacitor.com/examples/php/datagrid_xml.php" 
      method="POST" result="handleResultXML(event)" fault="handleFault(event)"
      useProxy="false" resultFormat="e4x"/>
   
   <!-- Layout -->
   <mx:Label x="10" y="10" text="Populate DataGrid with XML" fontSize="20" fontWeight="bold"/>
   <mx:HRule x="10" y="49" width="80%"/>
   <mx:Button id="submit0" x="10" y="73" label="Get XML" click="myServiceXML.send()"/>
   <mx:Label x="10" y="228" text="Result"/>
   <mx:DataGrid id="myDataGrid" x="10" y="114" width="374" height="106">
      <mx:columns>
         <mx:DataGridColumn headerText="First Name" dataField="firstname"/>
         <mx:DataGridColumn headerText="Last Name" dataField="lastname"/>
      </mx:columns>
   </mx:DataGrid>
   <mx:TextArea x="10" y="244" width="374" height="102" id="lastResultValue"/>

</mx:Application>


datagrid_xml.php:

<?php
   print "<?xml version='1.0' encoding='ISO-8859-1' ?>";
   print "<rows>";
   print "<row>";
   print "<firstname>john</firstname>";
   print "<lastname>smith</lastname>";
   print "</row>";
   print "<row>";
   print "<firstname>jane</firstname>";
   print "<lastname>smith</lastname>";
   print "</row>";
   print "</rows>";
?>


Read more in the Adobe LiveDocs documentation:

Bringing it up a notch

Flex provides many mechanisms that offer many more features and benefits for communicating with PHP beyond the HTTPService class. From the documentation:

Flex provides several solutions for data delivery to the client. It delivers data through runtime services that invoke methods on PHP classes, sends proxy requests to web services or HTTP servers.

Using the WebService component enables you to use a SOAP-based approach, but it does not always yield the best performance. Also, the additional XML with the SOAP encoding requires more overhead than AMF does.

AMF is a proprietary protocol for object remoting. It is much faster than HTTP service calls because the message is compressed natively. The data is also serialized so you can work directly with objects. AMF is part of the Remote Procedure Call group of services. To quote Patrick Mineault:

RPC (Remote Procedure Call) is a way to communicate data between a client and a server. You call a method on a local object with various parameters, set a callback, and receive a result. You don't have to worry about how you're going to send and receive the data. The server and the client, say PHP and Flash, agree on a common way of describing method calls and complex data. The implementation details are abstracted away so that it looks as though you're calling a local method.

For using the AMF with PHP you can use AMFPHP or WebORB.

AMFPHP

AMFPHP is an RPC toolkit for PHP. It allows seamless communication between PHP and the following technologies:

  • Flash and Flex with Remoting
  • JavaScript and Ajax with JSON
  • XML clients with XML-RPC

AMFPHP lets you focus on features instead of implementation details. Testing remote services can be tricky, so AMFPHP has a built-in service browser which lets you test your services before you start writing the front end, and allows you to generate code for various clients.

WebORB for PHP

Midnight Coders' WebORB is a platform enabling development, deployment, and runtime execution of rich Internet applications. The product facilitates connectivity between rich clients created with Flex, Flash, or Ajax and server-side applications developed with .NET, Java, Ruby on Rails, PHP, or XML web services:

  • Open-source alternative to AMFPHP
  • Dual licensing: GPL and commercial licenses available
  • Implements AMF0, AMF3, and Flex Data Services (Flex RPC)
  • Full implementation of the Flex Data Management Services functionality will be available in a commercial edition

Both have been strong advantages and have been used successfully in many commercial projects. AMFPHP is easier to use, offers a very useful service browser for testing and organizing services, and has extensions to increase speed. WebORB for PHP is slightly more complex but provides additional Flex Data Services features.

Where to go from here

Flex has many more features that are beyond the scope of this tutorial. One of the most comforting facts about Flex is that is written from the ground up for developers by developers who have worked in the industry for many years and are actively listening to the community to make it better. As you discover new time saving features in Flex this fact becomes clear again and again. Many additional resources are available to PHP developers for learning Flex and I have included a list of them below.

I hope this article has helped you get started with Flex.

Check out the following resources to get started:

About the author

Judah Frangipane is a software architect who has worked in the web industry since 1996. During that time he has worked at Roxio, Parsons and T8DESIGN. He is currently employed in the IT dept at Yellow Book. He has been working with Flash since Flash MX and Flex 1.5 and has created over 20 commercial Flash and Flex components.

Judah is also active in the Flash community. He is the manager of the Minnesota Flash User Group. He advocates good design and OOP principles. He believes that programming could be redesigned with a graphic user interface. One of his goals is to help with that vision. In his free time he enjoys teaching, reading, writing, going to rock shows, and doing the macarana.