Using a Session Facade - Mach-II/Mach-II-Framework GitHub Wiki

By Eric Cobb (ecobb@…)

Table of Contents

  1. Introduction
  2. What is a Session Facade?
  3. What is in a Session Facade?
  4. Choosing Between Concrete Versus Generic Getters/Setters?
  5. How do you use a Session Facade in Mach-II without ColdSpring?
  6. Using Our Concrete Session Facade
  7. Using Our Generic Session Facade
  8. What’s the point?
  9. How do you use a Session Facade in Mach-II with ColdSpring?

Introduction

A Session Facade is more of a programming concept than an actual Mach-II feature. While Mach-II makes working with a Session Facade extremely easy, you can actually use a Session Facade in any CFML application, with or without Mach-II.

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 shared scopes in CF (session, cookie, etc...). How you use a Session Facade is ultimately up to you. You should find what works best for you and stick 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 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.

What is in a Session Facade?

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 prefer to actually 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:

    <cfcomponent displayname="SessionFacade" hint="Basic Session Facade" output="false">

        <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:

    <cfcomponent displayname="SessionFacade" hint="Basic Session Facade" output="false">

        <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"/>

            <cfset session[arguments.key] = arguments.value />
        </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

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.

How do you use a Session Facade in Mach-II without ColdSpring?

We need to be able to access our Session Facade from anywhere in our application, just like we can with the session scope. The best way to do this is to set it up as a Property. To quote the documentation: "Properties in Mach-II applications are a convenient way to make variables available throughout an entire Mach-II application. Properties are declared in mach-ii.xml and after the application initializes, properties may be accessed via a simple getProperty() method call from anywhere within the application".

That sounds exactly like what we want. But, since we can only use simple name/value pairs for property declarations in our mach-ii.xml file, we're going to have to use a Property CFC to make it happen. The Property CFC (Introduced in Mach-II 1.5) works just like the other Mach-II core objects (Listener, Filter, Plugin) and contains a configure() method that Mach-II automatically calls when the application initializes. It allows us to use custom CFCs as properties in Mach-II applications, and can be declared in our mach-ii.xml file right along with the simple name/value properties.

Here is our SessionProperty.cfc:

    <cfcomponent displayname="SessionProperty" extends="machII.framework.Property"
        hint="I set the Session Property" output="false">

        <cffunction name="configure" access="public" output="false">
            <!--- create the sessionFacade and store it in the property mgr --->
            <cfset var sessionFacade = createObject("component","model.SessionFacade").init() />
            <cfset setProperty("sessionFacade",sessionFacade) />
        </cffunction>

    </cfcomponent>

And that's it. That wasn't so bad, was it? Our last step is even easier. We just add our property to mach-ii.xml, inside of our <properties> tags:

    <property name="sessionProperty" type="properties.SessionProperty" />

Using Our Concrete Session Facade

Now instead of calling session.UserID throughout our application, we can call getProperty("sessionFacade").getUserID(). Or, we can do something like:

    <cfset REQUEST.sessionFacade = getProperty("sessionFacade") />
    <cfoutput>#REQUEST.sessionFacade.getUserID()#</cfoutput>

Using Our Generic Session Facade

With a Generic Session Facade, instead of calling session.UserID throughout our application, we can call getProperty("sessionFacade").getVar("UserID"). Or, we can do something like:

    <cfset REQUEST.sessionFacade = getProperty("sessionFacade") />
    <cfoutput>#REQUEST.sessionFacade.getVar("UserID")#</cfoutput>

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. 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, that's 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.UserID
    SESSION.FirstName

to these calls:

    SESSION.UserInfo.ID
    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

    session[arguments.key]

to this call:

    session[listFirst(arguments.key,".")][listRest(arguments.key,".")]

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. There are other ways to accomplish the same thing (hey, it's your Facade, you 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.

How do you use a Session Facade in Mach-II with ColdSpring?

TODO - Needs sample code

⚠️ **GitHub.com Fallback** ⚠️