coldfusioncoldfusion-7bluedragon

Custom CFInclude for file customization


Our code base has quite a bit of the following example as we allow a lot of our base pages to be customized to our customers' individual needs.

<cfif fileExists("/custom/someFile.cfm")>
    <cfinclude template="/custom/someFile.cfm" />
<cfelse>
    <cfinclude template="someFile.cfm" />
</cfif>

I wanted to create a custom CF tag to boilerplate this as a simple <cf_custominclude template="someFile.cfm" />, however I ran into the fact that custom tags are effectively blackboxes, so they aren't pulling in local variables that exist prior to the start of the tag, and I can't reference any variable that was created as a result of the tag from importing the file.

E.G.

<!--- This is able to use someVar --->
<!--- Pulls in some variable named "steve" --->
<cfinclude template="someFile.cfm" />
<cfdump var="#steve#" /> <!--- This is valid, however... --->

<!--- someVar is undefined for this --->
<!--- Pulls in steve2 --->
<cf_custominclude template="someFile.cfm" />
<cfdump var="#steve2#" /> <!--- This isn't valid as steve2 is undefined. --->

Is there a means around this, or should I utilize some other language feature to accomplish my goal?


Solution

  • Well, I question doing this at all but I know we all get handed code at times we have to deal with and the struggle it is to get people to refactor.

    This should do what you are wanting. One important thing to note is that you will need to ensure your custom tag has a closing or it won't work! Just use the simplified closing, so like you had it above:

    <cf_custominclude template="someFile.cfm" />
    

    This should do the trick, called it has you had it : custominclude.cfm

    <!--- executes at start of tag --->
    <cfif thisTag.executionMode eq 'Start'>
        <!--- store a list of keys we don't want to copy, prior to including template --->
        <cfset thisTag.currentKeys = structKeyList(variables)>
        <!--- control var to see if we even should bother copying scopes --->
        <cfset thisTag.includedTemplate = false>
        <!--- standard include here --->
        <cfif fileExists(expandPath(attributes.template))>
            <cfinclude template="#attributes.template#">
            <!--- set control var / flag to copy scopes at close of tag --->
            <cfset thisTag.includedTemplate = true>
        </cfif>
     </cfif>
     <!--- executes at closing of tag --->
     <cfif thisTag.executionMode eq 'End'>
        <!--- if control var / flag set to copy scopes --->
        <cfif thisTag.includedTemplate>
            <!--- only copy vars created in the included page --->
            <cfloop list="#structKeyList(variables)#" index="var">
                <cfif not listFindNoCase(thisTag.currentKeys, var)>
                    <!--- copy from include into caller scope --->
                    <cfset caller[var] = variables[var]>
                </cfif>
            </cfloop>
        </cfif>
     </cfif>
    

    I tested it and it works fine, should work fine being nested as well. Good luck!

    <!--- Pulls in steve2 var from include --->
    <cf_custominclude template="someFile.cfm" />
    <cfdump var="#steve2#" /> <!--- works! --->