Handling FlashVars in PureMVC

In this blog entry I would like to share my approach to handling FlashVars in a PureMVC application. I assume that you are familiar with the basic concepts of PureMVC.

A Real-World Scenario

Recently, I developd a PureMVC-based Flash game for a client. The application had to be multi-lingual and had to provide an auto-login option. After registration via an HTML form, the user is redirected to the page with the embedded SWF file. The locale information and the credentials are handed over to the game page as GET variables (with the password encrypted). A PHP script then generates the appropriate JavaScript code for SWFObject:

  1. <script type="text/javascript">
  2.     var flashvars = { locale: "<?=$locale?>", username:"<?=$username?>", password:"<?=$password?>" };
  3.     var params = { bgcolor: "#000000" };
  4.     var attributes = {};
  5.     swfobject.embedSWF("Main.swf", "FlashDiv", "800", "600", "9.0.0", "assets/swfobject/expressInstall.swf", flashvars, params, attributes);
  6. </script>

With the help of SWFObject the parameters are injected into the Flash file.

The Document Class

The Flash Main.as document class isn’t much different from a usual PureMVC document class except for extracting the flashVars object from the root.loaderInfo object’s parameters property and passing it to the ApplicationFacade’s startup() method as the second parameter:

Main.as

  1. package
  2. {
  3.    import flash.display.Sprite;
  4.    import flash.display.LoaderInfo;
  5.    import flash.display.StageScaleMode;
  6.    import flash.display.StageAlign;
  7.    import com.log2e.app.ApplicationFacade;
  8.  
  9.    [SWF(width="800", height="600", frameRate="30", backgroundColor="#FFFFFF")]
  10.    public class Main extends Sprite
  11.    {      
  12.       public function Main()
  13.       {
  14.          stage.scaleMode = StageScaleMode.NO_SCALE;
  15.          stage.align = StageAlign.TOP_LEFT;
  16.          var flashVars:Object = LoaderInfo( this.root.loaderInfo ).parameters;
  17.      
  18.          var facade:ApplicationFacade = ApplicationFacade.getInstance();
  19.          facade.startup( stage, flashVars );
  20.       }
  21.    }
  22. }

The ApplicationFacade

Now, what to do with the flashVars inside the ApplicationFacade? I prefer using multiple fine-granulated proxy classes for managing different portions of my application’s data model. Therefore I created two proxies, one for holding the locale information, the other one for keeping track of the login parameters. Both proxies are registered by PureMVC commands that are invoked inside the startup() method.

To get the big picture first, let’s take a look at the ApplicationFacade class before exploring the proxies and commands:

ApplicationFacade.as

  1. package com.log2e.app
  2. {
  3.    import org.puremvc.as3.interfaces.IFacade;
  4.    import org.puremvc.as3.patterns.facade.Facade;
  5.    import com.log2e.app.controller.*;
  6.    import com.log2e.app.model.vo.LoginVO;
  7.    
  8.    public class ApplicationFacade extends Facade implements IFacade
  9.    {
  10.       public static const INIT_LOCALE_PROXY:String = "initLocaleProxy";
  11.       public static const INIT_LOGIN_PROXY:String = "initLoginProxy";
  12.       public static const STARTUP:String = "startup";
  13.  
  14.       public static function getInstance(): ApplicationFacade
  15.       {            
  16.          if (instance == null)
  17.          {
  18.             instance = new ApplicationFacade();
  19.          }
  20.          return instance as ApplicationFacade;
  21.       }
  22.    
  23.       override protected function initializeController():void
  24.       {
  25.          super.initializeController();  
  26.            
  27.          registerCommand( ApplicationFacade.INIT_LOCALE_PROXY, InitLocaleProxyCommand );  
  28.          registerCommand( ApplicationFacade.INIT_LOGIN_PROXY, InitLoginProxyCommand );
  29.          registerCommand( ApplicationFacade.STARTUP, StartupCommand );
  30.       }
  31.  
  32.       public function startup( stage:Object, flashVars:Object ):void
  33.       {
  34.          var locale:String = '';
  35.          if ( flashVars.locale )
  36.          {
  37.             locale = flashVars.locale;
  38.          }
  39.      
  40.          var loginVO:LoginVO = new LoginVO();
  41.          if ( flashVars.username && flashVars.password )
  42.          {
  43.             loginVO.username = flashVars.username;
  44.             loginVO.password = flashVars.password;
  45.          }
  46.  
  47.          sendNotification( INIT_LOCALE_PROXY, locale );
  48.          sendNotification( INIT_LOGIN_PROXY, loginVO );
  49.          sendNotification( STARTUP, stage );
  50.       }
  51.    }
  52. }

Lines 27-28: The InitLocaleProxyCommand and the InitLoginProxyCommand are registered. These commands are responsible for populating the proxies. We will take a look at them shortly.

Lines 34-38: So far we haven’t checked if the flashVars object’s locale property is set at all. If it is empty the locale variable holds an empty string.

Line 40: LoginVO is a value object class that is used as the inner data structure of the LoginProxy. We will take a closer look at this helper class, too.

Lines 41-45: Similar to checking the flashVars object’s locale property, we examine the username and password properties.

Lines 47-48: The InitLocaleProxyCommand and the InitLoginProxyCommand are triggered by sending the notifications they were registered with.

Line 49: The application flow is continued with the usual PureMVC StartupCommand that takes care of registering the stage mediator, etc.

The Proxy Classes

In order to understand what the commands do with their payload, we need to look at the proxy classes first. The LocaleProxy’s data object is a string that simply contains the locale (e.g. “en_GB”):

