ColdFusion Components
- To create and use ColdFusion Components.
CFC Basics
ColdFusion Components (CFCs) are very similar to classes in object-oriented languages. They are used to create structured applications and to "blackbox" complicated processing code.
Like all ColdFusion pages, CFCs are simply text files written in CFML; however, they use the extension ".cfc" rather than ".cfm". They can be stored anywhere in the application's directory structure.
Creating CFCs
All code within a CFC should be wrapped in a <cfcomponent> tag, which can contain one or more <cffunction> tags. The <cffunction>s are the methods of the component. The only major difference between functions written in CFCs and standard ColdFusion functions is that a CFC function has an access level, which is assigned in the access attribute of the <cffunction> tag.
| Access Level | Description |
|---|---|
| private | only accessible from other methods in the same component |
| package | only accessible from components in the same directory |
| public | accessible from any ColdFusion page in the application |
| remote | accessible over the internet and by the Flash Player. |
The code below shows an example of a CFC that has similar functionality to the imageflipper custom tag we saw earlier.
Code Sample: CFCs/Demos/Images.cfc
<cfcomponent> <cffunction name="ImageFlipper" access="public" returntype="string"> <cfargument name="directory" type="string" required="true"> <cfargument name="extensions" type="string" default="jpg,gif"> <cfset aryImages = getFileList(arguments.directory,arguments.extensions)> <cfparam name="SESSION.picture" default="0"> <cfset SESSION.picture = SESSION.picture + 1> <cfif SESSION.picture GT ArrayLen(aryImages)> <cfset SESSION.picture = 1> </cfif> <cfset imagepath="#arguments.directory#/#aryImages[SESSION.picture]#"> <cfreturn imagepath> </cffunction>---- Code Omitted ----</cfcomponent>
Storing CFCs
ColdFusion Components can be stored in any of the following locations. ColdFusion will search for them in the order listed.
- In the same directory as the calling page - while this is easy for demonstration purposes, it's not very practical, as it means that the CFC is only available within that directory.
- In a directory (or subdirectory of a directory) mapped in ColdFusion Administrator under Server Settings -> Mappings.
- In a directory (or subdirectory of a directory) specified in ColdFusion Administrator under Extensions -> Custom Tag Paths.
- In the web root.
Invoking CFCs
CFC methods are invoked using the <cfinvoke> tag. The tag does one of the following:
- instantiates the specified component transiently and then invokes the specified method.
- invokes the specified method on a component that has already been instantiated (e.g, with the <cfobject> tag).
Passing Argument Values
CFC method arguments can be passed in any of the following ways:
- Using a nested <cfinvokeargument> tag with name and value attributes:
<cfinvoke component = "component_name" method="method_name" returnvariable="return_variable"> <cfinvokeargument name="arg1" value="value"> <cfinvokeargument name="arg2" value="value"> </cfinvoke>
- Using attribute-value pairs in the <cfinvoke> tag itself:
<cfinvoke component = "component_name" method="method_name" returnvariable="return_variable" arg1="value" arg2="value">
- Using the argumentCollection attribute with the value set to a structure storing name-value pairs:
<cfset args = StructNew()> <cfset args.arg1 = "value"> <cfset args.arg2 = "value"> <cfinvoke component="component_name" method="method_name" argumentCollection="#args#" returnVariable="return_variable">
The following example shows different ways of invoking the ImageFlipper method of the Images CFC:
Code Sample: CFCs/Demos/Images.cfm
<html> <head> <title>Invoking Component Methods</title> </head> <body> <h1>Invoking Component Methods</h1> <h2>Example 1: Transient Instantiation</h2> <cfinvoke component = "Images" method="ImageFlipper" returnvariable="imgpath"> <cfinvokeargument name="directory" value="Images/Runners"> </cfinvoke> <cfoutput><img src="#imgpath#"/></cfoutput> <h2>Example 2: Using attributes rather than cfinvokeargument</h2> <cfinvoke component = "Images" method="ImageFlipper" returnvariable="imgpath" directory="Images/Runners"> <cfoutput><img src="#imgpath#"/></cfoutput> <h2>Example 3: Passing the arguments using argumentCollection</h2> <cfset args = StructNew()> <cfset args.directory = "Images/Runners"> <cfset args.extensions = "jpg"> <cfinvoke component="Images" method="ImageFlipper" argumentCollection="#args#" returnVariable="imgpath"> <cfoutput><img src="#imgpath#"/></cfoutput> <h2>Example 4: Separate instantiation and method invocation</h2> <cfset args = StructNew()> <cfset args.directory = "Images/Runners"> <cfset args.extensions = "jpg"> <cfobject name="objImage" component="Images2"> <cfloop index="i" from="1" to="7"> <cfinvoke component="#objImage#" method="ImageFlipper" directory="Images/Runners" extensions = "jpg" returnVariable="imgpath"> <cfoutput><img src="#imgpath#"/></cfoutput> </cfloop> </body> </html>
Transient Instantiation
The first example above uses transient instantiation. As the component has not yet been instantiated, <cfinvoke> instantiates the component, calls the method and then destroys the component. This is useful when all you need to do is call one method on the object. The argument is passed using <cfinvokeargument>.
The second and third examples are essentially the same, except the second uses attribute-value pairs and the third uses the argumentCollection attribute to pass arguments to the method.
Separate Instantiation and Method Invocation
The fourth example instantiates the component with the <cfobject> tag and then, using a loop, calles the ImageFlipper method seven times. Because the object is being used more than once, it's better to instantiate it separately. It will be destroyed when the page exits.
THIS Scope
You may also notice that the component is built a little differently. Instead of using session variables, it holds a picture variable in the THIS scope that stores the number of the picture showing. The ImageFlipper method changes the value of THIS.picture each time it is called. Variables in the THIS scope are properties of the component instance. That is, if another instance of this component were created, it would have its own picture property.
Extending ColdFusion Components
ColdFusion components can inherit from other ColdFusion components by means of the extends attribute. The example below shows a ThumbNails component that extends the Images component.
Code Sample: CFCs/Demos/ThumbNails.cfc
<cfcomponent extends="Images">
<cffunction name="CreateImageTable" access="public" returntype="string">
<cfargument name="directory" type="string" required="true">
<cfargument name="columns" type="numeric" default="2">
<cfargument name="extensions" type="string" default="jpg,gif">
<cfset aryImages = getFileList(arguments.directory,arguments.extensions)>
<cfset rows = Ceiling(ArrayLen(aryImages)/columns)>
<cfset picture = 1>
<cfsavecontent variable="ReturnTable">
<table border="1">
<cfloop index="i" from="1" to="#rows#">
<tr>
<cfloop index="j" from="1" to="#columns#">
<td>
<cfoutput><img src="#arguments.directory#/#aryImages[picture]#"></cfoutput>
</td>
<cfset picture = picture + 1>
</cfloop>
</tr>
</cfloop>
</table>
</cfsavecontent>
<cfreturn ReturnTable>
</cffunction>
</cfcomponent>
The ThumbNails component has a single method that displays all the images in the specified directory as a table. The following example makes use of that method and of a method in the parent Images component.
Code Sample: CFCs/Demos/ThumbNails.cfm
<html> <head> <title>Thumbnails</title> </head> <body> <h1>Thumbnails</h1> <cfobject name="objThumbNail" component="ThumbNails"> <cfinvoke component = "#objThumbNail#" method="CreateImageTable" returnvariable="ImgTable"> <cfinvokeargument name="directory" value="Images/Runners"> <cfinvokeargument name="columns" value="3"> </cfinvoke> <cfoutput>#ImgTable#</cfoutput> <hr /> <cfinvoke component = "#objThumbNail#" method="ImageFlipper" returnvariable="imgpath"> <cfinvokeargument name="directory" value="Images/Runners"> </cfinvoke> <cfoutput><img src="#imgpath#"/></cfoutput> </body> </html>
Although the examples above aren't very interesting in terms of functionality, they should give you the idea of how CFCs can be extended.
Application.cfc
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:
| Variable | Description |
|---|---|
| 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.
Application.cfc Methods
onApplicationStart
The onApplicationStart method is invoked when the first page of the application is requested. It can be used to:
- test database connections.
- verify the existence of key files.
- test the mail server.
- set application variables.
- log the time the application started.
onApplicationEnd
The onApplicationEnd method is invoked when the application times out. It can be used to log the time the application ended.
onRequestStart
The onRequestStart method is invoked at the start of every page request. It can be used to:
- authenticate the user.
- output a standard header.
- include common function libraries.
onRequest
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:
- filter content.
- output a standard header.
- output a standard footer.
onRequestEnd
The onRequestEnd method is invoked at the end of every page request. It can be used to output a standard footer.
onSessionStart
The onSessionStart method is invoked when a user's session starts. It can be used to:
- set session variables.
- log the time the session started.
onSessionEnd
The onSessionEnd method is invoked when the session ends. It can be used to log the time the session ended.
onError
The onError method is invoked when an exception is not caught by a try/catch block. It can be used to:
- Log errors.
- Display friendly error messages.
- Email the site administrator.
We cover the onError method in greater detail in the Handling Errors.
Application.cfc Benefits
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.
Application.cfm Shortcomings
Only one Application.cfm page per request
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.
No easy way to log sessions
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.
Application code runs every time a page is requested
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:
<cfif NOT isDefined("APPLICATION.DatabaseVerified")>
<cftry>
<cfquery name="VerifyDB" datasource="Animals">
SELECT AnimalType
FROM tblAnimals
</cfquery>
<cflock timeout="5" throwontimeout="No" type="EXCLUSIVE" scope="SESSION">
<cfset APPLICATION.DatabaseVerified = true>
</cflock>
<cfcatch type="database">
<cflog file="Animals" type="error"
text="Message: #cfcatch.message#
Detail: #cfcatch.detail#
Native Error: #cfcatch.NativeErrorCode#">
</cfcatch>
</cftry>
</cfif>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:
<cffunction name="onApplicationStart" output="true">
<cftry>
<cfquery name="VerifyDB" datasource="Animals">
SELECT AnimalType
FROM tblAnimals
</cfquery>
<cflog file="Animals" type="Information" text="Application Started">
<cfcatch type="database">
<cfoutput>Datasource "Animals" not available.</cfoutput>
<cflog file="Animals" type="error"
text="Message: #cfcatch.message#
Detail: #cfcatch.detail#
Native Error: #cfcatch.NativeErrorCode#">
<cfreturn false>
</cfcatch>
</cftry>
</cffunction>Extending Application.cfc - An Example
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:
- Animals/index.cfm and other pages under the Animals directory, but not under the Cats or Dogs directories.
- If URL.who is undefined or does not equal "dog", "cat" or "mouse":

