Dynamic And Unexpected ColdFusion GetCurrentTemplatePath() Behavior

Posted July 13, 2007 at 8:28 AM

Tags: ColdFusion

ColdFusion has two methods that help you determine which templates are being executed:

  • GetCurrentTemplatePath()
  • GetBaseTemplatePath()

Normally, the GetCurrentTemplatePath() method will return the path of the template in which the method call resides. However, I just came across some unexpected behavior; if the method call is inside of a ColdFusion user defined function, then the GetCurrentTemplatePath() returns the path of the template that binds dynamically at runtime to the parent function. We're not even talking about the template that houses the UDF - we're talking about the template that binds to the UDF.

However, that is not even 100% consistent. If the GetCurrentTemplatePath() is inside of a ColdFusion template that is then included into a function, the GetCurrentTemplatePath() function returns the path of the housing template, not of the page that binds to the ColdFusion UDF at runtime.

Take a look at this example. I have two mixins. One is a mixin that contains a ColdFusion UDF that simply returns the current template path (GetPath.cfm):

 Launch code in new window » Download code as text file »

  • <cffunction
  • name="GetMixinPath"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns the current template's (this) file path.">
  •  
  • <!---
  • Return the path of the currently executing
  • template (this mixin function).
  • --->
  • <cfreturn GetCurrentTemplatePath() />
  • </cffunction>

The other mixin is a simple ColdFusion template which just outputs the current template path:

 Launch code in new window » Download code as text file »

  • <cfoutput>
  • #GetCurrentTemplatePath()#
  • </cfoutput>

Then, I have two ColdFusion components. I have my Base.cfc which has a defined method, GetBaseComponentPath(), which returns the current template path. It also has a method, GetBaseComponenMixintPath(), which includes the GetCurrentTemplatePath.cfm mixin and returns the outputted value:

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • output="false"
  • hint="Base component to be extended">
  •  
  • <cffunction
  • name="GetBaseComponentPath"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns the base component's (this) file path.">
  •  
  • <!---
  • Return the path of the currently executing
  • template (this component).
  • --->
  • <cfreturn GetCurrentTemplatePath() />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="GetBaseComponenMixintPath"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns the base component's (this) file path.">
  •  
  • <cfset var strPath = "" />
  •  
  • <!---
  • Include the template that outputs the
  • current template path.
  • --->
  • <cfsavecontent variable="strPath">
  • <cfinclude template="GetCurrentTemplatePath.cfm" />
  • </cfsavecontent>
  •  
  • <!--- Return the path of the mixin template. --->
  • <cfreturn Trim( strPath ) />
  • </cffunction>
  •  
  • </cfcomponent>

Then, I have the Extender.cfc ColdFusion component which extends the Base.cfc and includes the mixin GetPath.cfm:

 Launch code in new window » Download code as text file »

  • <cfcomponent
  • extends="Base"
  • output="false"
  • hint="The extending component.">
  •  
  • <cffunction
  • name="GetExtenderComponentPath"
  • access="public"
  • returntype="string"
  • output="false"
  • hint="Returns the current component's (this) file path.">
  •  
  • <!---
  • Return the path of the currently executing
  • template (this component).
  • --->
  • <cfreturn GetCurrentTemplatePath() />
  • </cffunction>
  •  
  •  
  • <!---
  • Include the mixin file that defines a function
  • for getting the current template path.
  • --->
  • <cfinclude template="./GetPath.cfm" />
  •  
  • </cfcomponent>

Ok, so now, I am gonna instantiate the Extender.cfc ColdFusion component and test all the various method returns for GetCurrentTemplatePath():

 Launch code in new window » Download code as text file »

  • <!--- Create our extender CFC instance. --->
  • <cfset objCFC = CreateObject( "component", "Extender" ) />
  •  
  • <h4>
  • CFC-Based Methods
  • </h4>
  •  
  • <p>
  • Getting the path via the Base.cfc method:<br />
  • #objCFC.GetBaseComponentPath()#
  • </p>
  •  
  • <p>
  • Getting the path via the Exnteder.cfc method:<br />
  • #objCFC.GetExtenderComponentPath()#
  • </p>
  •  
  • <p>
  • Getting the path via the mixin method:<br />
  • #objCFC.GetMixinPath()#
  • </p>
  •  
  • <p>
  • Getting the path via the Base.cfc mixin method:<br />
  • #objCFC.GetBaseComponenMixintPath()#
  • </p>
  •  
  •  
  • <!---
  • The above have all been called on methods of
  • a CFC. What happens if we include the mixin
  • method directly into the current template
  • (index.cfm) and then execute it that way.
  • --->
  •  
  • <h4>
  • Template-Based Methods
  • </h4>
  •  
  • <!--- Now, let's include the mixin into this template. --->
  • <cfinclude template="./GetPath.cfm" />
  •  
  • <p>
  • Getting the path via TEMPLATE mixin method:<br />
  • #GetMixinPath()#
  • </p>

Running the above, we get the following output:

