Subscribe: Posts / Comments / Email


RSS

Adobe Flex – Presentation & Cookbook

Fri, Sep 19, 2008

Air, Flex, Snippets, Tutorials

Here is a little thing that I made up for people using Flex/Flash and amfphp a little cheat sheet to use as a reference.

I have two different versions of this:

  1. Is use without any framework and without a services-config.xml file in the compiler.
  2. Second version is for use with the Cairngorm Framework.

These example are snippets from my Flash Remoting presentation and Snippr Air application. Source files will be provided at the end.

Table Of Contents:

  1. Installation Setup
  2. Service Proxy for managing calls
  3. Value Objects
  4. Model Locator
  5. Getting Data
  6. Sending Data
  7. Removing Data
  8. Views
  9. Source

 

Amfphp Installation Setup

Server folder structure:

amfphp_root

Snippets MySQL Table:

 

   1: CREATE TABLE `snippets` (                                 
   2:            `snippet_id` int(11) NOT NULL auto_increment,           
   3:            `snippet_title` varchar(255) NOT NULL,                  
   4:            `snippet_code` text NOT NULL,                           
   5:            `snippet_type` varchar(3) default 'as',                 
   6:            `snippet_created` timestamp NULL default NULL,          
   7:            `snippet_user` varchar(200) NOT NULL,                   
   8:            PRIMARY KEY  (`snippet_id`)                             
   9:          ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1  

 

Service Proxy

Here is how you create a Service Proxy file that handles all of your calls, this makes all calls to and from amfphp really easy.

Use in SnipprService.as

   1: package com.jonniespratley.snippr.services
   2: {
   3:     import com.jonniespratley.snippr.model.ModelLocator;
   4:     import com.jonniespratley.snippr.vo.SnippetVO;
   5:     
   6:     import flash.net.NetConnection;
   7:     import flash.net.Responder;
   8:     
   9:     import mx.collections.ArrayCollection;
  10:     import mx.controls.Alert;
  11:     
  12:     /**
  13:      * This file is for use without! using the services-config.xml file 
  14:      * @author Jonnie
  15:      * 
  16:      */    
  17:     public class SnipprService
  18:     {
  19:         private static var _service:NetConnection;
  20:         private var model:ModelLocator = ModelLocator.getInstance();
  21:         
  22:         //Here we are creating a new connection to our amfphp service, when this is instantiated, it connects to our service
  23:         public function SnipprService()
  24:         {
  25:             _service = new NetConnection();
  26:             _service.connect( "http://YOURSERVER.COM/amfphp/gateway.php" );
  27:         }        
  28:         
  29:         
  30:         /* ***************************************
  31:         *** Service Calls
  32:         *****************************************/
  33:         
  34:         //Here we are calling the getSnippets on our server (amfphp) and setting the result and fault handlers
  35:         public function getSnippets():void
  36:         {
  37:             _service.call( "snippr.SnipprService.getSnippets", new Responder( snippetResultHandler, snipprFaultHandler ) );
  38:         }
  39:         
  40:         //We take one argument here, and that is a snippet, because our server (amfphp) is expecting a snippetVO
  41:         public function saveSnippet( snippet:SnippetVO ):void
  42:         {
  43:             _service.call( "snippr.SnipprService.saveSnippet", new Responder( snippetSavedHandler, snipprFaultHandler ), snippet );
  44:         }
  45:         
  46:         //We take one argument here, and that is the id of the snippet we are wanting to remove
  47:         public function removeSnippet( snippet_id:uint ):void
  48:         {
  49:             _service.call( "snippr.SnipprService.removeSnippet", new Responder( snippetRemoveHandler, snipprFaultHandler ), snippet_id );
  50:         }
  51:         
  52:         
  53:         /* ***************************************
  54:         *** Result and Fault Handlers
  55:         *****************************************/
  56:         
  57:         //Here we are handling the result coming back as an array of snippets, then we add our snippets to our model        
  58:         private function snippetResultHandler( data:Array ):void
  59:         {            
  60:             model.snippetCollection = initVO( data );
  61:         }
  62:         
  63:         //Helper for the result
  64:         private function initVO( resultArray:Array ):ArrayCollection
  65:         {
  66:             var tempArray:ArrayCollection = new ArrayCollection();
  67:             
  68:             for ( var s:String in resultArray )
  69:             {
  70:                 tempArray.addItem( new SnippetVO( resultArray[s] ) );
  71:                 
  72:             }
  73:             return tempArray;
  74:         }
  75:         
  76:         //Here we are handling the result and adding it to the value of serviceResponse in our model
  77:         private function snippetSavedHandler( data:Object ):void
  78:         {
  79:             ModelLocator.getInstance().serviceResponse = data.toString();
  80:         }
  81:         
  82:         /*
  83:         Here we are handling the result that is being returned, which will be the id of the removed snippet, and 
  84:         removing it from our model, at the snippet index
  85:         */
  86:         private function snippetRemoveHandler( data:Object ):void
  87:         {
  88:             getSnippets();
  89:         }
  90:         
  91:         //Here we are alerting the user that there was an error connection to our server
  92:         private function snipprFaultHandler( fault:Object ):void
  93:         {
  94:  
  95:             Alert.show( "There was an error connecting to the server.", "Snippr Service Error" );
  96:         }        
  97:     }        
  98: }

 

Use in SnipprService.php:

   1: <?php
   2: /** *******************************************************************
   3:  * Copyright (c) 2008 Jonnie Spratley. All Rights Reserved.
   4:  *
   5:  * THE SOFTWARE IS PROVIDED "AS" IS, WITHOUT WARRANTY OF ANY KIND,
   6:  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   7:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   8:  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
   9:  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  10:  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  11:  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  12:  *
  13:  * @author  Jonnie Spratley
  14:  * @contact jonniespratley@gmail.com
  15:  * @internal
  16:  ******************************************************************* */
  17:  
  18: class SnipprService
  19: {
  20:     //Specify our output temp directory
  21:     var $output_dir = "screenshots";
  22:     //Specify our output url 
  23:     var $server_url = "http://snippr.jonniespratley.com/";
  24:     //Specify our table name
  25:     private $table = "snippets";
  26:         
  27:     public function SnipprService()
  28:     {
  29:         mysql_connect("localhost", "spratley_guest", "guest");
  30:         mysql_select_db("spratley_snippr") ;    
  31:     }
  32:  
  33:  
  34:     private function mapRecordSet( $recordset )
  35:     {
  36:         require_once( "../vo/SnippetVO.php" );
  37:         $list = array();
  38:         
  39:         while( $data = mysql_fetch_array( $recordset ) )
  40:         {
  41:             $vo = new SnippetVO();
  42:             $vo->mapObject( $data );
  43:             array_push( $list, $vo );
  44:         }        
  45:         return $list;    
  46:     }    
  47:  
  48:  
  49:     public function getSnippets()
  50:     {
  51:         //We must specify our vo, because we need to map correctly
  52:         require_once( "../vo/SnippetVO.php" );
  53:         
  54:         $sql = mysql_query( "SELECT * FROM ". $this->table. "" );
  55:         
  56:         $result = array();
  57:  
  58:         while( $snip = mysql_fetch_array( $sql ) )
  59:         {
  60:             //Create a new snippet vo
  61:             $snippet = new SnippetVO();
  62:             $snippet->snippet_id             = $snip[snippet_id];
  63:             $snippet->snippet_title         = $snip[snippet_title];
  64:             $snippet->snippet_code             = $snip[snippet_code];
  65:             $snippet->snippet_type             = $snip[snippet_type];
  66:             $snippet->snippet_created         = $snip[snippet_created];
  67:             $snippet->snippet_user             = $snip[snippet_user];
  68:             //Result is a snippet
  69:             $result[] = $snippet;
  70:         }
  71:         //Print out the result
  72:         return $result;
  73:     }
  74:  
  75:     //This is used for returning the created or updated snippet for flex
  76:     public function getOne( $id )
  77:     {
  78:         $rs = mysql_query( "SELECT * FROM ".$this->table." WHERE snippet_id = ".$id );
  79:         //Map the recordset to our vo
  80:         $list = $this->mapRecordSet( $rs );
  81:         //Return our vo
  82:         return $list[ 0 ];        
  83:     }
  84:     
  85:     //Creates a new snippet
  86:     public function saveSnippet( $snippet )
  87:     {
  88:         require_once( "../vo/SnippetVO.php" );
  89:         //Check to see if the snippet has an id of 0
  90:         if ( $snippet[snippet_id] == 0 ) 
  91:         {
  92:         $query = "INSERT INTO ".$this->table."
  93:                                 ( snippet_title,
  94:                                 snippet_code,
  95:                                 snippet_type,
  96:                                 snippet_created,
  97:                                 snippet_user )        
  98:                                 VALUES (
  99:                                 '".mysql_real_escape_string($snippet[snippet_title])."',
 100:                                 '".mysql_real_escape_string($snippet[snippet_code])."',
 101:                                 '".mysql_real_escape_string($snippet[snippet_type])."',
 102:                                 '".mysql_real_escape_string($snippet[snippet_created])."',
 103:                                 '".mysql_real_escape_string($snippet[snippet_user])."')";
 104:         if( !mysql_query( $query ) ) 
 105:         {        
 106:             return false;
 107:         }                
 108:             return $this->getOne( mysql_insert_id() );
 109:             
 110:             } else {
 111:                     $id = $snippet[snippet_id];
 112:             
 113:                     $query = "UPDATE ".$this->table." SET 
 114:                     snippet_title = '".mysql_real_escape_string($snippet[snippet_title])."',
 115:                     snippet_code = '".mysql_real_escape_string($snippet[snippet_code])."',
 116:                     snippet_type = '".mysql_real_escape_string($snippet[snippet_type])."',
 117:                     snippet_created = '".mysql_real_escape_string($snippet[snippet_created])."',
 118:                     snippet_user = '".mysql_real_escape_string($snippet[snippet_user])."'
 119:             
 120:                     WHERE snippet_id =". $id;
 121:                 
 122:                     if( !mysql_query( $query ) )
 123:                     {        
 124:                         return false;        
 125:                     }                
 126:                     //Return the created snippet
 127:                     return $this->getOne( $id );                
 128:                 }                
 129:     }
 130:  
 131:     public function removeSnippet($id)
 132:     {
 133:         $sql = mysql_query( "DELETE FROM ".$this->table." WHERE snippet_id = ".$id );
 134:         
 135:         if( !$sql )
 136:         {
 137:         //    trigger_error("Unable to delete Snippets", E_USER_ERROR);
 138:             return "There was an error removing this snippet";
 139:         }
 140:         else return $id;        
 141:     }      
 142:       
 143:     /** *******************************************************************************
 144:     Save image from the given bytearray and return the path of the saved image
 145:     ***********************************************************************************/
 146:    public function takeScreenshot( $byteArray, $filename, $compressed = false )
 147:     {
 148:         if( !file_exists( $this->output_dir ) || !is_writeable( $this->output_dir ) )
 149:             trigger_error ( "Please create a directory first with write access", E_USER_ERROR );
 150:  
 151:         $data = $byteArray->data;
 152:  
 153:         if( $compressed )
 154:         {
 155:             if( function_exists( gzuncompress ) )
 156:             {
 157:                 $data = gzuncompress( $data );
 158:             } else {
 159:                 trigger_error ( "GZip method does not exists, please send uncompressed data", E_USER_ERROR );
 160:             }
 161:         }
 162:         //Put the File in the Directory, and Rename it, what the User wanted the Name to be.
 163:         file_put_contents( $this->output_dir . "/$filename", $data );
 164:        
 165:        return $this->server_url . $this->output_dir . "/$filename";
 166:     }
 167: }
 168: ?>

 

The Model Locator

Here is our ModelLocator.as file that will hold all of our data.

   1: /** *******************************************************************
   2:  * Snippr AIR
   3:  * Copyright (c) 2008 Jonnie Spratley. All Rights Reserved.
   4:  *
   5:  * THE SOFTWARE IS PROVIDED "AS" IS, WITHOUT WARRANTY OF ANY KIND,
   6:  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   7:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   8:  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
   9:  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  10:  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  11:  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  12:  *
  13:  * @author  Jonnie Spratley
  14:  * @contact jonniespratley@gmail.com
  15:  * @internal
  16:  ******************************************************************* */
  17: package com.jonniespratley.snippr.model
  18: {
  19:     import com.adobe.cairngorm.model.IModelLocator;
  20:     import com.jonniespratley.snippr.vo.SnippetVO;
  21:     
  22:     import mx.collections.ArrayCollection;
  23:  
  24:     /**
  25:      * The Model Locator pattern is a singleton and was created purely 
  26:      * to be used with Flex/Air application development. In this case, 
  27:      * a singleton is a design pattern that allows for only one 
  28:       * instance of the Model Locator to be present within your a
  29:      * application's memory. Any data that you think is required to live 
  30:      * in the application's state should be stored inside the Model Locator. 
  31:      * The Model Locator creates a central area where all the states 
  32:      * can be held in your Flex/Air application. This allows the view 
  33:      * components to bind to the model or state of the application 
  34:      * and keep everything up to date.
  35:      *
  36:      */
  37:     
  38:     [Bindable]
  39:     public final class ModelLocator implements IModelLocator
  40:     {
  41:         /**
  42:          * Defines the Singleton instance of the Application ModelLocator
  43:          */
  44:         private static var instance:ModelLocator;
  45:  
  46:         public function ModelLocator()
  47:         {
  48:             if( instance != null ) throw new Error( "Error: Singletons can only be instantiated via getInstance() method!" );
  49:  
  50:             ModelLocator.instance = this;
  51:         }
  52:  
  53:         /**
  54:          * Returns the Singleton instance of the Application ModelLocator
  55:          */
  56:         public static function getInstance():ModelLocator
  57:         {
  58:             if( instance == null )    instance = new ModelLocator();
  59:  
  60:             return instance;
  61:         }
  62:  
  63:         // *********** Public Variables that our views are going to bind to ************** 
  64:         
  65:         /* Snippet Collection for all lists/datagrids */
  66:         public var snippetCollection:ArrayCollection;
  67:         
  68:         /* The selected snippet */
  69:         public var selectedSnippet:SnippetVO;
  70:                 
  71:         public var serviceResponse:String = "";
  72:  
  73:         // ***************** Public Static Variables for Work View States ************* 
  74:         public var workflowState:uint = 0;
  75:         public static const LOGIN_SCREEN:uint = 0;
  76:         public static const WELCOME_SCREEN:uint = 1;
  77:     }
  78: }

 

Value Objects

Code for both server and client are provided as follows.

Use in SnippetVO.as

   1: package com.jonniespratley.snippr.vo
   2: {    
   3:     [RemoteClass(alias="vo.SnippetVO")]
   4:     
   5:     /**
   6:      * VOs are used to create a layer of business objects that can be 
   7:      * transferred between tiers, instead of using records, results sets, and datasets.
   8:      */
   9:     [Bindable]
  10:     public class SnippetVO
  11:     {
  12:         public var snippet_id:int;
  13:         public var snippet_title:String;
  14:         public var snippet_code:String;
  15:         public var snippet_type:String;
  16:         public var snippet_created:String;
  17:         public var snippet_user:String;        
  18:         
  19:         /**
  20:          * Helper function for building the data. 
  21:          * @param source
  22:          */        
  23:         public function SnippetVO( source:Object = null )
  24:         {
  25:             if ( source != null )
  26:             {
  27:                 for ( var item:String in source )
  28:                 {
  29:                     try 
  30:                     {
  31:                         this[item] = source[item];
  32:                     }
  33:                     catch ( error:Error )
  34:                     {
  35:                         throw new Error( "SnippetVO: " + error );
  36:                     }
  37:                 }
  38:             }
  39:         }
  40:     }
  41: }

 

Use in SnippetVO.php

   1: <?php
   2: /** *******************************************************************
   3:  * @author  Jonnie Spratley
   4:  * @contact jonniespratley@gmail.com
   5:  * @internal
   6:  ******************************************************************* */
   7: class SnippetVO 
   8: {
   9:     //AMFPHP only
  10:     var $_explicitType="com.jonniespratley.snippr.vo.SnippetVO";
  11:     
  12:     public $snippet_id;
  13:     public $snippet_title;
  14:     public $snippet_code;
  15:     public $snippet_type;
  16:     public $snippet_created;
  17:     public $snippet_user;
  18:     
  19:     public function SnippetVO(){}
  20:     
  21:     //Maps the data to the specific table names
  22:     public function mapObject( $data )
  23:     {        
  24:         $this->snippet_id = $data[snippet_id];
  25:         $this->snippet_title = $data[snippet_title];
  26:         $this->snippet_code = $data[snippet_code];
  27:         $this->snippet_type = $data[snippet_type];
  28:         $this->snippet_created = $data[snippet_created];
  29:         $this->snippet_user = $data[snippet_user];
  30:     }
  31: }
  32: ?>

 

Getting Data

Code for both server and client are provided as follows.

Use in SnippetList.mxml
 
   1: //Here we are calling the getSnippets on our server (amfphp) and setting the result and fault handlers
   2: public function getSnippets():void
   3: {
   4:     var _service:NetConnection = new NetConnection();
   5:     _service.connect( "http://localhost/Snippr/amfphp/gateway.php" );
   6:     _service.call( "snippr.SnipprService.getSnippets", 
   7: new Responder( snippetResultHandler, snipprFaultHandler ) );
   8: }

 
Use in SnippetService.php
   1: public function getSnippets()
   2: {
   3:     //We must specify our vo, because we need to map correctly
   4:     require_once( "../vo/SnippetVO.php" );
   5:     
   6:     $sql = mysql_query( "SELECT * FROM ". $this->table. "" );
   7:  
   8:     $result = array();
   9:  
  10:     while( $snip = mysql_fetch_array( $sql ) )
  11:     {
  12:         //Create a new snippet vo
  13:         $snippet = new SnippetVO();
  14:         $snippet->snippet_id             = $snip[snippet_id];
  15:         $snippet->snippet_title         = $snip[snippet_title];
  16:         $snippet->snippet_code             = $snip[snippet_code];
  17:         $snippet->snippet_type             = $snip[snippet_type];
  18:         $snippet->snippet_created         = $snip[snippet_created];
  19:         $snippet->snippet_user             = $snip[snippet_user];
  20:         //Result is a snippet
  21:         $result[] = $snippet;
  22:     }
  23:     //Print out the result
  24:     return $result;
  25: }

 

To Save Data

Code for both server and client are provided as follows.

Use in SnippetForm.mxml

   1: /* 
   2: The saveSnippet function that gets called when there is no errors in our form
   3: This is one function that is going to handle both creating a new snippet, and
   4: updating an existing one. Our server side php script says that if the snippetVO[snippet_id]
   5: is equal to 0, then go ahead and insert it as a new snippet. But if the snippetVO[snippet_id]
   6: is not set to 0, then update that snippet where the recieved id is equal to the id we are updating.
   7: */
   8: private function saveSnippet():void
   9: {
  10:     /* If the selectedSnippet is empty create a new snippet */
  11:     if ( model.selectedSnippet == null ) 
  12:     {                    
  13:     var createS:SnippetVO = new SnippetVO();
  14:         createS.snippet_id = 0;
  15:         createS.snippet_title = txt_title.text;
  16:         createS.snippet_code = txt_code.text;
  17:         createS.snippet_user = txt_author.text;
  18:         createS.snippet_type = txt_type.text;
  19:     
  20:     /* Service proxy */
  21:     service.saveSnippet( createS );            
  22:     
  23:     } else {
  24:         /* Set the snippet id to the value of the selected snippet_id */                    
  25:         var updateS:SnippetVO = new SnippetVO();
  26:             updateS.snippet_id = model.selectedSnippet.snippet_id;
  27:             updateS.snippet_title = txt_title.text;
  28:             updateS.snippet_code = txt_code.text;
  29:             updateS.snippet_user = txt_author.text;
  30:             updateS.snippet_type = txt_type.text;
  31:         
  32:     service.saveSnippet( updateS );
  33:                             
  34:     }
  35:     /* Do nothing */
  36: }

Use in SnippetSerivce.php

   1: //Saves a snippet if the id == 0, otherwise it updates it
   2: public function saveSnippet( $snippet )
   3: {
   4:     require_once( "../vo/SnippetVO.php" );
   5:  
   6:     //Check to see if the snippet has an $snippet[snippet_id] == 0 from Flex
   7:     if ( $snippet[snippet_id] == 0 ) 
   8:     {
   9:     $query = "INSERT INTO ".$this->table."
  10:                             ( snippet_title,
  11:                             snippet_code,
  12:                             snippet_type,
  13:                             snippet_created,
  14:                             snippet_user )        
  15:                             VALUES (
  16:                             '".mysql_real_escape_string($snippet[snippet_title])."',
  17:                             '".mysql_real_escape_string($snippet[snippet_code])."',
  18:                             '".mysql_real_escape_string($snippet[snippet_type])."',
  19:                             '".mysql_real_escape_string($snippet[snippet_created])."',
  20:                             '".mysql_real_escape_string($snippet[snippet_user])."')";
  21:     if( !mysql_query( $query ) ) 
  22:     {    
  23:         //Return False 
  24:         return false;
  25:     }                
  26:     //Return the new snippet
  27:     return $this->getOne( mysql_insert_id() );            
  28:     } else {
  29:         $id = $snippet[snippet_id];
  30:         //Set up the query
  31:         $query = "UPDATE ".$this->table." SET 
  32:                 snippet_title = '".mysql_real_escape_string($snippet[snippet_title])."',
  33:                 snippet_code = '".mysql_real_escape_string($snippet[snippet_code])."',
  34:                 snippet_type = '".mysql_real_escape_string($snippet[snippet_type])."',
  35:                 snippet_created = '".mysql_real_escape_string($snippet[snippet_created])."',
  36:                 snippet_user = '".mysql_real_escape_string($snippet[snippet_user])."'                
  37:                 WHERE snippet_id =". $id;
  38:             //If there was a problem
  39:             if( !mysql_query( $query ) )
  40:             {    
  41:                 //Return false
  42:                 return false;        
  43:             }                
  44:                 //Return the created snippet
  45:                 return $this->getOne( $id );                
  46:             }                
  47: }

 

To Delete Data

Code for both server and client are provided as follows.

Use in SnippetList.mxml

   1: //Display an alert to confirm the delete
   2: private function removeSnippet():void
   3: {        
   4:     Alert.show( "Are you sure?", "Remove Snippet", 3, null, removeSnippetAlertHandler );                        
   5: }
   6:  
   7: //If they click yes in the alert then call the removeSnippet method passing the selected snippet as the id
   8: private function removeSnippetAlertHandler( event:CloseEvent ):void
   9: {
  10:     if ( event.detail == Alert.YES )
  11:     {
  12:         service.removeSnippet( lt_snippets.selectedItem.snippet_id );
  13:     }
  14: }

 

Use in SnippetService.php

   1: //Remove a snippet by the id
   2: public function removeSnippet($id)
   3: {
   4:     $sql = mysql_query( "DELETE FROM ".$this->table." WHERE snippet_id = ".$id );
   5:     
   6:     if( !$sql )
   7:     {
   8:     //    trigger_error("Unable to delete Snippets", E_USER_ERROR);
   9:         return "There was an error removing this snippet";
  10:     }
  11:     else return $id;        
  12: }      

 

Views

SnippetForm.mxml

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <!--SnippetFormProxyService-->
   3: <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" 
   4:     creationComplete="init()" 
   5:     xmlns:components="com.jonniespratley.snippr.view.components.*">
   6:     
   7:     <mx:Script>
   8:         <![CDATA[
   9:             import mx.validators.Validator;
  10:             import mx.controls.Alert;
  11:             import mx.rpc.events.FaultEvent;
  12:             import mx.rpc.events.ResultEvent;
  13:         
  14:             import com.jonniespratley.snippr.vo.SnippetVO;
  15:             import com.jonniespratley.snippr.model.ModelLocator;
  16:             import com.jonniespratley.snippr.services.SnipprService;        
  17:  
  18:             /* Out Model so we can bind to the selectedSnippet */
  19:             [Bindable] private var model:ModelLocator = ModelLocator.getInstance();
  20:             
  21:             /* Our validation array to hold the values of our validators */
  22:             [Bindable] private var validators:Array = new Array();            
  23:             
  24:             /* Our custom remote proxy service for connection to amfphp */
  25:             private var service:SnipprService;
  26:             
  27:             /* 
  28:             On init we create a new instance of our service proxy 
  29:             We alway set our validators to our validator array
  30:             */
  31:             private function init():void
  32:             {
  33:                 service = new SnipprService();
  34:                 
  35:                 validators = [ titleV, authorV, codeV, typeV ];
  36:             }
  37:             
  38:             /* 
  39:             When the save button is clicked instead of sending the data right away
  40:             we first check it to see if it is indeed valid. If our validation array 
  41:             is empty, then we can go ahead and send our value object to amfphp, other
  42:             wise we need to alert the user that there are some errors in the form
  43:             */
  44:             private function checkForm():void
  45:             {
  46:                 var vals:Array = new Array();
  47:                     vals = Validator.validateAll( validators );
  48:                 
  49:                 //If no errors
  50:                 if ( vals.length == 0 )
  51:                 {
  52:                     saveSnippet();
  53:                     //cleanForms();
  54:                 } else {
  55:                     Alert.show( "Please correct invalid form entries", "Validation Error" );
  56:                 }
  57:             }
  58:                         
  59:             /* Clears all form inputs, and resets the selected index of the snippet list */
  60:             private function cleanForms():void
  61:             {
  62:                 //Set the model.selectedSnippet to null, so we dont have any fields used up
  63:                 //model.selectedSnippet = null;    
  64:                 txt_title.text = "";
  65:                 txt_author.text = "";
  66:                 txt_code.text = "";
  67:                 txt_type.text = "";
  68:             }
  69:  
  70:             /* 
  71:             The saveSnippet function that gets called when there is no errors in our form
  72:             This is one function that is going to handle both creating a new snippet, and
  73:             updating an existing one. Our server side php script says that if the snippetVO[snippet_id]
  74:             is equal to 0, then go ahead and insert it as a new snippet. But if the snippetVO[snippet_id]
  75:             is not set to 0, then update that snippet where the recieved id is equal to the id we are updating.
  76:             */
  77:             private function saveSnippet():void
  78:             {
  79:                 /* If the selectedSnippet is empty create a new snippet */
  80:                 if ( model.selectedSnippet == null ) 
  81:                 {                    
  82:                 var createS:SnippetVO = new SnippetVO();
  83:                     createS.snippet_id = 0;
  84:                     createS.snippet_title = txt_title.text;
  85:                     createS.snippet_code = txt_code.text;
  86:                     createS.snippet_user = txt_author.text;
  87:                     createS.snippet_type = txt_type.text;
  88:                 
  89:                 /* Service proxy */
  90:                 service.saveSnippet( createS );            
  91:                 
  92:                 } else {
  93:                     /* Set the snippet id to the value of the selected snippet_id */                    
  94:                     var updateS:SnippetVO = new SnippetVO();
  95:                         updateS.snippet_id = model.selectedSnippet.snippet_id;
  96:                         updateS.snippet_title = txt_title.text;
  97:                         updateS.snippet_code = txt_code.text;
  98:                         updateS.snippet_user = txt_author.text;
  99:                         updateS.snippet_type = txt_type.text;
 100:                     
 101:                 service.saveSnippet( updateS );
 102:                                         
 103:                 }
 104:                 /* Do nothing */
 105:             }
 106:             
 107:             /* ******************* MXML Result and Fault handlers ********************* */
 108:             private function onResult( event:ResultEvent ):void
 109:             {
 110:                 Alert.show(event.result.toString(), "Success" );
 111:             }            
 112:             
 113:             private function onFault( event:FaultEvent ):void
 114:             {
 115:                 Alert.show( event.fault.faultString );
 116:             }
 117:                     
 118:         
 119:                             
 120:         ]]>
 121:     </mx:Script>
 122:     
 123:     <!--MXML Remote Object-->
 124:         
 125:     <!--Remote Object-->
 126:     <mx:RemoteObject id="snipprSvc"    source="snippr.SnipprService" 
 127:         destination="amfphp" 
 128:         showBusyCursor="true" 
 129:         fault="onFault( event )">
 130:             <!--Methods that are on our server-->        
 131:             <mx:method name="saveSnippet" result="onResult( event )"/>
 132:             <mx:method name="getSnippets" result="onResult( event )"/>
 133:     </mx:RemoteObject>    
 134:     
 135:     <mx:ApplicationControlBar width="100%" styleName="formBar">
 136:         <mx:HBox width="100%" verticalAlign="middle">            
 137:             <mx:Label text="Author:" fontWeight="bold"/>
 138:             <mx:TextInput id="txt_author"
 139:                 text="{ model.selectedSnippet.snippet_user }" 
 140:                 width="100%"/>            
 141:         </mx:HBox>                
 142:     </mx:ApplicationControlBar>
 143:     
 144:     <mx:ApplicationControlBar width="100%" styleName="formBar">        
 145:         <mx:HBox width="100%" verticalAlign="middle">
 146:                 
 147:                 <mx:Label text="Title:" fontWeight="bold"/>
 148:                 <mx:TextInput id="txt_title"
 149:                     text="{ model.selectedSnippet.snippet_title }"
 150:                      width="100%"/>    
 151:                          
 152:                 <mx:Label text="Type:" fontWeight="bold"/>
 153:                 <mx:TextInput id="txt_type"
 154:                     text="{ model.selectedSnippet.snippet_type }" 
 155:                     width="100%"/>
 156:         
 157:             <mx:Button id="btn_clear"
 158:                 click="cleanForms()"
 159:                  label="Clear"/>
 160:             <mx:Button id="btn_save"
 161:                 click="checkForm()" 
 162:                  label="Save"/>
 163:         </mx:HBox>
 164:     </mx:ApplicationControlBar>
 165:             <mx:VBox width="100%" height="100%" label="Edit">                
 166:                 <mx:TextArea id="txt_code"
 167:                     text="{ model.selectedSnippet.snippet_code }"
 168:                     width="100%" 
 169:                     height="100%" 
 170:                      styleName="codeView"/>                
 171:             </mx:VBox>    
 172:     
 173:     <!-- Validators -->
 174:     <mx:StringValidator id="titleV"
 175:         source="{ txt_title }"
 176:         minLength="1"
 177:         maxLength="200"
 178:         required="true"
 179:         property="text"/>
 180:     <mx:StringValidator id="authorV"
 181:         source="{ txt_author }"
 182:         minLength="1"
 183:         maxLength="200"
 184:         required="true"
 185:         property="text"/>
 186:     <mx:StringValidator id="codeV"
 187:         source="{ txt_code }"
 188:         minLength="5"
 189:         required="true"
 190:         property="text"/>
 191:     <mx:StringValidator id="typeV"
 192:         source="{ txt_type }"
 193:         minLength="1"
 194:         maxLength="200"
 195:         required="true"
 196:         property="text"/>        
 197: </mx:VBox>

SnippetList.mxml

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <!--SnippetList-->
   3: <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="200" height="100%" creationComplete="init()">
   4:  
   5:     <mx:Script>
   6:         <![CDATA[
   7:             import mx.controls.Alert;
   8:             import mx.events.CloseEvent;
   9:             import com.jonniespratley.snippr.services.SnipprService;
  10:             import com.jonniespratley.snippr.vo.SnippetVO;
  11:             import com.jonniespratley.snippr.events.SnippetGetEvent;
  12:             import com.jonniespratley.snippr.model.ModelLocator;            
  13:             
  14:             //Make a instance of our model for our data display
  15:             [Bindable] private var model:ModelLocator = ModelLocator.getInstance();                
  16:             
  17:             //Make a variable to check weither there is a selected snippet or not
  18:             [Bindable] private var isSelected:Boolean = false;
  19:             
  20:             //Make variable of our service
  21:             private var service:SnipprService; 
  22:         
  23:             
  24:             private function init():void
  25:             {
  26:                 service = new SnipprService();
  27:                 getSnippets();
  28:             }
  29:             
  30:             //Send a call to get the snippets
  31:             private function getSnippets():void
  32:             {            
  33:                 service.getSnippets();    
  34:             }
  35:             
  36:             private function removeSnippet():void
  37:             {        
  38:                 Alert.show( "Are you sure?", "Remove Snippet", 3, null, removeSnippetAlertHandler );                        
  39:             }
  40:             
  41:             private function removeSnippetAlertHandler( event:CloseEvent ):void
  42:             {
  43:                 if ( event.detail == Alert.YES )
  44:                 {
  45:                     service.removeSnippet( lt_snippets.selectedItem.snippet_id );
  46:                 }
  47:             }
  48:             
  49:             //Make sure we handle the selected snippet and bind it to our model
  50:             private function selectHandler( event:Event ):void
  51:             {
  52:                 isSelected = true;
  53:                 model.selectedSnippet = event.target.selectedItem as SnippetVO;
  54:             }
  55:             
  56:         ]]>
  57:     </mx:Script>
  58:     
  59:     <!--Helper for Data Binding-->
  60:     <mx:Binding destination="lt_snippets.selectedItem" source="model.selectedSnippet"/>        
  61:         
  62:         <!--List of Snippets-->
  63:         <mx:List id="lt_snippets"
  64:             dataProvider="{ model.snippetCollection }"
  65:             change="selectHandler( event )"
  66:             labelField="snippet_title" 
  67:             width="100%" 
  68:             height="100%"/>
  69:             
  70:         <!--Remove Button-->
  71:         <mx:Button label="Remove"
  72:             click="removeSnippet()"
  73:             enabled="{ isSelected }"
  74:             width="100%"/>
  75: </mx:VBox>

 MainView.mxml

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <!--MainView-->
   3: <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" 
   4:     xmlns:snippets="com.jonniespratley.snippr.view.components.*" 
   5:     xmlns:view="com.jonniespratley.snippr.view.*">
   6:  
   7:     <!--ApplicationControll Bar-->
   8:     <view:ApplicationBar id="applicationBar"/>
   9:         
  10:     <!--MainViewStack-->
  11:     <mx:ViewStack id="vs_main" width="100%" height="100%" paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">    
  12:         <view:SnipprProxyView id="snippetsProxyView" label="Snippets Proxy"/>
  13:     </mx:ViewStack>
  14:             
  15:     <!--ViewToggle-->
  16:     <mx:ToggleButtonBar dataProvider="vs_main" width="100%"/>
  17:     
  18: </mx:VBox>

 

Ok, with that said, here is a list of files that goes with this

Tags: ,

6 Comments For This Post

  1. Hyder Alamgir Says:

    Hey Jonnie! Excellent post… will be a lot of help to flex devs new to AMFPHP

    Keep up the great work!

    Featured here:
    http://alamgirdesigns.blogspot.com/2008/09/flex-cheatsheet-flex-and-amfphp.html

  2. Alan Says:

    Good Stuff.

    >I’ve created one robust Flex / AMFPHP app using caringorm, so my questions are in that context

    In ‘SnippetVO.as’ I don’t understand what is happening in your in constuctor. Any reason why just an empty constructor won’t do?

    Next, in ‘SnippetVO.php’ , you have ‘mapObject’. Why is that? When I made my app, my php VO was just the variables, everything was always typed and uber cool.

    Look forward to taking this apart. Thanks

  3. Jonnie Says:

    Let me try to explain this..

    If TableA has the following naming convention:

    ID VARCHAR NOT NULL
    poSTitle VARCHAR NOT NULL
    POsTbODY TEXT NOT NULL

    And we want to be able to rename our fields comming back, so we can create our own
    names for the columns.

    We want to create something alittle bit more readable, for example:

    $post_id
    $post_title
    $post_body

    The record set that we are taking is a object,
    then we are filtering those fields, and assigning
    them to the variables that we created.

    we would use something like this

    $this->VARIABLE = ARGUMENT["NAME-OF-COLUMN"];

    Now we can get a clean output of our data,
    I have tried using amfphp without doing this and it
    wasn’t a pretty sight, all of the names were jacked up and I just couldn’t
    stand looking at those horrible names from the database. Amfphp can be used
    with out mapObject(obj) and it can, I prefer using it.

  4. Kiruban Naidoo Says:

    Hi,

    What’s happened to the first part of the cookbook? I can’t access it at all – just a blank page with a title and no info….

    I am looking for resources that explain AMFPHP/Cairngorm and Flex3 simply for someone new to Flex…

    Compliments on a cool site tho :)

  5. Kiruban Naidoo Says:

    Hi,

    Thanks for your response…

    I am busy going through your Cairngorm articles/recipes (Chapter4) – the cookbook is great but reading your code is extremely tedious! The black background and dark blue color of some of the code just does not work!! Make the background a lighter color to make it easy on our eyes :)

  6. Kiruban Naidoo Says:

    Hi again….

    I need your help and hope for a quick response.

    I am working on my first flex3/amfphp/Cairngorm project and have spent sleepless nights on basic issues! I just need some direction.

    For the login section of my program, I created a LoginVO.as file as a value object to pass my userid and password to my php service. There is also a UserVO.as and UserVO.php value object files that are supposed to return the logged in user’s details (such as first_name, last_name, cell, etc.) The service works but I get an ArrayCollection returned instead of a UserVO object.

    I have checked all my paths and they are correct. How can I fix this? Do I need to map the array collection returned to my VO. This seems to defeat the purpose of using amfphp and remote objects….

    Please help urgently.

    Thanks

Leave a Reply