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:
-
…
-
<script type="text/javascript">
-
var flashvars = { locale: "<?=$locale?>", username:"<?=$username?>", password:"<?=$password?>" };
-
var params = { bgcolor: "#000000" };
-
var attributes = {};
-
swfobject.embedSWF("Main.swf", "FlashDiv", "800", "600", "9.0.0", "assets/swfobject/expressInstall.swf", flashvars, params, attributes);
-
</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
-
package
-
{
-
import flash.display.Sprite;
-
import flash.display.LoaderInfo;
-
import flash.display.StageScaleMode;
-
import flash.display.StageAlign;
-
import com.log2e.app.ApplicationFacade;
-
-
[SWF(width="800", height="600", frameRate="30", backgroundColor="#FFFFFF")]
-
public class Main extends Sprite
-
{
-
public function Main()
-
{
-
stage.scaleMode = StageScaleMode.NO_SCALE;
-
stage.align = StageAlign.TOP_LEFT;
-
var flashVars:Object = LoaderInfo( this.root.loaderInfo ).parameters;
-
-
var facade:ApplicationFacade = ApplicationFacade.getInstance();
-
facade.startup( stage, flashVars );
-
}
-
}
-
}
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
-
package com.log2e.app
-
{
-
import org.puremvc.as3.interfaces.IFacade;
-
import org.puremvc.as3.patterns.facade.Facade;
-
import com.log2e.app.controller.*;
-
import com.log2e.app.model.vo.LoginVO;
-
-
public class ApplicationFacade extends Facade implements IFacade
-
{
-
public static const INIT_LOCALE_PROXY:String = "initLocaleProxy";
-
public static const INIT_LOGIN_PROXY:String = "initLoginProxy";
-
public static const STARTUP:String = "startup";
-
-
public static function getInstance(): ApplicationFacade
-
{
-
if (instance == null)
-
{
-
instance = new ApplicationFacade();
-
}
-
return instance as ApplicationFacade;
-
}
-
-
override protected function initializeController():void
-
{
-
super.initializeController();
-
-
registerCommand( ApplicationFacade.INIT_LOCALE_PROXY, InitLocaleProxyCommand );
-
registerCommand( ApplicationFacade.INIT_LOGIN_PROXY, InitLoginProxyCommand );
-
registerCommand( ApplicationFacade.STARTUP, StartupCommand );
-
}
-
-
public function startup( stage:Object, flashVars:Object ):void
-
{
-
var locale:String = '';
-
if ( flashVars.locale )
-
{
-
locale = flashVars.locale;
-
}
-
-
var loginVO:LoginVO = new LoginVO();
-
if ( flashVars.username && flashVars.password )
-
{
-
loginVO.username = flashVars.username;
-
loginVO.password = flashVars.password;
-
}
-
-
sendNotification( INIT_LOCALE_PROXY, locale );
-
sendNotification( INIT_LOGIN_PROXY, loginVO );
-
sendNotification( STARTUP, stage );
-
}
-
}
-
}
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
-
package com.log2e.app.model
-
{
-
import org.puremvc.as3.interfaces.IProxy;
-
import org.puremvc.as3.patterns.proxy.Proxy;
-
-
public class LocaleProxy extends Proxy implements IProxy
-
{
-
public static const NAME:String = "LocaleProxy";
-
-
public function LocaleProxy( name:String, data:String='' )
-
{
-
super( name, data );
-
}
-
-
public function get locale():String
-
{
-
return data as String;
-
}
-
}
-
}
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
-
package com.log2e.app.model
-
{
-
import org.puremvc.as3.interfaces.IProxy;
-
import org.puremvc.as3.patterns.proxy.Proxy;
-
import com.log2e.app.model.vo.LoginVO;
-
-
public class LoginProxy extends Proxy implements IProxy
-
{
-
public static const NAME:String = "LoginProxy";
-
-
public function LoginProxy( name:String, data:LoginVO=null )
-
{
-
super( name, data ? data : new LoginVO() );
-
}
-
-
public function get tryAutoLogin():Boolean
-
{
-
return ( loginVO.username != '' ) && ( loginVO.password != '' );
-
}
-
-
public function get loginVO():LoginVO
-
{
-
return data as LoginVO;
-
}
-
}
-
}
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
-
package com.log2e.app.model.vo
-
{
-
import flash.net.registerClassAlias;
-
-
public class LoginVO
-
{
-
private var _username:String;
-
private var _password:String;
-
-
public function LoginVO( username:String='', password:String='' )
-
{
-
_username = username;
-
_password = password;
-
}
-
-
public function set username( username:String ):void
-
{
-
_username = username;
-
}
-
-
public function get username():String
-
{
-
return _username;
-
}
-
-
public function set password( password:String ):void
-
{
-
_password = password;
-
}
-
-
public function get password():String
-
{
-
return _password;
-
}
-
-
static public function register():void
-
{
-
registerClassAlias( "com.log2e.app.model.vo.LoginVO", LoginVO );
-
}
-
}
-
}
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
-
package com.log2e.app.controller
-
{
-
import com.log2e.app.model.LocaleProxy;
-
import com.log2e.app.ApplicationFacade;
-
import org.puremvc.as3.interfaces.ICommand;
-
import org.puremvc.as3.interfaces.INotification;
-
import org.puremvc.as3.patterns.command.SimpleCommand;
-
-
public class InitLocaleProxyCommand extends SimpleCommand implements ICommand
-
{
-
override public function execute( note:INotification ):void
-
{
-
var locale:String = note.getBody() as String;
-
-
switch ( locale )
-
{
-
case 'de_DE':
-
case 'en_GB':
-
case 'en_US':
-
case 'es_ES':
-
case 'fr_FR':
-
case 'it_IT':
-
break;
-
default:
-
locale = 'en_GB';
-
break;
-
}
-
-
facade.registerProxy( new LocaleProxy( LocaleProxy.NAME, locale ) );
-
}
-
}
-
}
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
-
package com.log2e.app.controller
-
{
-
import org.puremvc.as3.interfaces.ICommand;
-
import org.puremvc.as3.interfaces.INotification;
-
import org.puremvc.as3.patterns.command.SimpleCommand;
-
import com.log2e.app.model.LoginProxy;
-
import com.log2e.app.ApplicationFacade;
-
import com.log2e.app.model.vo.LoginVO;
-
-
public class InitLoginProxyCommand extends SimpleCommand implements ICommand
-
{
-
override public function execute( note:INotification ):void
-
{
-
var loginVO:LoginVO = note.getBody() as LoginVO;
-
facade.registerProxy( new LoginProxy( LoginProxy.NAME, loginVO ) );
-
}
-
}
-
}
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: ActionScript, Flash, FlashVars, PureMVC
Nice tutorial! Would it be possible for you to post a working version of the above code and source files for reference?