Closing The 404 Gap For Dynamic Page Generation With onMissingTemplate()

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.

The Problem

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.

The Solution

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 />
</cfif>
<cflog ...>
<cfreturn false />
</cffunction>

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.

Average: 4.7 (3 votes)

Comments

Boyan Kostadinov replied on Thu, 2008/03/13 - 9:11am

Neat ColdFusion based solution. However, here are a couple of points to consider:

  1. Your error handler assumes port 80 and probably should pick the port from the CGI scope
  2. Since you have to edit the server config anyway, a better solution would be to use mod_rewrite (for Apache) or Ionic's ISAPI rewrite (for IIS)

Adam Tuttle replied on Thu, 2008/03/13 - 9:35am

Boyan, I don't entirely disagree with you, but can you explain why URL rewriting is a better solution?

Boyan Kostadinov replied on Thu, 2008/03/13 - 9:45am

Adam, a few reasons:

  1. It is language independant. I don't think that needs any more details.
  2. It is faster since it hooks right into the web server through a module or dll.
  3. It is easier to manage and maintain. All you have to do to extend and/or change things is edit the .htaccess file (Apache) or the .ini file (IIS)
  4. It is more powerful since it supports regular expression.

Adam Tuttle replied on Thu, 2008/03/13 - 10:03am

Boyan, all good points. That said, in some shared hosting environments, people are given the ability to specify custom error pages, but not much else in terms of server config. In that case, running an ISAPI filter may not be an option.

I did assume port 80, but 99 times out of 100, your website will be hit on port 80, and if not, it's easy enough to know that and to account for it, as you pointed out. 

ColdFusion supports regular expressions, so that argument doesn't hold much water. In fact, I would argue that a custom ColdFusion 404 error handling script could be more powerful because of all of the options available to you when writing a CF script. You could log, email, and even send yourself an IM or text message if there are errors - none of which you have direct control over with mod_rewrite or an IIS ISAPI filter (to the best of my knowledge).

In the end, I think there are multiple ways to skin this cat -- none of them really wrong. It's all about personal preference.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.