Detecting CFINCLUDE versus Custom Tag

This post is more than 2 years old.

JC Panzerpants asks:

Hey Ray! I've been googling for a good 45 minutes trying to find a way to do this... maybe you know off the top of your head. Is there a way for a CF file to determine how it's being accessed? Like, directly vs cfincluded vs cfmoduled etc. Mostly I'm interested in if it can tell whether it's being accessed directly or not, but being able to tell what the parent file is that's calling it would be useful too.

I'm trying to convert an old, big, messy 1000+ line application.cfm file into something readable, functional, and able to be edited without cringing in fear that one change might break other parts.

I'm absolutely sure I've seen a way to do this before, but all I've been able to find is the executionmode function for custom tags, which is nice, but not what I'm looking for...

Well there are a few things going on here and a few things we can try. For the simplest check - how can you tell a custom tag? One quick way is just do:

<cfif isDefined("attributes")>

This used to be sufficient, but don't forget that you also get an attributes scope inside cfthread. So the better check may be:

<cfif isDefined("attributes") and not isDefined("thread")>

Now, as to checking a cfincluded template, the only way I know of is to compare getBaseTemplatePath to getCurrentTemplatePath. getBaseTemplatePath always gets the "core" CFM whereas getCurrentTemplatePath returns the "active" one. I put this and the earlier code block together to form this:

<cfif isDefined("attributes") and not isDefined("thread")> I seem to be a custom tag. <cfelseif getBaseTemplatePath() neq getCurrentTemplatePath()> I seem to be an include <cfelse> I seem to be vanilla code. </cfif>

I then wrote this test:

<h2>Root</h2>

<cfif isDefined("attributes") and not isDefined("thread")> I seem to be a custom tag. <cfelseif getBaseTemplatePath() neq getCurrentTemplatePath()> I seem to be an include <cfelse> I seem to be vanilla code. </cfif>

<h2>CFInclude</h2>

<cfinclude template="test2.cfm">

<h2>Custom Tag</h2>

<cf_simpletag>

The contents of test2.cfm were the CFIF. Ditto in simpletag.cfm. The result seemed fine to me:

As for getting the immediate parent, that isn't quite as easy. If test1.cfm includes test2.cfm and test2.cfm includes test3.cfm, your base template path in test3.cfm will go all the way up to test1.cfm. The only way I know of to get that lineage in that case is with a try/catch and introspecting the tag context array.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by John Farrar posted on 4/2/2010 at 6:05 PM

Well let us consider this scenario.

Page A has custom tag script B as tag and script C via include.

Script B calls script C as include.

Results = On page A script c reports it is called as include. But on include call from within script B it will report with this logic that it is not called as an include.

Comment 2 by John Farrar posted on 4/2/2010 at 6:08 PM

P.S.
There is also many frameworks that turn the URL (get) and Form (post) variables into a common attribute scope. If someone is using one of those frameworks it will kill this test every time and report it is not happening via include.

You might use a try catch scenario with the parent tag list. It seems that would let you compare the current script name to the nested tag list. That should be more accurate.

Comment 3 by JC posted on 4/2/2010 at 6:13 PM

Thanks, Ray :)

Maybe StructKeyExists(variables,"thisTag") would be more effective than testing for attributes? but I'm not sure how it works as an include inside a custom tag or another blended situation.

Comment 4 by Steve Bryant posted on 4/2/2010 at 6:29 PM

Elliott Sprehn has a really nice function for getting information about the template calling a custom tag.

http://www.elliottsprehn.co...

Comment 5 by Tyler Clendenin posted on 4/4/2010 at 12:07 AM

One way to differentiate if the attributes scope was created by a custom tag call vs a framework is to also test StructKeyExists(variables, "attributes")

Comment 6 by Raymond Camden posted on 4/4/2010 at 12:17 AM

Slick Tyler.

Comment 7 by Adam Cameron posted on 4/4/2010 at 2:41 PM

Hi Ray
Re the try/catch tag context thing. If one's prepared to play slightly outside the square, one can simply instantiate a coldfusion.runtime.CustomException object, rather than actually throwing/catching one.

Or even just a vanilla java.lang.Exception has the tag context in there too.

--
Adam

Comment 8 by Raymond Camden posted on 4/4/2010 at 6:06 PM

@Adam: That's interesting. Do you have an example you can point to? Or if it is short and sweet you can post it as a comment.

Comment 9 by Adam Cameron posted on 4/5/2010 at 5:33 PM

<cfset oE = createObject("java", "coldfusion.runtime.CustomException").init("", "", "", "", "")>
<cfdump var="#oE#">

OR

<cfset oE = createObject("java","java.lang.Exception").init()>
<cfdump var="#oE#">

--
Adam

Comment 10 by Raymond Camden posted on 4/5/2010 at 8:01 PM

Thank you for sharing that Adam.

Comment 11 by Jon Hartmann posted on 4/6/2010 at 9:52 PM

Couldn't you just use IsDefined("ThisTag") ? Unlike Attributes, ThisTag is specified as being used only in custom tags.

Comment 12 by Jon Hartmann posted on 4/6/2010 at 9:52 PM

Ah, I see that JC beat me to it.