OK, we're still working through setting up our Application for a Multi Site One Codebase scenario, and we haven't really gotten into the application yet (aside from dynamically setting the application name). Now is where we really have to take some serious consideration to variable scoping and application workflow. Thing is, there are dozens of ways to skin this cat (no, the view layer stuff comes later). The things we'll talk about in these next several posts aren't MSOC specific either, as they can apply to most any application. The first step is getting a hard handle on what you can do within the Application.cfc, and start to use it as intended.
Your Application.cfc can (and should) have several methods that will automatically fire during key points of your application lifecycle. It's critical to understand these event handlers and gain a good understanding of their order of precedence (when they fire).
- onApplicationEnd(struct applicationScope)
- onSessionEnd(struct sessionScope, struct applicationScope)
- onRequestStart(string targetPage)
- onCFCRequest(string cfcName, string method, struct args)
- onRequest(string targetPage)
- onRequestEnd(string targetPage)
- onError(struct exception, string eventName)
You also have the onServerStart() method of the Server.cfc to consider as well, but we've talked about it before. (I tried to put an onMissingMethod() into an Application.cfc, and force a call by calling an undefined method from my constructor, but it just errored out. Guess that method is only for standard cfc's.) In the next few articles we'll go further in depth on some uses of each of these event handlers, but for now we'll discuss what can happen outside of these methods.
A Little Of THIS And A Little Of That
Within your Application.cfc you have functions and metadata (the stuff in comments outside of functions), and then there's everything else. Application definition occurs mostly outside of these functions (THIS.name = "foo"; THIS.datasource = "bar") in the constructor. Not that you can't manipulate those variables in your functions. In fact, there are some very valid use cases for manipulating THIS variables in the various request functions, but for now let's talk about their use and the constructor.
Code within the constructor executes without calling a function, and prior to any of the events being fired. In our last post we dynamically set our application name in the constructor prior to any events being fired. And, in terms of Application.cfc, this is very important as it happens on every single ColdFusion request. The THIS variable scope of the Application.cfc is where our application is defined, and that definition basically is redefined on each request (as the constructor is executed on request, and outside of the application event handlers).
"But Cutter, what does that mean?" Well, that's a good question. There are times when we want our application to stop and do something else. We don't want a new session started and taking up memory. We don't want a new application initialized (see the last post for an example). We don't want to even begin a request. By placing code within the constructor, the code will execute outside of these handlers, giving us the means to stop processing.
Say you have two versions of a site: the standard version and a mobile version. Within the constructor we are already querying the database for details on the requested domain. Within the constructor you can run some code that says something like:
location(url="http://" & thisdomain.mobileUrl);
if(!thisdomain.ismobile AND thisuseragent.ismobile)
Or maybe you have multiple urls for the same site. You want them all to 301 redirect back to the primary site for SEO purposes. You could do something like:
location(url="http://" & thisdomain.primaryUrl,statusCode=301);
if(thisurl != thisdomain.primaryUrl)
Obviously you'll want to do a lot more than that, like including the requested template or any query string in the request, but there are a lot of uses. You just have to remember that constructor code processes prior to any of your application event handlers, and you don't want to bog it down too much as it will process on every ColdFusion request. Now you just have to get creative and decide what to do in your constructor. (What do you do in your constructor?)