ColdFusion's new onMissingTemplate() function is a great addition to our toolbox, and mind blowingly useful for Dynamic Page Generation, but (as Ben Nadel notes) the problem of requiring a ColdFusion template to be requested in order to invoke the functionality has yet to be addressed.
In the most recent issue of the Fusion Authority Quarterly Update, Michael Dinowitz covers the onMissingTemplate functionality of Application.cfc -- new in ColdFusion 8 -- and how you can use it for Dynamic Page Generation, so for the most part I will not be covering that in this article. The FAQU article was terrific, hopefully opening the eyes of developers everywhere to the dynamic possibilities over and above error trapping (just like onMissingMethod). I wish I could link directly to the article, but you're going to have to buy the magazine. It's worth every penny, and tax deductible, so what are you waiting for?
I've got a working solution to this problem, and I thought I would share it with you in the interest of making it better. If you have ideas for improvement, please leave them in the comments.
A client of mine that provides a service to thousands of brick-and-mortar shops asked me to come up with a solution that would allow them to provide an informational page, possibly up to two or three (think in the terms of a very small company website) for each of their shops as part of their website. Pages like myclient.com/foo/ and myclient.com/bar/.
Sure, I could get dirty with the CFDIRECTORY and CFFILE tags, creating the foo and bar directories as needed; but like I said, there are thousands of clients. Trying to manage thousands of folders like this would quickly become cumbersome, not to mention the ridiculous amount of code duplication. What if a change needed to be made to one of the contained CFM files? Would you want to be the one to have to copy and paste the new file in, or write a script to copy it to all of the new folders? What if thousands of customers became hundreds of thousands? Could the file system handle that? Even if it could, think about how inefficient looping over the query returned from CFDIRECTORY would be.
Instead, what I decided to do was use onMissingTemplate() to dynamically generate these pages at run-time, from data stored in my client's database.
Essentially, a request comes in for myclient.com/foo/index.cfm, the file isn't found, and the error is handled by onMissingTemplate(). In this function, I simply check that the requested URL is in the format I'm expecting -- specifically that it has a single sub-folder from the root, and wants some .cfm file inside that folder. If this is the case, and the shop-site requested is defined in the database, and matches some business rules, I cfinclude my template that handles the shop-site request. Otherwise, log the error and return false; which runs my site-wide 404 handler.
<cffunction name="onMissingTemplate" returnType="boolean" output="true">
<cfargument name="targetpage" required="true" type="string">
<cfset var shop = listGetAt(arguments.targetPage, 1, "/") />
<cfif listLen(arguments.targetPage) eq 2
and right(arguments.targetPage, 4) is ".cfm">
<!--- apply business rules as necessary --->
<cfset request.shop = shop />
<cfinclude template="/shop/DynamicPageGenerator.cfm" />
<cfreturn true />
<cfreturn false />
If you would like more information on using onMissingTemplate for Dynamic Page Generation, I suggest you pick up a copy of the most recent edition of the FAQU.
My shop-site handler include parses the requested URL to determine which shop it needs to pull information for, and displays it. If the request was for index.cfm, I can display the content for the main page. If the request was for hours.cfm, I can display the content for the store hours page. To keep my dynamic page generation template clean, I create these page templates as further includes, which set up the page template for each page type. Don't think of them as files being requested, so much as messages being sent. "I need the store hours for foo."
On page 2 I'll show what problem this introduces, and the way that I resolve it with some simple ColdFusion code.