![]() |
Fusion Authority The House of Fusion Technical Magazine |
Issue:
18 April 10, 2000 April 16, 2000 |
| This is an opt-in magazine. To join, leave or change subscription mode, please visit the signup page. All content of this magazine is copyright Fusion Authority, Inc. It may not be reproduced without permission. | ||
[Top]
[Top]
[Top]
[Top]
[Top]
Allaire Announces Open License Program
[Top]
[Top]
[Top]
http://www.sys-con.com/xml/archives
[Top]
Yahoo Report on RadioWallStreet.com Broadcast
[Top]
Requires a separate database-specific custom tag (sample version supplied)to determine the datatypes of table columns.
[Top]
Solution: Workaround available at http://www.allaire.com/handlers/index.cfm?ID=15274.
[Top]
JRun 2.3.3: Too Many Concurrent JRun Requests Error Message
[Top]
[Top]
JRun 2.3.x: System Changes Made when Installing JRun on Windows NT
[Top]
Solution: This URL leads to a workaround.
File Upload Problems with IE 4.01
[Top]
Written / Researched By:
Fred T. Sanders and Nat Papovich
In Part I, we will be dealing with "Document Templates," which are stored in the "New Document" section of the File menu in Studio. By the end of this article, we will have several starter templates for you to start off your collection of generic, reusable code. The author uses the Fusebox method, and as these examples are taken from his collection, most will conform to that methodology. This is in no way an attempt to sell you on the Fusebox method and is just a matter of personal taste. Hopefully, with a better understanding of Document Templates, they will become an integral part of your development style and increase the speed, accuracy, and consistency of the coding of your applications.
You can make your own template directories under:
(Studio 4.0.1) "C:\Program Files\Allaire\ColdFusion Studio4\Wizards"
or
(Studio 4.5) " C:\Program Files\Allaire\ColdFusion Studio45\Wizards."
Once you "Save as Template," you will need to move them from the "Custom" folder into the subdirectory you have chosen. Hopefully, you can now see the importance of this tool, and will begin using it to its full potential.
We will be using the Application.cfm template for the speed benefit, initial application documentation, and a little extra Fusebox-specific template security. You will need to define two things in this template.
The first variable you will need to define is "request.root." This is the root of the application, not necessarily of the entire site. Since Application.cfm is not used for session management, we will actually assign a separate request.root value for each sub-application (smaller applications that are called from parent applications) as well. As an example, if you have a fusebox application in its own subdirectory (i.e., www.my-site.com/myapp), then you'll want ("request.root") to be "myapp."
Request.root is used for, but not limited to, site security. For instance, one of the Fusebox conventions is to have all applications called through the index.cfm. Let's say someone was trying to call a template directly, rather than going through index.cfm. With code using this variable, you can tell the application to redirect this user in the following ways:
1. Find an index.cfm in the directory of the template being called.
2. If there isn't one, then find an index.cfm in the immediate parent directory (which is supposed to be defined by #request.root#.)
3. If there isn't one, then go to the absolute root of the website and call that index.cfm.
Now this code has a problem, in that it will redirect while you're in development and you may not want this. Therefore, we've encapsulated all this code in a few <CFIF> statements that are based on a variable we set called "#attributes.published#." This is set by default to "NO". When we are ready to publish the application to its permanent home, we will set this to "YES" to enable the template security. If you are not using the Fusebox application framework, you'll need to modify this a bit before saving it as a "Document Template."
|
<!--- Application.cfm --->
<!----------------------------------------------------------- NAME: Application.cfm PURPOSE: DATE CREATED: AUTHOR: CHANGE HISTORY: -----------------------------------------------------------> <!--- Is this application published or still in development. "NO" = we are developing. "YES" = we are published. ---> <CFSET ATTRIBUTES.PUBLISHED = "NO"> <CFIF NOT ISDEFINED("request.domain")> <CFSET REQUEST.DOMAIN="#CGI.SERVER_NAME#"> </CFIF> <!--- Set Application's Root Directory Default ---> <CFIF #ATTRIBUTES.PUBLISHED# EQ "NO"> <!--- Do nothing; we are developing. ---> <CFELSE> <CFIF NOT ISDEFINED("request.root")> <!--- Insert Published Application's Root/Sub Directory Name, or leave blank.---> <CFSET REQUEST.ROOT = ""> </CFIF> </CFIF> <CFIF #ATTRIBUTES.PUBLISHED# EQ "NO"> <!--- Do nothing we are developing. ---> <CFELSE> <!--- Prevents someone from directly calling a template without going through our Fusebox. This will redirect them to the first page of the application, or to an index.cfm in the directory they're sticking their nose in. If that fails, it will redirect them to the main page of our application. ---> <CFIF FINDNOCASE("cfm",CGI.CF_TEMPLATE_PATH) AND NOT FINDNOCASE("index.cfm",CGI.CF_TEMPLATE_PATH)> <CFSET THISPATH = EXPANDPATH("*.*")> <CFSET THISDIRECTORY = GETDIRECTORYFROMPATH(THISPATH)> <CFIF FILEEXISTS(EXPANDPATH("index.cfm"))> <CFLOCATION URL = "index.cfm?badfile=yes"> <CFELSE> <CFIF REQUEST.ROOT IS NOT ""> <CFLOCATION URL = "/#request.root#/index.cfm?badfile=yes"> <CFELSE> <CFLOCATION URL = "/index.cfm?badfile=yes"> </CFIF> </CFIF> </CFIF> </CFIF> <!--- end Application.cfm ---> |
<!--- app_globals.cfm --->
<CFSETTING ENABLECFOUTPUTONLY="Yes">
<!--- Change form and URL variables to attributes variables. --->
<!--- This is to keep with the Fusebox Standard --->
<CFIF NOT ISDEFINED("attributes.fuseaction")>
<CF_FORMURL2ATTRIBUTES>
</CFIF>
<!--- Define Application name and turn on client and
session management settings --->
<CFAPPLICATION NAME = "" <!--- Application Name --->
CLIENTMANAGEMENT = "YES"
SESSIONMANAGEMENT = "YES"
SETCLIENTCOOKIES = "NO">
<!--- Set some global variables --->
<CFSCRIPT>
request.MainDSN = ""; // Define Data Source Name
request.MailServer = ""; // Define Mail Server (optional)
request.sysAdmin = "<A HREF='MAILTO:WEBMASTER@THIS-SITE.COM'>Webmaster</A>"; // Define Administrator Email
attributes.headerfile = "dsp_header.cfm"; // Define our Application Header File
attributes.footerfile = "dsp_footer.cfm"; // Define our Application Footer File
request.WeeklyCache = CreateTimeSpan(7,0,0,0); // Define Cache time for queries that need updating weekly
request.DailyCache = CreateTimeSpan(0,1,0,0); // Define Cache time for queries that need updating daily
request.HourlyCache = CreateTimeSpan(0,0,1,0); // Define Cache time for queries that need updating hourly
</CFSCRIPT>
<!--- Fusebox tag for CFID and CFTOKEN in Search Engine Friendly URLs--->
<CF_FUSETOKEN>
<CFSETTING ENABLECFOUTPUTONLY="No">
<!--- end global variables --->
|
app_locals.cfm
This template is used for defining our application's local variables. You will have one for each application and one for each of (if any) sub applications. A good analogy for this template and the app_globals.cfm template would be to compare the differences between your driver's license and the owner's manual for your car. You need your driver's license to operate any car. This is like your "app_globals.cfm" template, which affects every application and sub-application. The owner's manual is what you need to know to drive a specific car. This is like the "app_locals.cfm" template, which is specific to only one application. In this template, we'll define our application's stylesheet. If you do not wish to do so, just delete or comment out the include. I've named it "app_style.cfm" in the template code below. If you have several stylesheets, I would just include them from "app_style.cfm," or if you have only one stylesheet, then store it there. The other four parameters to define will be the default values for your site's page title, keywords associated with the site, page description for, and possibly the search engine robot directives. We will change these settings dynamically within our fuseactions (located in our "index.cfm" template).
<!--- app_locals.cfm ---> <!--- Include Global Application Settings---> <CFINCLUDE TEMPLATE = "app_globals.cfm"> <!--- Get Our Stylesheet ---> <!--- Optional ---> <CFINCLUDE TEMPLATE = "app_style.cfm"> <!--- Set Any Local Application Variables ---> <CFPARAM NAME = "request.title" DEFAULT = ""> <!--- Set Default Application Title---> <CFPARAM NAME = "request.keywords" DEFAULT = ""> <!--- Application Keywords---> <CFPARAM NAME = "request.description" DEFAULT = ""> <!--- Set Default Application Description---> <CFPARAM NAME = "request.robots" DEFAULT="index,follow"> <!---(index, noindex; follow, nofollow)---> <!--- end app_locals.cfm ---> |
app_layout.cfm
This is the default template used by the Fusebox BODYCONTENT tag. No changes need to be made to this template. It is simply added to the collection for convenience when starting a new project.
<!--- app_layout ---> <!--- Used In Conjuction With The Fusebox BODYCONTENT Custom Tag. ---> <CFPARAM NAME="attributes.headerfile"> <CFPARAM NAME="attributes.footerfile"> <CFPARAM NAME="request.bodycontent"> <CFPARAM NAME="attributes.showbody" DEFAULT="yes"> <CFIF LEN(ATTRIBUTES.HEADERFILE)><CFINCLUDE TEMPLATE = "#attributes.headerfile#"> </CFIF> <CFIF ATTRIBUTES.SHOWBODY><CFOUTPUT>#request.bodycontent#</CFOUTPUT></CFIF> <CFIF LEN(ATTRIBUTES.FOOTERFILE)><CFINCLUDE TEMPLATE = "#attributes.footerfile#"> </CFIF> <!--- end app_layout---> |
dsp_header.cfm
This template is just a header template. The only things you may want to change are the Meta Tags. You may also want to go ahead and fill out the HTML comment provided at the bottom with author information, etc. Remember: Only fill out what is unlikely to change. Leave all "#request.?????#" variable references alone, as we will change these dynamically within our fuseactions.
<!--- dsp_header.cfm ---> <!--- This template is used in conjunction with the BODYCONTENT Fusebox Custom Tag. ---> <CFOUTPUT> <!DOCTYPE HTML PUBLIC "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN"> <META HTTP-EQUIV = "Content-type" CONTENT = "text/html; charset = US-ASCII"> <!--- Help prevent Page Caching ---> <META HTTP-EQUIV = "Expires" CONTENT = "Sun, 12 May 1996 00:36:05 GMT"> <HTML> <HEAD> <TITLE>#request.title#</TITLE> <META NAME = "robots" CONTENT = "#request.robots#"> <META NAME = "revisit-after" CONTENT = "5 days"> <META NAME = "rating" CONTENT = "General"> <META NAME = "DC.Language" SCHEME="RFC1766" CONTENT="EN"> <META NAME = "Description" CONTENT="#request.description#"> <META NAME = "Keywords" CONTENT="#request.keywords#"> <LINK REL = "SHORTCUT ICON" HREF = "http://#request.domain#/favicon.ico"> </HEAD> <!-- Title: Company: Coded by: Web Address: http://www.your-site.com <!--- replace ---> Email: webmaster@your-site.com <!--- replace ---> --> </CFOUTPUT> <!--- end dsp_header.cfm ---> |
dsp_footer.cfm
This template, like the header template above, shouldn't really need changing, and this is the bare minimum required in it. What I will often do (once I've decided on a page layout) is to include everything from the end of the page body that isn't going to change, as well as the closing HTML tags for the entire document. I'm providing bare minimum here; modify any way you like.
<!--- dsp_footer.cfm ---> </HTML> <!--- end dsp_footer.cfm---> |
Index.cfm
This is probably one of the most important templates in this set. This is where everything comes together. All of the links in a Fusebox application point here. Other than defining your fuseactions, there is not much extra that needs to be done here. In Part II, we will build a "Fuseaction" Code Template (among others) to help speed this along.
<!--- index.cfm --->
<CFTRY>
<!--- Call Local Application Variables.--->
<CFINCLUDE TEMPLATE="app_locals.cfm">
<!--- Set our Default Fuseaction. --->
<CFPARAM NAME="attributes.fuseaction" DEFAULT="Main">
<!--- Call BODYCONTENT Fusebox Tag to define page layout. --->
<CF_BODYCONTENT>
<!---
Set Allowable Fuseactions.
The following CFSWITCH expression defines what fuseactions
are allowed and what procedures to follow when a fuse-
action is called.
--->
<CFSWITCH EXPRESSION="#attributes.fuseaction#">
<CFCASE VALUE="Main">
<!--- Be sure to change the following to call page layout template. We're using dsp_body.cfm. --->
<CFINCLUDE TEMPLATE="dsp_body.cfm">
</CFCASE>
<!--- Insert Additional Fuseactions Here. --->
<!--- Define What to do if an invalid action is called. --->
<CFDEFAULTCASE>
<CFMODULE TEMPLATE="/#request.root#/index.cfm" FUSEACTION="#attributes.defaultfuseaction#">
</CFDEFAULTCASE>
</CFSWITCH>
<!--- end of fuseaction definitions --->
</CF_BODYCONTENT>
<CFINCLUDE TEMPLATE="app_layout.cfm">
<!--- Catch Page Errors and Display Message --->
<CFCATCH TYPE="Any">
<!--- You can have this do whatever you want it to do
when an error occurs.--->
<CFOUTPUT>#cfcatch.message#</CFOUTPUT>
</CFCATCH>
</CFTRY>
<!--- end of index.cfm --->
|
That's it for our Document Templates. Please stay tuned for Part II, "Code Templates," for another exciting but under-valued tool to help you on your way to faster application coding.
[Top]
When I have a problem with my code, I like to debug by 'thinking as the server.' This means walking through the code step by step as if I was the ColdFusion server and seeing what is actually happening. I'll actually talk more about this in another article, but this time I'd like to talk about two things I've discovered in one of these 'walks'.
The first thing is that Application.cfm and OnRequestEnd.cfm are required by the ColdFusion server. When I say required, I don't mean that a template will not work without them but that the ColdFusion server expects them to always exist.
Let's imagine we're the ColdFusion server and we've just been asked to process a page. The first thing we do is to see if an Application.cfm exists in memory for this directory. If not, we'll look at the directory to see if one is there. If we still can't find it, we'll go to the parent directory and do the operation again (check memory and then check disk). This process will continue until we have checked all the way up to the drive root (Yes, the ColdFusion server looks all the way to the drive root rather than to the web or ColdFusion root.) At this point, if we haven't found any Application.cfm files, we simply assume that none exist and start to process the template that was actually requested. Once we're done with the template, we'll do the exact same search for the OnRequestEnd.cfm template.
These searches are actually rather fast and probably don't even show up on the resource monitors, but they do exist. For this reason, I suggest every application has an Application.cfm and an OnRequestEnd.cfm file, even if it simply contains a space character (Template must contain at least one character or an error will occur).
The second thing I found is that the way most people set their variables inside Application.cfm templates is wrong. Again, let's act as the ColdFusion server and process a page, but this time let's just focus on the Application.cfm file.
Someone requests the template index.cfm. Before that template is run, the Application.cfm template is processed. The first line is a CFAPPLICATION tag, which says that index.cfm is part of an application. The next line is a CFSET with a variable of Application.DSN and a value of "datasource". A few more CFSETs are used for different application variables and by the time we're ready to process index.cfm, four variables have been written to memory for this application. So far, so good. The next minute, someone (the same person or someone else, it doesn't matter) asks for a template called outdex.cfm in the same directory. Again, we start with the Application.cfm. The first line is the CFAPPLICATION tag that says that outdex.cfm is part of an application, the same application as index.cfm. This means that it can share the same memory-based variables. The next line is a CFSET with a variable of Application.DSN and a value of "datasource". A few more CFSETs are used for different application variables and, by the time we're ready to process index.cfm, four variables have been written to memory for this application.
Can you see what's wrong here?
If an application variable was set once, why are we setting it again? Why are we setting application.DSN on EVERY template call we make? There's no reason and, in some cases, this can run into variable overwrite errors (in CF 4.0x especially). Instead, what we should be doing is setting the application variables once and never again. This avoids extra work on every page and avoids the potential for errors. This method should be used for Session variables as well.
Old Way
|
<CFSET Application.DSN = "DataSource">
<CFSET Application.Path = "/"> <CFSET Application.Images = "/images/"> <CFSET Application.Attachments = "c:\cfusion\attachments\"> |
New Way
|
<CFIF Not IsDefined('Application.DSN')>
<CFSET Application.DSN = "DataSource"> <CFSET Application.Path = "/"> <CFSET Application.Images = "/images/"> <CFSET Application.Attachments = "c:\cfusion\attachments\"> </CFIF> |
The application variables will only be created if they don't already exist. I use Application.DSN as the 'key' value as most programmers use this to dynamically set their data source names. Finally, you can add a CFLOCK inside the CFIF statment if you are using CF 4.0x.
[Top]
| This is an opt-in magazine. To join, leave or change subscription mode, please visit the signup page. All content of this magazine is copyright Fusion Authority, Inc. It may not be reproduced without permission. | ||