LocaleProxy.as

  1. package com.log2e.app.model
  2. {
  3.    import org.puremvc.as3.interfaces.IProxy;
  4.    import org.puremvc.as3.patterns.proxy.Proxy;
  5.  
  6.    public class LocaleProxy extends Proxy implements IProxy
  7.    {
  8.       public static const NAME:String = "LocaleProxy";
  9.  
  10.       public function LocaleProxy( name:String, data:String='' )
  11.       {  
  12.          super( name, data );
  13.       }
  14.  
  15.       public function get locale():String
  16.       {
  17.          return data as String;
  18.       }
  19.    }
  20. }

The LoginProxy class is a little more complex. Not only is the inner data structure defined by a value object class (LoginVO), the proxy also provides a getter method that inspects the data object in order to decide if the application should try an auto-login.

LoginProxy.as

  1. package com.log2e.app.model
  2. {
  3.    import org.puremvc.as3.interfaces.IProxy;
  4.    import org.puremvc.as3.patterns.proxy.Proxy;
  5.    import com.log2e.app.model.vo.LoginVO;
  6.  
  7.    public class LoginProxy extends Proxy implements IProxy
  8.    {
  9.       public static const NAME:String = "LoginProxy";
  10.  
  11.       public function LoginProxy( name:String, data:LoginVO=null )
  12.       {
  13.          super( name, data ? data : new LoginVO() );
  14.       }
  15.  
  16.       public function get tryAutoLogin():Boolean
  17.       {
  18.          return ( loginVO.username != '' ) && ( loginVO.password != '' );  
  19.       }
  20.  
  21.       public function get loginVO():LoginVO
  22.       {
  23.          return data as LoginVO;
  24.       }
  25.    }
  26. }

Lines 16-18: If the credentials have been passed to Flash via SWFObject the application is supposed to try an auto-login. If tryAutoLogin is false the user will be redirected to a login view inside the Flash movie.

The LoginVO class contains setter and getter methods for username and password.

LoginVO.as

  1. package com.log2e.app.model.vo
  2. {
  3.    import flash.net.registerClassAlias;
  4.  
  5.    public class LoginVO
  6.    {
  7.       private var _username:String;
  8.       private var _password:String;
  9.    
  10.       public function LoginVO( username:String='', password:String='' )
  11.       {
  12.          _username = username;
  13.          _password = password;
  14.       }
  15.  
  16.       public function set username( username:String ):void
  17.       {
  18.          _username = username;
  19.       }
  20.  
  21.       public function get username():String
  22.       {
  23.          return _username;
  24.       }
  25.  
  26.       public function set password( password:String ):void
  27.       {
  28.          _password = password;
  29.       }
  30.  
  31.       public function get password():String
  32.       {
  33.          return _password;
  34.       }
  35.  
  36.       static public function register():void
  37.       {      
  38.          registerClassAlias( "com.log2e.app.model.vo.LoginVO", LoginVO );      
  39.       }  
  40.    }
  41. }

Lines 36-39: The static method register() is supposed to be used in an AMF remoting environment. Since this post describes a pure AS3 approach we can’t rely on the RemoteClass meta tag which is only available in Flex. (Maybe I will blog on PureMVC and AMFPHP in another post.)

The Commands

Finally, here are the commands that process the FlashVars information and register the proxies.

InitLocaleProxyCommand.as

  1. package com.log2e.app.controller
  2. {
  3.    import com.log2e.app.model.LocaleProxy;
  4.    import com.log2e.app.ApplicationFacade;
  5.    import org.puremvc.as3.interfaces.ICommand;
  6.    import org.puremvc.as3.interfaces.INotification;
  7.    import org.puremvc.as3.patterns.command.SimpleCommand;
  8.  
  9.    public class InitLocaleProxyCommand extends SimpleCommand implements ICommand
  10.    {  
  11.       override public function execute( note:INotification ):void    
  12.       {  
  13.          var locale:String = note.getBody() as String;
  14.  
  15.          switch ( locale )
  16.          {
  17.             case 'de_DE':
  18.             case 'en_GB':
  19.             case 'en_US':
  20.             case 'es_ES':
  21.             case 'fr_FR':
  22.             case 'it_IT':
  23.                break;
  24.             default:
  25.                locale = 'en_GB';
  26.                break;
  27.          }  
  28.  
  29.          facade.registerProxy( new LocaleProxy( LocaleProxy.NAME, locale ) );  
  30.       }    
  31.    }
  32. }

Lines 15-27: The locale is checked against a list of valid locales. If no valid value is found a default value is set.

There’s nothing special about the InitLoginProxyCommand, I post it here just for the sake of completeness:

InitLoginProxyCommand.as

  1. package com.log2e.app.controller
  2. {
  3.    import org.puremvc.as3.interfaces.ICommand;
  4.    import org.puremvc.as3.interfaces.INotification;
  5.    import org.puremvc.as3.patterns.command.SimpleCommand;
  6.    import com.log2e.app.model.LoginProxy;
  7.    import com.log2e.app.ApplicationFacade;
  8.    import com.log2e.app.model.vo.LoginVO;
  9.  
  10.    public class InitLoginProxyCommand extends SimpleCommand implements ICommand
  11.    {    
  12.       override public function execute( note:INotification ):void    
  13.       {      
  14.          var loginVO:LoginVO = note.getBody() as LoginVO;
  15.          facade.registerProxy( new LoginProxy( LoginProxy.NAME, loginVO ) );  
  16.       }      
  17.    }
  18. }

After the LocaleProxy and the LoginProxy have been registered the StartupCommand (which I do not post here) takes control over the application flow by registering the StageMediator and so on.

I hope you found this post useful. Do share your thoughts and comments. Thanks for your time.

Tags: , , ,

One Response to “Handling FlashVars in PureMVC”

  1. gregory Says:

    Nice tutorial! Would it be possible for you to post a working version of the above code and source files for reference?

Leave a Reply