Using a Session Facade in ColdFusion
Over the weekend I updated my Using a Session Facade entry on the Mach-II wiki, and decided to abstract part of it and repost here as a "non Mach-II" tutorial on Session Facades. Now by no means do I consider myself an authority on Session Facades (or anything else for that matter). I realize that there are varying opinions on the subject of Session Facades, as well other (possibly better) ways to accomplish the same thing. My hopes are that I've written this blog post in a way that it can explain the basic concept of a Session Facade to someone who's never used it, and possibly help to trigger one of those "Ah-ha!" moments that we programmers do so enjoy.
What is a Session Facade?
A Session Facade is nothing more than a CFC that your application interacts with to get information. In this tutorial our Session Facade is a CFC that handles all of our application's session information. It allows us to have a single point of reference for our session variables, which lets us abstract the session scope from the rest of our application. With a Session Facade, our application doesn't need to know anything about the session scope, it just calls and interacts with the Session Facade like any other object.
It should be noted that the Session Facade is just a concept, not an actual rule. By this I mean that there is no One True Way that you have to use a Session Facade. Some people use Session Facades to interact with only session variables. Others use a Session Facade to interact with multiple CFML shared scopes (session, cookie, etc...). How you use a Session Facade is ultimately up to you. You should find what works best for you and go with it. For the sake of simplicity, I'm going to be referencing the session scope in this tutorial. But, I do want to point out that just because it's called a "Session" Facade, doesn't mean that it's limited to just the session scope.
What does a Session Facade consist of?
Our Session Facade will consist of a series of get and set methods for our session variables. Some people like to use a generic object with a generic getter and setter that allows you to pass whatever you want into the Session Facade (we'll call this a Generic Session Facade). However, I usually prefer to create the individual getter and setter methods for each variable (we'll call this a Concrete Session Facade). This limits what information gets added to our session scope to only what is needed.
So, our Concrete Session Facade (SessionFacade.cfc) that manages user information is going to look something like:
<cffunction name="init" returntype="SessionFacade" access="public" output="false">
<cfreturn this/>
</cffunction>
<cffunction name="getUserID" access="public" returntype="numeric" output="false" displayname="getUserID" hint="I get User ID from the Session">
<cfreturn SESSION.UserID />
</cffunction>
<cffunction name="setUserID" access="public" returntype="void" output="false" displayname="setUserID" hint="I set User ID in the Session">
<cfargument name="UserID" type="numeric" required="true" />
<cflock scope="Session" timeout="10">
<cfset SESSION.UserID = arguments.UserID />
</cflock>
</cffunction>
<cffunction name="getUserFirstName" access="public" returntype="string" output="false" displayname="getUserFirstName" hint="I get User FirstName from the Session">
<cfreturn SESSION.FirstName />
</cffunction>
<cffunction name="setUserFirstName" access="public" returntype="void" output="false" displayname="setUserFirstName" hint="I set User FirstName in the Session">
<cfargument name="FirstName" type="string" required="true" />
<cflock scope="Session" timeout="10">
<cfset SESSION.FirstName = arguments.FirstName />
</cflock>
</cffunction>
</cfcomponent>
As I said before, some people prefer to work with generic getter and setter methods in their Session Facades. Here's an example of a Generic Session Facade:
<cffunction name="init" returntype="SessionFacade" access="public" output="false">
<cfreturn this/>
</cffunction>
<cffunction name="setVar" access="public" returntype="void" output="false" hint="I set a value into the session">
<cfargument name="key" type="string" required="true" hint="I am the key to store as"/>
<cfargument name="value" type="any" required="true" hint="I am the value to store"/>
<cflock scope="Session" timeout="10">
<cfset session[arguments.key] = arguments.value />
</cflock>
</cffunction>
<cffunction name="getVar" access="public" returntype="any" output="false" hint="I retrieve a value from the session">
<cfargument name="key" type="string" required="true" hint="I am the key whose value will be retrieved"/>
<cfreturn session[arguments.key] />
</cffunction>
</cfcomponent>
Choosing Between Concrete Versus Generic Session Facades
When it comes choosing between using a Concrete Session Facade and a Generic Session Facade there really is no "right" way, it's merely a matter of personal opinion. Some people like the Generic Facade because it's much less code to maintain, and you don't have to worry about continuously adding/removing methods as your application grows. However, you don't have as much control over what gets passed into your session. With a Concrete Facade you have much more control since you specify exactly what gets put into your session. But, as your application grows the number of methods in a Concrete Facade can quickly become larger and larger if you have a lot of variables to put in your session.
Personally, I have used both Concrete and Generic Session Facades in my applications in the past, and will continue to do so depending on the needs of whatever application I happen to be working on. If I'm working on an application that will have a manageable number of variables, I'll use a Concrete Session Facade because I like that little extra layer of control. However, if I'm working on an application that will be managing dozens (or hundreds?) of variables, then I'll go the Generic Session Facade route because it will be much less of a hassle to maintain.
Using a Session Facade
Since we're going to be using our Session Facade quite regularly for all of our session variables (right?), we want to have easy access to it. There's really no point in having to use cfinvoke or creatObject to access our CFC every time we want to use it, so lets just go ahead and save it in the aplication scope.
<cfset Application.sessionManager.setMethodName("VariableValue") />
EXAMPLE: If we wanted to set session.firstName = Bob
<cfset Application.sessionManager.setUserFirstName("Bob") />
2) To get a session variable:
<cfset myVar = Application.sessionManager.getMethodName() />
EXAMPLE: If we wanted to set a variable equal to session.firstName
<cfset userFirstName = Application.sessionManager.getUserFirstName() />
EXAMPLE: If we just wanted to display session.firstName
<cfoutput>#Application.sessionManager.getUserFirstName()#</cfoutput>
EXAMPLE: Using session.userID in a cfif tag
<cfif Application.sessionManager.getUserID() eq 1>
Using a Generic Session Facade is just as simple
<cfset Application.sessionManager.setVar("VariableName","VariableValue") />
EXAMPLE: If we wanted to set session.firstName = Bob
<cfset Application.sessionManager.setVar("firstName","Bob") />
2) To get a session variable:
<cfset myVar = Application.sessionManager.getVar("VariableName") />
EXAMPLE: If we wanted to set a variable equal to session.firstName
<cfset userFirstName = Application.sessionManager.getVar("firstName") />
EXAMPLE: If we just wanted to display session.firstName
<cfoutput>#Application.sessionManager.getVar("firstName")#</cfoutput>
EXAMPLE: Using session.userID in a cfif tag
<cfif Application.sessionManager.getVar("UserID") eq 1>
What's the point?
I know what you're thinking. We just took a simple session variable call and made it a lot more complex than it needs to be. While this may seem true at first, it's important to remember that the Session Facade offers several benefits, with one of the main ones being maintainability. Since the Session Facade is the only thing that interacts directly with the session scope, it keeps references to the session scope from being scattered throughout our entire codebase (which also helps enforce encapsulation). So, in the event we ever need to make any changes to the way we store our session data, or rename a session variable, we only have to change it in one place instead of throughout our application.
For example, let's take our two session variables, session.userID and session.firstName. One day we realize that we need to organize our sessions a little better, and decide to group things together into structures like session.userInfo.ID and session.userInfo.firstName. If we were not using a Session Facade, we would have to search our entire codebase for session.userID and session.firstName and replace every one of them with the new variables. But, since we are using a Session Facade, our CFC is the only place we have to make changes.
So with a Concrete Session Facade, in our SessionFacade.cfc we would simply change these calls:
SESSION.FirstName
to these calls:
SESSION.UserInfo.FirstName
And that's it. Since our Session Facade is the only place we reference the session variables, that is the only code that needs to be changed.
However, in a Generic Session Facade you'll have to change a little (but not much) more code to deal with breaking things into separate structures. You will need to change
to this call:
This will allow you to call getVar("UserInfo.ID"), and also allow your existing Session Facade calls that are not broken into separate structures to continue to work. This also ensures that the values get put into actual structures, instead of just creating a string named "UserInfo.ID". There are other ways to accomplish the same thing (hey, it's your Facade, do can do anything you want), but this way lets you make the change inside of your SessionFacade.cfc without having to change the Session Facade calls throughout your entire application.
And that's pretty much it. I hope this has been enough to get you started with Session Facades. I do want to point out, however, that the above example should not be considered a complete, all encompassing Session Facade. There are things that I left out of SessionFacade.cfc such as removing a session variable or handling missing session variables. I wanted this example to be as basic as possible and just demonstrate the general concept.
Happy coding!


But, the thing that starts to cross my mind is: Is there a value to just leaping past the concept of delegates session access and move right into a persisted session object?
By that, I mean that rather than just delegating session-scope access as in here:
Application.sessionManager.getUserFirstName()
... what about dealing directly with CFC-based session data:
Application.sessionManager.getSession().getUserFirstName()
... then, rather than delegation to ColdFusion's implicit "session" scope, the session object could manage data internally (ie. this.firstName, this.lastName)?
I guess, where I'm going with is thinking about the value add of a "Facade" over simply creating a session "Entity" that is non-knowing about its own persistence.
Thanks!
session scope: i do this from a long time, as i think this is a basic oop concept.
Suppose i have a role based app: first of all i incapsulate my verified user, instantiating an object to be persisted
in session; now suppose this logged user has to compile an order: i model the order body as an iterator, an array
of item objects, persisted in session too.
In general the iterator has other methods than getters: you may want to retreive the tax total, prices sum etc: i use
sessionMgr.get("iterator").getTax().
In my session manager i use generic getter and setter, plus an isItemInSession(obj) method for every obj in the scope.
regards
Basically, if you create your own "session" container and store *that* in the session scope (or however you choose to persist session-like data), then, your code never need to know about "Session" or at least in a very minimal way.
This is confusing 'cause we are mixing the meaning of session scope and session concept :)
Great stuff bro! @Ben brings some very valid ideas as well (as always). One item on your examples: in your Generic Facade example, you forgot to put a lock in your generic setter method. That may be fine if you only access the SessionManager from within you OnSessionStart() and OnSessionEnd() methods, but could potentially cause issues otherwise.
Not sure about Mach-II, but I believe the one in ColdBox is used for monitoring server's session usage.. that is optional to me so I usually stay away from using it if i have the choice.
I use it the same way Ben Nadel suggested, encapsulating a session bean and using the variables scope of the bean to store the values.
@henry
The main thing this does is encapsulates all access to the session scope (or cookie in my case)-- so all your access to that scope is in 1 place, so you don't need to hunt down everyplace you use session.XXX when making changes-- in a small app it makes little difference, but as was mentioned when you have a lot of session variables, especially complex ones this method can simplify the process.
To the exception you noted, it should actually be something like this:
Replace <cfreturn session[ arguments.key ] /> with :
<cfif ListLen(arguments.key,".") gt 1>
<cfreturn session[listFirst(arguments.key,".")][listRest(arguments.key,".")] />
<cfelse>
<cfreturn session[ arguments.key ] />
</cfif>
As opposed to replace <cfreturn session[ arguments.key ] /> with (that you posted):
session[listFirst(arguments.key,".")][listRest(arguments.key,".")]
Nice one. Cheers!