CFC-Based Methods

Getting the path via the Base.cfc method:
D:\....\testing\app_extend\Extender.cfc

Getting the path via the Exnteder.cfc method:
D:\....\testing\app_extend\Extender.cfc

Getting the path via the mixin method:
D:\....\testing\app_extend\Extender.cfc

Getting the path via the Base.cfc mixin template/method:
D:\....\testing\app_extend\GetCurrentTemplatePath.cfm

Template-Based Methods

Getting the path via TEMPLATE mixin method:
D:\....\testing\app_extend\index.cfm

As you can see, the Base.cfc method, GetBaseComponentPath(), the Extender.cfc method, GetExtenderComponentPath(), and the Extender.cfc mixin method, GetMixinPath(), all dynamically bound themselves to the Extender.cfc at runtime, returning the Extender.cfc as the current template path (regardless of where GetCurrentTemplatPath() was defined). Even the index.cfm-based mixin method, GetPath(), bound dynamically to the index page at runtime.

The only thing that didn't seem to bind dynamically at runtime was the GetCurrentTemplatePath.cfm mixin which was a straight-up ColdFusion template, not a mixin method.

Something about this just rubs me the wrong way. I understand that function binding is highly dynamic, and this is a very powerful thing because it allows us to evaluate the THIS and VARIABLES scope at the point of reference, which, in turn, allows us to add, delete, and share methods across ColdFusion components. However, I don't feel that this is the intent of methods like GetBaseTemplatePath() and GetCurrentTemplatePath(). In fact, if you look at the documentation for GetCurrentTemplatePath(), it reads:

Returns: The absolute path of the page that contains the call to this function, as a string.

It doesn't mention anything here about dynamic runtime binding. Now, you might argue that the documentation then states:

If the function call is made from a page included with a cfinclude tag, this function returns the page path of an included page.

Here, at least it mentions the CFInclude usage. However, if that was the requirement, then using it within a CFModule of CFImport tag would not meet this criteria. Of course, if we invoke the GetCurrentTemplatePath.cfm as a module from WITHIN the index.cfm page:

 Launch code in new window » Download code as text file »

  • <cfmodule template="./GetCurrentTemplatePath.cfm">

... we get the following output:

D:\....\testing\app_extend\GetCurrentTemplatePath.cfm

Here, the GetCurrentTemplatePath() method is binding to the tag, not to the index page. This proves that CFInclude is NOT a requirement for the GetCurrentTemplatePath() method to work correctly.

So, long story short, I think the dynamic binding of the GetCurrentTemplatePath() to its housing ColdFusion component is not the expected behavior and seems to go against the ColdFusion documentation.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Jul 16, 2007 at 2:38 AM // reply »
2 Comments

Another interesting behavior i just notice a month a go with thegetTemplatePath() function.

If you add a call to this function in the application.cfm and on the url your accessing a cfm file the function return the actual path of the cfm page - but if your accessing a remote method of a cfc file the getTemplatePath() return the path to the application.cfm file.

note that this was not the behavior of the Coldfusion mx 6.1. In 6.1 the function returns the path to the cfc file as well.


Jul 16, 2007 at 7:14 AM // reply »
6,371 Comments

@Kris,

That is very interesting. I haven't done much yet with direct CFC calls. I am surprised that is has changed from version to version.


Jul 17, 2007 at 6:01 PM // reply »
123 Comments

I ran into a problem with this behavior while working on a project recently. I needed to get the path to the calling page inside a custom tag, which proved to be pretty complicated.

For anyone who's curious about the internals of the CF engine this sheds a lot of light on how function binding and includes/cfcs/custom tags really work inside the engine.

http://enfinitystudios.thaposse.net/blog/2007/07/17/getting-the-expected-results-for-getcurrenttemplatepath-in-a-custom-tag/


Post Comment  |  Ask Ben

Recent Blog Comments
Jill
Nov 7, 2009 at 11:40 AM
How To Unformat Your Code (Like A Pro)
Derek, I think you might be right - sweet! Thanks for the link :) ... read »
Nov 7, 2009 at 11:25 AM
How To Unformat Your Code (Like A Pro)
I think it would be way easier to just use this http://www.logichammer.com/html-formatter/ He just released v3 and it rocks. ... read »
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »
Nov 6, 2009 at 4:53 PM
How To Unformat Your Code (Like A Pro)
I tried to go *back* the other way. Adding formatting is actually a much more complicated problem than removing formatting. Anyway, here is what I could put together with a minimal amount of time: ... read »
Asaf
Nov 6, 2009 at 2:35 PM
ColdFusion GetPageContext() Massive Exploration
Hi, I actually found this post useful. I recently acquired a SSL certificate for my website and when I switched over to HTTPS Internet Explorer would throw an error when trying to download a dynamic ... read »
Nov 6, 2009 at 2:19 PM
How To Unformat Your Code (Like A Pro)
@Chuck, @Nathan, Well, now I feel like it's a challenge.... I accept. ... read »