ColdFusion has two methods that help you determine which templates are being executed:
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 »
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 »
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 »
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 »
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 »
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 »
... 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
Comments (3) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
Ignorance Rears Its Ugly Head Again
Nylon Technology Presentation: Introduction To XPath And XmlSearch() In ColdFusion
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.
Posted by Kris on Jul 16, 2007 at 2:38 AM
@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.
Posted by Ben Nadel on Jul 16, 2007 at 7:14 AM
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.
Posted by Elliott Sprehn on Jul 17, 2007 at 6:01 PM