| By Ben Forta | Article Rating: |
|
| October 15, 2003 04:35 PM EDT | Reads: |
16,397 |
ColdFusion developers rely on session state management and the SESSION scope extensively. But as applications grow in complexity, so do the number of SESSION variables, and the risk of overwriting or misusing them. It need not be that way; with a little work (and ColdFusion Components), SESSION use can be clean, simple, and highly organized.
When Session Data Proliferates
First, an introduction. The
Web is stateless. Or put in terms
that actually mean something,
every request on the Web stands
on its own two feet. The data
received by a form submission,
for example, is only available in
the receiving page and not to
subsequent requests. Or, user
credentials specified at login are not kept
until logout. And similarly, items put in a
shopping cart won't still be in the cart at
checkout time.
But wait a minute, those statements can't be true, can they? After all, we've all put items in shopping carts and then checked out, and we've all logged in to sites that remembered us until logout, haven't we? If the Web is stateless, how is that data maintained? That's the job of session state management, a mechanism that creates the illusion of state in a stateless world.
Data to be maintained between requests is stored on the server, along with an id that designates the client that the data belongs to. That id is sent back and forth with each and every request, so that the server can associate the maintained data and give the illusion of persistent data. In ColdFusion all this is accomplished using SESSION variables. Developers simply refer to variables like #SESSION.Firstname# and ColdFusion takes care of all the details (setting and receiving session identifiers, maintaining the SESSION data, and ensuring that the correct data is used when referring to variables with the SESSION scope).
Okay, end of introduction.
So you need to track session information, great. The first thing you do is set SESSIONMANAGEMNT="yes" in your <CFAPPLICATION> tag (which makes a lot of sense; after all, you can't use the SESSION scope without having first instructed ColdFusion to enable that functionality. Once enabled you are free to save any data within SESSION. For example, a simple variable:
<CFSET SESSION.FirstName="Ben">
or a more complex data type:
<CFSET SESSION.cart=ArrayNew(1)>
or even queries:
<CFQUERY DATASOURCE="dsn"
NAME="SESSION.profile">
SELECT *
FROM Users
WHERE user_id = #FORM.user_id#
</CFQUERY>
There is no limit to what can be stored
in the SESSION scope. That's a good
thing, but it's also a liability. Why?
Consider the following:
This is just the tip of the iceberg. The key here is that because SESSION variables are so easy to create and use, their use can quickly get out of hand unless some semblance of structure is imposed.
The Basics of Encapsulation
The word encapsulation is one of
those terms that means lots of different
things and usually ends up being misused
most of the time. But at its simplest,
encapsulation is a technique by
which applications are separated into
parts so that code need not know the
inner workings of things it doesn't need
to know.
For example, stored procedures are one of the best known forms of encapsulation. A stored procedure contains one or more database instructions in the form of SQL statements, but all that is hidden from the stored procedure user who simply makes a call to obtain data or to perform some other operation. What happens within the stored procedure is not important, what is important is that it does what it's supposed to do, it just works.
ColdFusion Custom Tags (or rather, well-written ColdFusion Custom Tags) offer another form of encapsulation. A tag is invoked to perform an operation, the details of which are concealed within the tag.
Encapsulation thus does several things:
I'm using the term encapsulation a little more loosely than most object-oriented developers would like, but having said that, this is indeed what encapsulation is all about. (Note: This idea was explained in detail in CFDJ, Volume 4, issue 10.)
ColdFusion Components and Encapsulation
ColdFusion Components (CFCs for
short), first introduced in ColdFusion MX,
are a way to create reusable objects in
ColdFusion. Although not objects in the
purest sense, they do provide basic object
functionality wrapped within the simplicity
that is uniquely CFML. (Note: ColdFusion
Components were introduced in detail in a
two-part column that appeared in CFDJ,
Volume 4, issues 6 & 7.)
Two of the most important aspects of CFCs is that they can store data internally, and they can persist. Let me explain. Within every CFC is a special scope named THIS. THIS contains some default data, but it can also be used to store data of your own. For example, the following method accepts two arguments (first and last name) and then saves them into the THIS scope:
<CFFUNCTION NAME="SetName"
OUTPUT="no">
<CFARGUMENT NAME="NameFirst"
TYPE="string"
REQUIRED="yes">
<CFARGUMENT NAME="NameLast"
TYPE="string"
REQUIRED="yes">
<CFSET THIS.NameFirst=ARGUMENTS.NameFirst>
<CFSET THIS.NameLast=ARGUMENTS.NameLast>
</CFFUNCTION>
To invoke this method you could use the following code (assuming the previous method was saved in a file named user.cfc):
<CFINVOKE COMPONENT="user"
METHOD="SetName"
NAMEFIRST="Ben"
NAMELAST="Forta">
This next method returns a string made up of the saved first and last name:
<CFFUNCTION NAME="GetName"
RETURNTYPE="string"
OUTPUT="no">
<CFRETURN THIS.NameFirst & " " &
THIS.NameLast>
</CFFUNCTION>
So, SetName saves the name and GetName retrieves it, so the following code should save my name and return it as a string:
<CFINVOKE COMPONENT="user"
METHOD="SetName"
NAMEFIRST="Ben"
NAMELAST="Forta">
<CFINVOKE COMPONENT="user"
METHOD="GetName"
RETURNVARIABLE="FullName">
If you were to execute this code, however, you would throw an error. The SetName call will work, but GetName will complain that THIS.NameFirst and THIS.NameLast do not exist. Why? After all, they were just set in SetName?
The problem with the above invocation is that the user component is being invoked twice, two separate invocations that have nothing to do with each other. Each <CFINVOKE> loads the component, invokes the appropriate method, and then unloads the components. So when GetName is executed there is no NameFirst and NameLast in THIS; those were in the previously invoked instance.
The solution? Persistence. Aside from being a type of file, a CFC is a ColdFusion data type, an object. <CFINVOKE>, as used above, loads the object, uses it, and then unloads it. But those steps can be separated. Look at this example:
<CFOBJECT COMPONENT="user"
NAME="userObj">
<CFINVOKE COMPONENT="#userObj#"
METHOD="SetName"
NAMEFIRST="Ben"
NAMELAST="Forta">
Here the component is being loaded as an object (which it actually is). The <CFOBJECT> instantiates (creates an instance of) the user object, but does not invoke any method. Rather, it stores the object in a named variable. <CFINVOKE> then invokes the previously loaded object; notice that the value passed to COMPONENT is the object (as opposed to the name of the CFC). Once an object is loaded it can be used multiple times, and as it is the same object being used over and over, all invocations share the same object and thus the same internal THIS scope.
Here's a corrected version of the code to set and get the user name:
<CFOBJECT COMPONENT="user"
NAME="userObj">
<CFINVOKE COMPONENT="#userObj#"
METHOD="SetName"
NAMEFIRST="Ben"
NAMELAST="Forta">
<CFINVOKE COMPONENT="#userObj#"
METHOD="GetName"
RETURNVARIABLE="FullName">
<CFOBJECT> instantiates the object, SetName stores the values into THIS, and GetName returns it (possibly to be displayed).
This can also be accomplished using object style invocation. For example, the object instantiation could be performed using:
<CFSET userObj=CreateObject("component","user")>
and the GetName could be executed as:
<CFSET FullName=userObj.GetName()>]
or used directly for display as:
#userObj.GetName()#
Session Encapsulation
So, components are objects and can
persist. The examples thus far loaded the
object as local variables (type VARIABLES,
the default variable type). But other scopes
may be used too. Components may be
loaded into REQUEST, for example:
<CFOBJECT COMPONENT="user" NAME="REQUEST.userObj">
and components may even be loaded into persistent scopes like SESSION:
<CFSET SESSION.user=CreateObject("component", "user")>
Which brings us back to session state management. Instead of defining and accessing all sorts of SESSION variables throughout your application, you could define just one, an object (an instantiated ColdFusion Component). If your application uses user data you may want to create a user.cfc, which would contain all user information (including obtaining information from underlying databases). To check if a user has logged in you'd use code like this:
<CFIF NOT IsDefined("SESSION.user")>
... redirect to login page ...
</CFIF>
The login page would authenticate the user (if needed) and then create an instance of the user object in the user's SESSION scope:
<CFOBJECT COMPONENT="user" NAME="SESSION.user">
You may then want to initialize the object so as to populate the internal THIS with any needed information (user name, color preferences, language choices, and so on). Perhaps you'd simply pass the user id to an initialization method immediately after object creation:
<CFSET SESSION.user.Init(user_id)>
Init() should probably return a true or false flag (indicating whether or not the initialization was successful), and within the CFC you'll probably want each method to ensure that Init() was called before begin executed, but that is all internal to the CFC.
What about user logout? Simple; when a user logs out you'd kill SESSION. user like this:
<CFSET StructDelete(SESSION, "user")>
so that on a subsequent request the login and initialization process would restart.
With user.cfc you can do anything, so perhaps you'd have methods like these:
- ChangePassword
- GetLanguage
- GetFirstName
- GetLastName
- GetFullName
- GetDisplayName
- IsMember
- IsAdmin
And this goes beyond user processing. Consider a shopping cart example. Shopping carts are stored in SESSION variables, but instead of storing arrays or structures or arrays of structures of whatever in SESSION and accessing them directly, you'd create a cart component. To start shopping you'd create an instance of the cart:
<CFOBJECT COMPONENT="cart" NAME="SESSION.cart">
When an item is to be added you'd call the appropriate method:
<CFINVOKE COMPONENT="#SESSION.cart#"
METHOD="AddItem"
ITEMID="#itemid#"
QUANTITY="#FORM.qty#">
Other methods would update or remove items, and perhaps a list method would return a query (a ColdFusion query created within the CFC using the QueryNew() function) for displaying or processing. There is no limit to what you can do within a CFC, and your CFC code can evolve and adapt independent of any calling code.
Conclusion
ColdFusion Components are objects.
CFCs facilitate the encapsulation of data
and logic, and they can be made to persist
if needed. The combination of these two
features makes CFCs perfect for managing
session state. With minimal work the
techniques described here can be used in
any application, and doing so will both
simplify and improve your code.
Published October 15, 2003 Reads 16,397
Copyright © 2003 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Ben Forta
Ben Forta is Adobe's Senior Technical Evangelist. In that capacity he spends a considerable amount of time talking and writing about Adobe products (with an emphasis on ColdFusion and Flex), and providing feedback to help shape the future direction of the products. By the way, if you are not yet a ColdFusion user, you should be. It is an incredible product, and is truly deserving of all the praise it has been receiving. In a prior life he was a ColdFusion customer (he wrote one of the first large high visibility web sites using the product) and was so impressed he ended up working for the company that created it (Allaire). Ben is also the author of books on ColdFusion, SQL, Windows 2000, JSP, WAP, Regular Expressions, and more. Before joining Adobe (well, Allaire actually, and then Macromedia and Allaire merged, and then Adobe bought Macromedia) he helped found a company called Car.com which provides automotive services (buy a car, sell a car, etc) over the Web. Car.com (including Stoneage) is one of the largest automotive web sites out there, was written entirely in ColdFusion, and is now owned by Auto-By-Tel.
- Oracle To Keynote Cloud Computing Expo
- Contrary Opinion: Why Silverlight is Good for Adobe
- Analytics for Adobe Air Applications
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Is Microsoft as Free as Open Source?
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- The Planet Named “Bronze Sponsor” of Cloud Computing Expo
- Adobe Reader Sued
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Adobe Enters Cloud Computing with LiveCycle
- Oracle To Keynote Cloud Computing Expo
- Social Media Terrorists
- Adobe Flash Media Server on iPhone
- Contrary Opinion: Why Silverlight is Good for Adobe
- Adobe Flash Based GetJar Surpasses a Half Billion Downloads
- Adobe ColdFusion 9 and ColdFusion Builder Public Betas Now Available
- Adobe Tries Commercializing Its Online Software
- Adobe Open Sources Flash Initiatives
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers

































