facebook google plus twitter
Webucator's Free ColdFusion MX Tutorial

Lesson: Reusing Code and Writing Functions

Welcome to our free ColdFusion MX tutorial. This tutorial is based on Webucator's Comprehensive ColdFusion Training course.

Lesson Goals

  • To include files with <cfinclude>.
  • To to use Application.cfm and OnRequestEnd.cfm.
  • To to write user-defined functions.

Including Files

Including files in ColdFusion is made simple with the <cfinclude> tag, which takes a single attribute: template. The template attribute points to the file to include. ColdFusion first looks for the included file relative to the current directory. If it cannot find it, it then looks in directories mapped in ColdFusion Administrator.

<cfinclude template="path_to_file">

Note that a ColdFusion tag cannot be opened in a calling file and then closed in an included file or vice versa. The ColdFusion code in the included file must be syntactically valid on its own.

A Note on Security

If included files are under the web root, they can be accessed just as any other file can. If they have an extension such as .inc then the browser may display them as plain text. With other extensions, the browser may attempt to download the file. If the included file is a ColdFusion file and a user navigates to it, the server will try to process the file and may return errors. As a precaution, you may want to place your included files in a directory above or outside of the web root. This will prevent users from accessing the files directly.

Code Sample:

ReusingCode/Demos/index.cfm
<html>
<head>
<title>Runners Home&trade;</title>
<link href="Styles/Main.css" rel="stylesheet">
</head>

<body>
<cfinclude template="Includes/NavBar.cfm">

<div id="greeting">
	<cfoutput>The time is #TimeFormat(Now(),"h:mm tt")# on #DateFormat(Now(), "mmmm d, yyyy")#.</cfoutput>
</div>

<table align="center" cellpadding="10" cellspacing="0" width="100%" height="100%" id="hometable">
---- C O D E   O M I T T E D ----
</table>
<cfinclude template="Includes/Footer.cfm">

</body>
</html>

The above code is relatively straightforward. It contains to included files: Includes/NavBar.cfm and Includes/Footer.cfm.

Application.cfm and OnRequestEnd.cfm

Whenever a ColdFusion page is called, the ColdFusion Application Server checks the current directory for a file called Application.cfm. If Application.cfm is not found in the current directory, ColdFusion looks for the file in the parent directory and continues to look up the tree until it gets to the root directory of the file system. As soon as the file is found, ColdFusion stops looking up the tree and prepends the found Application.cfm to the called page.

Application.cfm is often used for the following tasks:

  • Control state management variables and set the application name with <cfapplication>.
  • Set default global variables such as data source names and file paths.
  • Set custom error handling using <cferror>.

Application.cfm should not used for including code to be output to the browser, such as a common header.

When and only when an Application.cfm file is found, ColdFusion will also look for a file called OnRequestEnd.cfm in the same directory. If it finds OnRequestEnd.cfm it will append it to the called file. OnRequestEnd.cfm is sometimes used for outputting debugging information or logging information about the page.

User-defined Functions

User-defined functions are used to make common tasks easier and to make code more modular and easier to read.

Defining and Calling Functions

Functions are defined with the <cffunction> tag as follows. Like built-in functions, user-defined functions can receive arguments. Arguments are defined using the <cfargument> tag. If no default is defined with the default attribute, then the argument is required.

<cffunction name="function_name" returntype="type"> <cfargument name="arg" type="type" default="default"> </cffunction>

Here is an example user-defined function for adding numbers.

Code Sample:

ReusingCode/Demos/UDF.cfm
<html>
<head>
<title>User-defined Function</title>
</head>

<body>
<cfset total = addNums(1)>
<cfoutput>#total#</cfoutput>
</body>
</html>

<cffunction name="addNums" returntype="numeric">
	<cfargument name="num1" type="numeric">
	<cfargument name="num2" type="numeric" default="0">
	<cfargument name="num3" type="numeric" default="0">
	<cfset sum=num1 + num2 + num3>
	<cfreturn sum>
</cffunction>
            

Notice that user functions are called in the same way as built-in functions.

Creating a File2Table Function

Duration: 20 to 30 minutes.

In this exercise, you will modify RunningLog.cfm to include a function that creates a table from a tab-delimited text file.

  1. Open ReusingCode/Exercises/RunningLog.cfm in your editor.
  2. Create a function called File2Table that takes two arguments: the path to the file and an array of the table headers.
  3. Modify the page so that the function contains all the processing code that loads the file and creates and returns an HTML table.
  4. If the file cannot be opened, the function should return "File not found".
  5. the function and send the result to the browser.

Add formatting functionality to the function. For example, make the border size and the background color of the table controlled by the function call.

The function currently has the headers hardcoded in. This is not great for reuse. Change this so the function excepts a Headers array and loops through the array to output the headers.

Solution:

ReusingCode/Solutions/RunningLog.cfm
<html>
<head>
  <title>Running Log</title>
  <style type="text/css">
  	.grayBg {background-color:#cccccc; font-style:italic;}
	.whiteBg {background-color:#ffffff; font-weight:bold}
  </style>
</head>
<body>
<h1>Running Log</h1>
<a href="AddEntry.cfm">Add Entry</a><hr/>
<cfoutput>#File2Table("Logs/RunningLog.txt")#</cfoutput>
</body>
</html>
<cffunction name="File2Table" returntype="string">
	<cfargument name="PathToFile" type="string" required="yes">
	
	<cfset FullPath = ExpandPath(ARGUMENTS.PathToFile)>
	<cfset CrLf = chr(10) & chr(13)>
	<cfif FileExists(FullPath)>
		<cffile action="read" file="#FullPath#" variable="myfile">
		
		<cfsavecontent variable="Table">
			<cfoutput>
			<table border="1" bgcolor="##ccccff">
			<tr>
				<th>Date</th>
				<th>Distance</th>
				<th>Time</th>
				<th>Comments</th>
			</tr>
			<cfloop list="#myfile#" index="run" delimiters="#CrLf#">
				<cfif NOT isDefined("bg") OR bg EQ "grayBg">
					<cfset bg="whiteBg">
				<cfelse>
					<cfset bg="grayBg">
				</cfif>
			
				<tr class="#bg#">
				<cfloop list="#run#" index="col" delimiters="#chr(9)#">
					<td>#col#</td>
				</cfloop>
				</tr>
			</cfloop>
			</table>
			</cfoutput>
		</cfsavecontent>
		<cfreturn Table>
	<cfelse>
		<cfreturn "File not found.">
	</cfif>
</cffunction>
            

Challenge Solution:

ReusingCode/Solutions/RunningLog-challenge.cfm
---- C O D E   O M I T T E D ----
<cffunction name="File2Table" returntype="string">
	<cfargument name="PathToFile" type="string" required="yes">
	<cfargument name="OddColor" type="string" default="##ffffff">
	<cfargument name="EvenColor" type="string" default="##cccccc">
	
	<cfset FullPath = ExpandPath(ARGUMENTS.PathToFile)>
	<cfset CrLf = chr(10) & chr(13)>
	<cfif FileExists(FullPath)>
		<cffile action="read" file="#FullPath#" variable="myfile">
		
		<cfsavecontent variable="Table">			
			<cfoutput>
			<table border="1" bgcolor="##ccccff">
			<tr>
				<th>Date</th>
				<th>Distance</th>
				<th>Time</th>
				<th>Comments</th>
			</tr>
			<cfloop list="#myfile#" index="run" delimiters="#CrLf#">
				<cfif NOT isDefined("bg") OR bg EQ ARGUMENTS.EvenColor>
					<cfset bg=ARGUMENTS.OddColor>
				<cfelse>
					<cfset bg=ARGUMENTS.EvenColor>
				</cfif>

				<tr bgcolor="#bg#">
				<cfloop list="#run#" index="col" delimiters="#chr(9)#">
					<td>#col#</td>
				</cfloop>
				</tr>
			</cfloop>
			</table>
			</cfoutput>
		</cfsavecontent>
		<cfreturn Table>
	<cfelse>
		<cfreturn "File not found.">
	</cfif>
</cffunction>

Challenge Solution:

ReusingCode/Solutions/RunningLog-challenge2.cfm
---- C O D E   O M I T T E D ----
<cffunction name="File2Table" returntype="string">
	<cfargument name="PathToFile" type="string" required="yes">
	<cfargument name="Headers" type="array" required="yes">
	<cfargument name="OddColor" type="string" default="##ffffff">
	<cfargument name="EvenColor" type="string" default="##cccccc">
	
	<cfset FullPath = ExpandPath(ARGUMENTS.PathToFile)>
	<cfset CrLf = chr(10) & chr(13)>
	<cfif FileExists(FullPath)>
		<cffile action="read" file="#FullPath#" variable="myfile">
		
		<cfsavecontent variable="Table">			
			<cfoutput>
			<table border="1" bgcolor="##ccccff">
			<tr>
				<cfloop index="i" from="1" to="#ArrayLen(ARGUMENTS.Headers)#">
					<th>#ARGUMENTS.Headers[i]#</th>
				</cfloop>
			</tr>
---- C O D E   O M I T T E D ----
</cffunction>

Creating a Function Library

Duration: 5 to 10 minutes.

In this exercise, you will move the function you created in the last exercise into a function library and then include that library in RunningLog2.cfm with <cfinclude>.

  1. Open ReusingCode/Exercises/RunningLog.cfm in your editor and save it as RunningLog2.cfm.
  2. Cut the File2Table function and paste it in a new file. Save the new files as Functions.cfm.
  3. Add code to RunningLog2.cfm so that it includes the new function library.

Solution:

ReusingCode/Solutions/RunningLog2.cfm
               <cfinclude template="Functions.cfm">
<html>
<head>
  <title>Running Log</title>
</head>
<body>
<h1>Running Log</h1>
<a href="AddEntry.cfm">Add Entry</a><hr/>
<cfset arrHeaders = ArrayNew(1)>
<cfset ArrayAppend(arrHeaders,"Date")>
<cfset ArrayAppend(arrHeaders,"Distance")>
<cfset ArrayAppend(arrHeaders,"Time")>
<cfset ArrayAppend(arrHeaders,"Comments")>
<cfoutput>#File2Table("Logs/RunningLog.txt",arrHeaders,"pink","lightblue")#</cfoutput>
</body>
</html>