Sunday, 3 August 2014

CFML: That <cfexit> bug I thought I had spotted: solved

G'day:
Yesterday I asked for some help understanding a mismatch between some code and some docs: "Are the docs for <cfexit> wrong, or am I misunderstanding?".

I just looked at this some more, and discovered the docs are right, Railo is right, and <cfexit> is right. However there's still a bug in ColdFusion...

Here's a refined repro case:

<!--- testusingCfimport.cfm --->
<cfimport taglib="." prefix="t">
<t:basic>
    Text within tags<br>
</t:basic>
<hr>

<t:basic exitMethod="exittag">
    Text within tags<br>
</t:basic>
<hr>

<t:basic exitMethod="exittemplate">
    Text within tags<br>
</t:basic>
<hr>

<!--- basic.cfm --->
<cfparam name="attributes.exitMethod" default="">
executionMode: <cfoutput>#thisTag.executionMode#</cfoutput><br>
<cfif thisTag.executionMode EQ "start">
    <cfif len(attributes.exitMethod)>
        exitMethod: <cfoutput>#attributes.exitMethod#</cfoutput><br>
        <cfexit method="#attributes.exitMethod#">
    <cfelse>
        exitMethod: not specified<br>
        <cfexit>
    </cfif>
</cfif>

So what happens here is that I demonstrate each method of <cfexit> except for loop: basically demonstrating each of these:
<cfexit>
<cfexit method="exittag">
<cfexit method="exittemplate">

The output is thus:

executionMode: start
exitMethod: not specified


executionMode: start
exitMethod: exittag


executionMode: start
exitMethod: exittemplate
Text within tags
executionMode: end



Note the default behaviour mirrors exittag, which is exactly what it suggests in the docs, and is exactly what Railo does too. So there's no error anywhere here.

However now I use a CFScript version of the tag:

// scriptVersion.cfm
param attributes.exitMethod="";

writeOutput("executionMode: #thisTag.executionMode#<br>");
if (thisTag.executionMode == "start"){
    if (len(attributes.exitMethod)){
        writeOutput("exitMethod: #attributes.exitMethod#<br>");
        exit attributes.exitMethod;
    }else{
        writeOutput("exitMethod: not specified<br>");
        exit;
    }
}

Same logic: just script instead of tags. The test rig for this is the same as the first one, just calling scriptversion instead of basic:

<!--- testScriptVersion.cfm --->
<cfimport taglib="." prefix="t">
<t:scriptversion>
    Text within tags<br>
</t:scriptversion>
<hr>

<t:scriptversion exitMethod="exittag">
    Text within tags<br>
</t:scriptversion>
<hr>

<t:scriptversion exitMethod="exittemplate">
    Text within tags<br>
</t:scriptversion>
<hr>

And the output on CF11?

executionMode: start
exitMethod: not specified
Text within tags
executionMode: end


executionMode: start
exitMethod: exittag


executionMode: start
exitMethod: exittemplate
Text within tags
executionMode: end




So <cfexit> behaves one way, and just exit behaves another way. That's a bug in the implementation of exit then. I will raise an issue accordingly: 3799016.



Do you want to know something funny (at my expense)? Well one might wonder why I am looking at custom tags, suddenly. Well it's because I am in the throes of teaching myself PHP, and I had started by working my way through the CFML tags, and quickly arrived at <cfassociate> (which is a custom-tag-specific tag). So the first thing I decided to do is check how CFML's and PHP's implementations of custom tags goes. So I did all the CFML groundwork, only to then discover... PHP doesn't have the concept of custom tags. Doh! That's 1-0 to CFML, but a bit of a waste of my time over the last few days, getting up to speed with Railo's CFC-based custom tags, and looking at <cfexit> etc. Oh well.

Back to the PHP now...

--
Adam