Anyone know how I could do an include from the con...
# cfml-general
s
Anyone know how I could do an include from the context of the calling page of a custom tag? If I have a test.cfm and an included.cfm in the same folder, then I want to call <cf_MyTag include="included.cfm"> and have MyTag.cfm (which sits in the CustomTags folder) include the "included.cfm" file that is in the same folder as "test.cfm". I realize that I could use cfsavecontent and pass the resulting string, but I'd rather have a nice syntax (also, I want to use the file name as well as the content of "included.cfm" from within my custom tag).
s
personally, if I needed to accomplish this, I would just pass the absolute path in the custom tag attribute like <cf_MyTag include="/path/to/included.cfm">
a
Not sure this is ideal, I believe
callStackGet
has some overhead to it, but:
Copy code
.../callingContextPath# tree .
.
|-- lib
|   `-- MyTag.cfm
|-- public
|   `-- test.cfm
`-- views
    `-- myView.cfm
Copy code
<!--- test.cfm --->
<cfinclude template="../views/myView.cfm">
Copy code
<!--- myView.cfm --->
<cfimport taglib="../lib" prefix="x">
<x:Mytag>
Copy code
<!--- MyTag.cfm --->
<cfset callStack = callStackGet()>
<cfset callingFile = callStack[2].template>
<cfset callingDir = getDirectoryFromPath(callingFile)>
<cfset includeRoot = expandPath("/")>
<cfset includePath = callingDir.replace(includeRoot, "/")>

<cfdump var="#[callingFile,includeRoot,includePath]#">
Copy code
Dump:

array
1	/app/cfml/cfmlLanguage/customtags/callingContextPath/views/myview.cfm
2	/app/
3	/cfml/cfmlLanguage/customtags/callingContextPath/views/
You'll like have to be less naive than this if there are mappings involved, etc. --- TBH, I would perhaps also question why you want to do this, and think about it rather than settling on "this is what I want to do".
s
generally speaking.... what are you doing that requires an actual custom tag? There are very rare cases that I ever use custom tags anymore as a CFC function is usually the better route
👍 1
s
@Adam Cameron
callStackGet
looks like the answer. A single call to it seems to take 0-1 ms, so I don't think that will be a problem. Thanks!
On the off-chance that anyone is interested in the final code, here it is:
Copy code
/**
* I get the contents of a file included from the calling page.
*/
private string function getIncludedFileContents(required string include) {
    var ThisPath = GetCurrentTemplatePath();
    var aCallStack = callStackGet();//Get the calling stack (Thanks Adam Cameron!)
    var callingFile = aCallStack.filter(function(item){
        return item.Template NEQ ThisPath;
    })[1]["Template"];//Get first matching template from the stack that isn't the current file.
    var callingDir = getDirectoryFromPath(callingFile);
    var includeRoot = expandPath("/");//Get root path
    var includePath = callingDir.replace(includeRoot, "/") & Attributes.include;//Get root-relative path
    var result = savecontent {
        include includePath;
    }//Get the contents of the file

    return result;
}
a
Not understanding why yer using that
filter
there. It's always gonna be the second one, innit? And there will always be at least two in there (custom tag file, and the file that calls it), so yer safe to just use the second one. Also bear in mind that
filter
always traverses the entire collection, so it's not gonna get the "first" one, it's gonna get all of them except the first one. Not that the callstack will ever be very big, but unless there's something I'm missing, it's just not the right tool for the job in this case.
e
I would define your custom tags in the Application cfc / cfm ie this.customTagPaths = "/Mycustomtags"; Then I would use the module functions as YOU CAN GET WAY MORE REFUSE <cfmodule template="X.cfm" code="#myXCode#" />
s
@Adam Cameron I did some experimenting and it wasn't always the second one. I did debate doing a straight loop so I could pop out of it as soon as I found a match, but I went with shorter code over performance in this case. Not sure that was the right call though...
a
Interesting. When was it not the second one?
s
When I put the code in a UDF, it bumped it a position. I think if I called that from a UDF then it would bump it again and I would like to have the flexibility to refactor my code without breaking it.
a
Right. Slight mix-up in your description "Anyone know how I could do an include from the context of the calling page of a custom tag?". Because if you call the custom tag from a UDF ("WTF???", btw 😉 ), then the UDF is the "calling page". But I see what yer getting at. Fair enough.
s
Heh! Yeah, the challenge is always clearly defining what we want, isn't it? Which is why AI still won't be able to do everything for us! 😉