- If URL.who equals "dog", "cat" or "mouse":

- If URL.who is undefined or does not equal "dog", "cat" or "mouse":
- Animals/Dogs/index.cfm and other pages under the Dogs directory.
- If URL.who is undefined or does not equal "dog":

- If URL.who equals "dog" :

- If URL.who is undefined or does not equal "dog":
- Animals/Cats/index.cfm and other pages under the Cats directory.
- If URL.who is undefined or does not equal "cat":

- If URL.who equals "cat" :

- If URL.who is undefined or does not equal "cat":
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.
Code Sample: CFCs/Demos/Animals/index.cfm
<html> <head> <title>You're an animal!</title> </head> <body> You're an animal! </body> </html>
Code Sample: CFCs/Demos/Animals/Application.cfc
<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 onApplicationStart, onRequestStart, and onRequestEnd.
onApplicationStart sets 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.
Code Sample: CFCs/Demos/Animals/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:
- The component extends 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.
- Only the onRequestStart method, which authenticates the user, is overridden.
CFCs/Demos/Animals/Cats/Application.cfc works exactly the same way.
ColdFusion Components Conclusion
In this lesson of the ColdFusion tutorial, you have learned how to create and use ColdFusion Components, which allow for an object-oriented style of programming in ColdFusion as they support inheritance and type safety. You have also learned how to use Application.cfc to make your application development more modular.
