[[Dashboard | << Back to Dashboard ]]
{|align="right"
| __TOC__
|}
= ColdBox Flash RAM =
{{{Messagebox message="Covers up to version 3.5.0" type="info"}}}
== Introduction ==
The purpose of the Flash RAM is to allow variables to be persisted seamlessly from one request and be picked up in a subsequent request(s) by the same user. This allows you to hide implementation variables and create web flows or conversations in your ColdBox applications. So why not just use session or client variables? Well, most developers forget to clean them up and sometimes they just end up overtaking huge amounts of RAM and no clean cut definition is found for them. With Flash RAM, you have the facility already provided to you in an abstract and encapsulated format. This way, if you need to change your flows storage scope from session to client scope, the change is seamless and painless.
''ColdBox Flash RAM Sequence Diagram''
Every handler, plugin, interceptor, layout and view has a '''flash''' object in their '''variables''' scope already configured for usage. The entire flash RAM capabilities are encapsulated in a flash object that you can use in your entire ColdBox code. Not only that, but the ColdBox Flash object is based on an interface and you can build your own Flash RAM implementations very easily. It is extremely flexible to work on a concept of a Flash RAM object than on a storage scope directly. So future changes are easily done at the configuration level.
Our Flash Scope also can help you maintain flows or conversations between requests by using the ''discard() and keep()'' methods. This will continue to expand in our 3.X releases as we build our own conversations DSL to define programmatically wizard like or complex web conversations. Also, the ColdBox Flash RAM has the capability to not only maintain this persistence scope but it also allows you to seamlessly re-inflate these variables into the request collection or private request collection, both or none at all.
== Flash Storage ==
There are times where you need to store user related variables in some kind of permanent storage then relocate the user into another section of your application, be able to retrieve the data, use it and then clean it. All of these tedious operations are definitely doable by why reinvent the wheel if we can have the platform give us a tool for maintaing conversation variables across requests. The key point for Flash RAM is where will the data be stored so that it is unique per user. ColdFusion gives us several persistent scopes that we can use and we have also created several flash storages for this purpose. Since the ColdBox flash scope is based on an interface, the flash scope storage can be virtually anywhere. You will find all of these implementations in the following package: ''coldbox.system.web.flash''. In order to choose what implementation to use in your application you need to tell the [[ConfigurationCFC]] which one to use via '''flash''' configuration structure:
=== Configuration ===
// flash scope configuration
flash = {
scope = "session,client,cluster,ColdboxCache,or full path",
properties = {}, // constructor properties for the flash scope implementation
inflateToRC = true, // automatically inflate flash data into the RC scope
inflateToPRC = false, // automatically inflate flash data into the PRC scope
autoPurge = true, // automatically purge flash data for you
autoSave = true // automatically save flash scopes at end of a request and on relocations.
};
Below is a nice chart of all the keys in this configuration structure so you can alter behavior of the Flash RAM objects:
{| cellpadding="5", class="tablelisting"
! '''Key''' !! '''Type''' !! '''Required''' !! '''Default''' !! '''Description'''
|-
| '''scope''' || string or instantiation path || false || ''session'' || Determines what scope to use for [[FlashRAM | Flash RAM]]. The available aliases are: session, client, cluster, ColdboxCache or a custom instantiation path
|-
| '''properties''' || struct || false || {} || Properties that can be used inside the constructor of any [[FlashRAM | Flash RAM]] implementation
|-
| '''inflateToRC''' || boolean || false || true || Whatever variables you put into the [[FlashRAM | Flash RAM]], they will also be inflated or copied into the [[RequestContext | request collection]] for you automatically.
|-
| '''inflateToPRC''' || boolean || false || false || Whatever variables you put into the [[FlashRAM | Flash RAM]], they will also be inflated or copied into the private [[RequestContext | request collection]] for you automatically
|-
| '''autoPurge''' || boolean || false || true || This is what makes the [[FlashRAM | Flash RAM]] work, it cleans itself for you. Be careful when setting this to false as it then becomes your job to do the cleaning
|-
| '''autoSave''' || boolean || false || true || The [[FlashRAM | Flash RAM]] saves itself at the end of requests and on relocations via ''setNextEvent()''. If you do not want auto-saving, then turn it off and make sure you save manually
|}
=== Core Flash Implementations ===
The included flash implementations for ColdBox are:
{|cellpadding="5", class="tablelisting"
! '''Name''' !! '''Class''' !! '''Description'''
|-
|| '''Session''' || ''coldbox.system.web.flash.SessionFlash'' || Persists variables in ''session'' scope
|-
|| '''Cluster''' || ''coldbox.system.web.flash.ClusterFlash'' || Persists variables in ''cluster'' scope via Railo only
|-
|| '''Client''' || ''coldbox.system.web.flash.ClientFlash'' || Persists variables in ''client'' scope
|-
|| '''Mock''' || ''coldbox.system.web.flash.MockFlash'' || Mocks the storage of Flashed variables. Great for unit/integration testing.
|-
|| '''ColdboxCache''' || ''coldbox.system.web.flash.ColdboxCacheFlash'' || Persists variables in the ColdBox Cache
|-
|}
==== Configuration Properties ====
Each RAM implementation can also use properties in order to alter its behavior upon construction via the '''properties''' configuration struct. Below are the properties our core implementations can use:
'''SessionFlash Settings''':
* '''none'''
'''ClusterFlash Settings''':
* '''none'''
'''ClientFlash Settings''':
* '''none'''
'''MockFlash Settings''':
* '''none'''
'''ColdboxCacheFlash Settings''':
{|cellpadding="5", class="tablelisting"
! '''Setting''' !! '''Type''' !! '''Required''' !! '''Default''' !! '''Description'''
|-
|| '''cacheName''' || string || false || ''default'' || The cache provider name declared in [[CacheBox]] to be used to store the user's flash RAM content.
|}
// flash scope configuration
flash = {
scope = "ColdboxCache",
properties = { cacheName="cluster" }
};
== Using Flash RAM ==
There are several ways to interact with the ColdBox Flash RAM:
* Using the '''flash''' scope object (Best Practice)
* Using the '''persistVariables()''' method from the super type and coldbox controller (''coldbox.system.web.Controller'')
* Using the persistence arguments in the '''setNextEvent()''' method from the super type and coldbox controller (''coldbox.system.web.Controller'')
All of these methods interact with the Flash RAM object but the last two methods not only place variables in the temporary storage bin but actualy serialize the data into the Flash RAM storage immediately. The first approach queues up the variables for serialization and at the end of a request it serializes the variables into the correct storage scope, thus saving precious serialization time. In the next section we will learn what all of this means.
=== Flash Scope Object ===
The flash scope object is our best practice approach as it clearly demarcates the code that the developer is using the ''flash'' scope for persistence. Any flash scope must inherit from our '''AbstractFlashScope''' and has access to several key methods that we will cover in this section. However, let's start with how the flash scope stores data:
# The flash persistence methods are called for saving data, the data is stored in an internal temporary request bin and awaiting serialization and persistence either through relocation or termination of the request.
# If the flash methods are called with immediate save arguments, then the data is immediately serialized and stored in the implementation's persistent storage.
# If the flash's '''saveFlash()''' method is called then the data is immediately serialized and stored in the implementation's persistent storage.
# If the application relocates via '''setNextEvent()''' or a request finalizes then if there is data in the request bin, it will be serialized and stored in the implementation's storage.
'''Important''' : By default the Flash RAM queues up serializations for better performance, but you can alter the behavior programmatically or via the configuration file.
{{{Messagebox type="info" message="If you use the persistVariables() method or any of the persistence arguments on the setNextEvent() method, those variables will be saved and persisted immediately."}}}
To review the Flash Scope methods, please [http://apidocs.coldbox.org go to the API] and look for the correct implementation or the '''AbstractFlashScope'''. Please note that the majority of a Flash scope methods return itself so you can concatenate method calls. Below are the main methods that you can use to interact with the Flash RAM object:
==== clear() ====
Clears the temporary storage bin
flash.clear();
==== clearFlash() ====
Clears the persistence flash storage implementation
flash.clearFlash();
==== discard() ====
any discard([string keys=''])
Discards all or some keys from flash storage. You can use this method to implement flows.
// discard all flash variables
flash.discard();
// dicard some keys
flash.discard('userID,userKey,cardID');
==== exists() ====
boolean exists(string name)
Checks if a key exists in the flash storage
if( flash.exists('notice') ){
// do something
}
==== get() ====
any get(string name, [any default])
Get's a value from flash storage and you can even pass a default value if it does not exist.
// Get a flash key that you know exists
cardID = flash.get("cardID");
// Render some flash content
#flash.get("notice","")#
==== getKeys() ====
Get a list of all the objects in the temp flash scope.
Flash Keys: #structKeyList( flash.getKeys() )#
==== getFlash() ====
Get a reference to the permanent storage implementation of the flash scope.
==== getScope() ====
Get the flash temp request storage used throughout a request until flashed at the end of a request.
==== isEmpty() ====
Check if the flash scope is empty or not
==== keep() ====
any keep([string keys=''])
Keep all or a single flash temp variable alive for another relocation. Usually called from interceptors or event handlers to create conversations and flows of data from event to event.
function step2(event){
// keep variables for step 2 wizard
flash.keep('userID,fname,lname');
// keep al variables
flash.keep();
}
==== persistRC() ====
any persistRC([string include=''], [string exclude=''], [boolean saveNow='false'])
Persist keys from the ColdBox request collection into flash scope. If using exclude, then it will try to persist the entire request collection but excluding certain keys. Including will only include the keys passed from the request collection.
// persist some variables that can be reinflated into the RC upon relocation
flash.persistRC(include="name,email,address");
setNextEvent('wizard.step2');
// persist all RC variables using exclusions that can be reinflated into the RC upon relocation
flash.persistRC(exclude="ouser");
setNextEvent('wizard.step2');
// persist some variables that can be reinflated into the RC upon relocation and serialize immediately
flash.persistRC(include="email,addressData",savenow=true);
==== put() ====
any put(string name, any value, [boolean saveNow='false'], [boolean keep='true'], [boolean inflateToRC=FROMConfig], [boolean inflateToPRC=FROMConfig], [boolean autoPurge=FROMConfig)
This is the main method to place data into the flash scope. You can optionally use the arguments to save the flash immediately, inflate to RC or PRC on the next request and if the data should be auto purged for you. You can also use the configuration settings to have a consistent flash experience, but you can most certainly override the defaults. By default all variables placed in flash RAM are automatically purged in the next request once they are inflated UNLESS you use the '''keep()''' methods in order to persist them longer or create flows. However, you can also use the '''autoPurge''' argument and set it to '''false''' so you can control when the variables will be removed from flash RAM. Basically a glorified ColdFusion scope that you can use.
// persist some variables that can be reinflated into the RC upon relocation
flash.put(name="userData",value=userData);
setNextEvent('wizard.step2');
// put and serialize immediately.
flash.put(name="userData",value=userData,saveNow=true);
// put and mark them to be reinflated into the PRC only
flash.put(name="userData",value=userData,inflateToRC=false,inflateToPRC=true);
// put and disable autoPurge, I will remove it when I want to!
flash.put(name="userData",value=userWizard,autoPurge=false);
==== putAll() ====
Same as the '''put()''' method but instead you pass in an entire structure of name-value pairs into the flash scope.
var map = {
addressData = rc.address,
userID = securityService.getUserID(),
loggedIn = now()
};
// put all the variables in flash scope as single items
flash.putAll(map);
// Use them later
if( flash.get("loggedIn") ){
}
==== remove() ====
any remove(string name, [boolean saveNow='false'])
Remove an object from the temporary flash scope so when the flash scope is serialized it will not be serialized. If you would like to remove a key from the flash scope and make sure your changes are reflected in the persistence storage immediately, use the ''saveNow'' argument.
// mark object for removal
flash.remove('notice');
// mark object and remove immediately from flash storage
flash.remove('notice',true);
==== removeFlash() ====
Remove the entire flash storage. We recommend using the clearing methods instead.
==== saveFlash() ====
Save the flash storage immediately. This process looks at the temporary request flash scope and serializes if it needs to and persists to the correct flash storage on demand.
{{{Messagebox type="info" message="We would advice to not overuse this method as some storage scopes might have delays and serializations"}}}
flash.saveFlash();
==== size() ====
Get the number of the items in flash scope
You have #flash.size()# items in your cart!
==== More Examples ====
// handler code:
function saveForm(event){
// save post
flash.put("notice","Saved the form baby!");
// relocate to another event
setNextEvent('user.show');
}
function show(event){
// Nothing to do with flash, inflating by flash object automatically
event.setView('user.show');
}
// User/show.cfm template using if statements
#flash.get("notice")#
// User/show.cfm using defaults
#flash.get(name="notice",default="")
== Creating Your Own Flash Scope ==
The ColdBox Flash capabilities are very flexible and you can easily create your own Flash Implementations by doing two things:
# Create a CFC that inherits from '''coldbox.system.web.flash.AbstractFlashScope'''
# Implement the following functions: ''clearFlash(), saveFlash(), flashExists(), and getFlash()''
=== Implementable Methods ===
{| cellpadding="5", class="tablelisting", width="98%"
! '''Method''' !! '''ReturnType''' !! '''Description'''
|-
|| '''clearFlash()''' || void || Will destroy or clear the entire flash storage structure.
|-
|| '''saveFlash()''' || void || Will be called before relocations or on demand in order to flash the storage. This method usually talks to the ''getScope()'' method to retrieve the temporary flash variables and then serialize and persist.
|-
|| '''flashExists()''' || boolean || Checks if the flash storage is available and has data in it.
|-
|| '''getFlash()''' || struct || This method needs to return a structure of flash data to reinflate and use during a request.
|}
'''Important''' : It is the developer's responsibility to provide consistent storage locking and synchronizations.
All of the methods must be implemented and they have their unique purposes as you read in the description. Let's see a real life example, below you can see the flash implementation for the session scope:
instance = structnew();
super.init(arguments.controller);
instance.flashKey = "cbox_flash_scope";
return this;
// Check if session is defined first
if( NOT isDefined("session") ) { return false; }
// Check if storage is set and not empty
return ( structKeyExists(session, getFlashKey()) AND NOT structIsEmpty(session[getFlashKey()]) );
As you can see from the implementation, it is very straightforward to create a useful session flash RAM object. You can also get more funky and use some ColdBox internal serializers for any kind of object:
instance = structnew();
super.init(arguments.controller);
// Marshaller
instance.converter = createObject("component","coldbox.system.core.conversion.ObjectMarshaller").init();
instance.flashKey = "cbox_flash";
return this;
// Check if session is defined first
if( NOT isDefined("client") ) { return false; }
// Check if storage is set
return ( structKeyExists(client, getFlashKey()) );
== Summary ==
The ColdBox Flash RAM is an excellent utility to help you create basic or even complex conversations between events and be able to persist data across requests. I really encourage you to start using the Flash RAM capabilities and go funky with them. Expect great things to come as we develop our webflow and conversation DSL language in versions to come.