There is a special reserved Application.cfc component that works much like the Application.cfm and OnRequestEnd.cfm files, but uses an object-oriented approach, which allows it to be extended in a way that the Application.cfm file cannot.
Like Application.cfm, the Application.cfc component is called before each page request. Its THIS scope is used to set the same application properties that can be set with <cfapplication>'s attributes:
|name||Name of application.|
|applicationTimeout||Lifespan of application variables. Default is set in Administrator.|
|clientManagement||Enable client variables. Default is set in Administrator.|
|clientStorage||Where to store client variables. Default is set in Administrator.|
|loginStorage||Where to store login variables (in Cookies or Session). Default is "Cookie".|
|sessionManagement||Enable session management. Default is "No".|
|sessionTimeout||Lifespan of session variables. Default is set in Administrator.|
|setClientCookies||Enable cookies. Default is "Yes".|
|setDomainCookies||Sets CFID and CFTOKEN for a domain. Default is "No".|
|scriptProtect||Protect variables from cross-site scripting attacks. Default is set in Administrator.|
The Application.cfc component has eight pre-named methods, none of which is required. They are described below.
The onApplicationStart method is invoked when the first page of the application is requested. It can be used to:
The onApplicationEnd method is invoked when the application times out. It can be used to log the time the application ended.
The onRequestStart method is invoked at the start of every page request. It can be used to:
The onRequest method is invoked immediately after the onRequestStart method. It takes one argument: the path to the target page. The method can be used to:
The onRequestEnd method is invoked at the end of every page request. It can be used to output a standard footer.
The onSessionStart method is invoked when a user's session starts. It can be used to:
The onSessionEnd method is invoked when the session ends. It can be used to log the time the session ended.
The onError method is invoked when an exception is not caught by a try/catch block. It can be used to:
We cover the onError method in greater detail in the Handling Errors.
Why do we need Application.cfc? What was wrong with Application.cfm? Application.cfm certainly is useful, but it has some major shortcomings, which Application.cfc addresses.
Each time a page runs, ColdFusion looks for an Application.cfm page in the current directory and then in each parent directory up to the web root until it finds one. As soon as it finds an Application.cfm page, it runs it and stops looking. The problem with this system is that it makes it difficult to treat any single directory differently from the rest of the application. To do so, you have to create an entirely new Application.cfm file for that directory, even though much of the code will be the same as in the other Application.cfm files in the application. If you decide to make an application-wide change, you will have to make the change in each Application.cfm file.
ColdFusion actually searches for Application.cfc files in the same way it searches for Application.cfm files and it stops as soon as it finds one. The big difference is that one Application.cfc can extend another. This means that we don't have to repeat all the same code every time we want a slight change in functionality.
Application.cfm does not provide any mechanism for flagging the start and end of sessions. Application.cfc's onSessionStart and onSessionEnd methods are invoked when a session starts and ends, so the developer can easily log information about the visit.
All the code in Application.cfm runs every time a page is requested. This makes it a less than ideal place for performing expensive tests like verifying a database connection. We can get around this by writing code to check if the database has already been verified:
Application.cfc's onApplicationStart method makes this simpler as the method is only invoked one time: when the application is started. This means we don't have to check to see if the connection has already been verified and we don't have to lock application variables. It also allows us to take more serious action, like stopping the application from starting. The method might be written like this:
Imagine a site for dogs, cats and mice. All certified animals (dogs, cats and mice) can access the main part of the site, but there is a part of the site reserved for cats and another part reserved for dogs. The directory structure looks like this:
In this demo, we will indicate who the user is by passing "who=dog" or "who=cat" along the querystring. We want the application to act as follows:
The index.cfm pages all look the same, except for the words "animal", "dog", and "cat". The code for Animals/index.cfm is shown below, followed by the code for its Application.cfc file.
<html> <head> <title>You're an animal!</title> </head> <body> You're an animal! </body> </html>
<cfcomponent> <cfset THIS.name="Animals"> <cfset THIS.sessionManagement="true"> <cfset THIS.clientManagement="true"> <cfset THIS.setClientCookies="true"> <cfset THIS.applicationTimeout=CreateTimeSpan(2,0,0,0)> <cfset THIS.sessionTimeout=CreateTimeSpan(0,0,20,0)> <cffunction name="onApplicationStart"> <!--- POSSIBLE USES: Test database connection Test mail server Set application variables (do not have to lock code) Log the start of the application ---> <cfset APPLICATION.animals = "dog,cat,mouse"> </cffunction> <cffunction name="onApplicationEnd"> <!--- POSSIBLE USES: Log the end of the application ---> </cffunction> <cffunction name="onRequestStart"> <!--- POSSIBLE USES: Authentication code Output header ---> <cfif NOT isDefined("URL.who") OR NOT ListContains(APPLICATION.animals,URL.who)> You must be a certified animal to visit this page. <cfabort> </cfif> </cffunction> <cffunction name="onRequest"> <!--- POSSIBLE USES: Filter content Output header Output footer ---> <cfargument name = "targetPage" type="String" required="true"/> <cfsavecontent variable="content"> <cfinclude template="#ARGUMENTS.targetPage#"> </cfsavecontent> <cfoutput> #replace(content, "badword", "%&!@", "all")# </cfoutput> </cffunction> <cffunction name="onRequestEnd"> <cfargument type="String" name = "targetTemplate" required="true"/> <!--- POSSIBLE USES: Output footer ---> <hr/> © Animals Incorporated </cffunction> <cffunction name="onSessionStart"> <!--- POSSIBLE USES: Set session variables Log the start of the session ---> <cflock timeout="5" throwontimeout="No" type="EXCLUSIVE" scope="SESSION"> <cfset APPLICATION.sessions = APPLICATION.sessions + 1> </cflock> <cflock timeout="5" throwontimeout="No" type="EXCLUSIVE" scope="SESSION"> <cfset APPLICATION.currentSessions = APPLICATION.currentSessions + 1> </cflock> </cffunction> <cffunction name="onSessionEnd"> <cfargument name = "SessionScope" required="true"/> <!--- POSSIBLE USES: Log the end of the session ---> <cflock timeout="5" throwontimeout="No" type="EXCLUSIVE" scope="SESSION"> <cfset APPLICATION.currentSessions = APPLICATION.currentSessions - 1> </cflock> </cffunction> <cffunction name="onError"> <cfargument name="Exception" required="true"/> <cfargument type="String" name = "EventName" required="true"/> <!--- POSSIBLE USES: Log errors Display error Email site administrator ---> </cffunction> </cfcomponent>
This Application.cfc file includes code to set the
THIS scope variables and it also includes all eight reserved methods. For our purposes, the interesting methods to look at are
APPLICATION.animals, which determines which animals are allowed on the site.
onRequestStart checks to make sure that the visitor is an allowed animal.
onRequestEnd outputs a standard footer.
Now let's look at Dogs/Application.cfc.
<cfcomponent extends="Animals.Application" output="yes"> <cffunction name="onRequestStart" output="yes"> <cfif NOT isDefined("URL.who") OR URL.who NEQ "dog"> You must be a dog to visit this page. <cfabort> </cfif> </cffunction> </cfcomponent>
Things to notice:
Animals.Application. (For this to work, you'll need to create a mapping in Administrator to the CFCs/Demos/Animals.) This means that all the code in Animals/Application.cfc will run unless something is overridden.
onRequestStartmethod, which authenticates the user, is overridden.
CFCs/Demos/Animals/Cats/Application.cfc works exactly the same way.