Skip to main content
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Guust Nieuwenhuis
Ben Nadel at cf.Objective() 2013 (Bloomington, MN) with: Guust Nieuwenhuis ( @Lagaffe )

ColdFusion Application.cfc OnRequest() Creates A Component Mixin

By on
Tags:

A lot of people have trouble wrapping their heads around the OnRequest() event method of the ColdFusion Application.cfc component. I have to admit, at first, you just accept that it works, but you don't quite understand the magic that's behind it. The truth is, the OnRequest() event method really treats the target template as a component mixin. Understanding this will really help you to see what data the requested page has access to and in what context the page is actually executing.

Let's take a look at a standard OnRequest() Application.cfc event:

<cffunction
	name="OnRequest"
	access="public"
	returntype="boolean"
	output="true"
	hint="Executes the requested ColdFusion template.">

	<!--- Define arguments. --->
	<cfargument
		name="TargetPage"
		type="string"
		required="true"
		hint="The requested ColdFusion template."
		/>

	<!--- Include the requested ColdFusion template. --->
	<cfinclude template="#ARGUMENTS.TargetPage#" />

	<!--- Return out. --->
	<cfreturn true />
</cffunction>

And, let's assume that the target page being passed into the OnRequest() event method is this HTML page:

<html>
<head>
	<title>OnRequest() Mixin</title>
</head>
<body>

	<p>
		This is the target page. Sweet!
	</p>

</body>
</html>

In this event code, the user-requested page is passed in as the only argument. We then, turn around and CFInclude that target page for execution (the mixin aspect). People get so caught up on the whole newness of the Application.cfc that they forget what CFInclude does: it includes the target template into the current page of execution.

Understanding that, we can actually get rid of the CFInclude totally and rewrite the above OnRequest() event method to look like this:

<cffunction
	name="OnRequest"
	access="public"
	returntype="boolean"
	output="true"
	hint="Executes the requested ColdFusion template.">

	<!--- Define arguments. --->
	<cfargument
		name="TargetPage"
		type="string"
		required="true"
		hint="The requested ColdFusion template."
		/>

	<!--- Include the requested ColdFusion template. --->
	<!---
		<cfinclude template="#ARGUMENTS.TargetPage#" />
	--->

	<!---
		Instead of CFIncluding the target template,
		let's just rewrite the event method to actually
		contain the target template code. This
		accomplishes the exact same thing. We are just
		skipping the middle man.
	--->
	<html>
	<head>
		<title>OnRequest() Mixin</title>
	</head>
	<body>

		<p>
			This is the target page. Sweet!
		</p>

	</body>
	</html>

	<!--- Return out. --->
	<cfreturn true />
</cffunction>

Once you see the OnRequest() application event written in this manner, it becomes much easier to understand the context in which the page is executing. The target page is really PART OF the Application.cfc, and more specifically, it is actually PART OF the OnRequest() event code. Therefore, it has access to all local variables of the OnRequest() event method as well as all public and private variables of the Application.cfc's THIS and VARIABLES scope.

Now that we are beginning to bridge this mental gap, it becomes more clear why Application.cfc-scoped methods are available to OnRequest() included pages and why something like this:

<html>
<head>
	<title>OnRequest() Mixin</title>
</head>
<body>

	<p>
		This is the target page. Sweet!
	</p>

	<!---
		Output the page passed to the OnRequest()
		event method.
	--->
	<p>
		<cfoutput>
			TargetPage: #ARGUMENTS.TargetPage#
		</cfoutput>
	</p>

</body>
</html>

... will not bomb out, but will in fact output the template path passed to the OnRequest() event method.

Understanding the concept of the Mixin really helped me get my head fully wrapped around the concept of the OnRequest() event method. I hope that this has cleared a few things up for you.

Want to use code from this post? Check out the license.

Reader Comments

29 Comments

Also cool is the ability to use CFM pages as modules, instead of includes.

<cfinclude template="#arguments.targetPage#"/>

<cfmodule template="#arguments.targetPage#"/>

You can then do some fancy stuff, like pass attributes.

<!--- <cfset uri="/blog/805-ColdFusion-Application-cfc-OnRequest-Creates-A-Component-Mixin.htm"/> --->
<cfset article=reReplace(uri, "^/blog/(\d+)-.+.htm$", "\1", "all")/>
<cfmodule template="#arguments.targetPage#" article="#article#"/>

15,674 Comments

@Alex,

True, but in that you are no longer creating a Mixin (which is really what this post was about). Since custom tags exist in their own memory space, you will need to explicitly use the CALLER scope to reach back up into the Application.cfc.

Custom tags are definitely cool; but, you really have to pick one or the other as they have extremely different behaviors - you can't just swap between the two.

29 Comments

You can also is Ben's technique to do page-specific mixins.

Separate your business logic from display logic!

This is similar to code behind files in ASP.NET. (Although ASP.NET provides late bind and other stuff.)

Keep in mind this is simplified to demonstrate. This just does pre-processing. Theoretically, you could also perform post-processing, late bind, et al cool tricks.

application.cfc
<cfcomponent output="false">
<cffunction name="onRequest"><
cfset var temp={}/><
cfsilent>
<cfif (fileExists(expandPath(reReplace(arguments[1], "\.cfm$", ".cfc", "all"))))>
<cfset data=createObject("component", arrayToList(listToArray(reReplace(arguments[1], "\.cfm$", "", "all"), "/"), ".")).init()/>
</cfif>
<cfsavecontent variable="temp.body"><cfinclude template="#arguments[1]#"/></cfsavecontent>
<cfset temp.body=trim(temp.body)/>
</cfsilent
><cfoutput>#toString(temp.body)#</cfoutput><
/cffunction>
</cfcomponent>

samplepage.cfc
<cfcomponent output="false">
<cffunction name="init" output="false">
<cfset var temp={}/>
<cfset temp.data="foo"/>
<cfreturn temp.data/>
</cffunction>
</cfcomponent>

samplepage.cfm
<div>data: <cfdump var="#data#"/></div>

@Ben, I guess I need my own blog, so I stop mucking up yours. :) -AH

1 Comments

I have a weird newbie problem. I've recently (tried) to move from application.cfm to .cfc. I found and used a generic template. When I delete or comment out the onRequest function, the site starts substituting blank white pages. With it left in all is well, but a critical page seems to hang (sporadically) at the cfinclude. Really trying to get it, but I have a permanent case of brain cloud:

<cffunction name="OnRequest" access="public" returntype="void">
<cfargument name="TargetPage" type="string" required="true" />
<cfinclude template="#ARGUMENTS.TargetPage#" />
</cffunction>
Any help would be more than appreciated!

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel