Sorry, mentioned this on Twitter a few days ago now:
Today I learned that writeOutput() is not a direct analogy of <cfoutput> for simple expressions. And now I hate #CFML that tiny bit more.
— Adam Cameron (@dacCfml) January 13, 2014
...but not finding any time for writing at the moment. I'll make a start, and see how far I get.
Here's some sample code:
<!--- test.cfm --->
<cffunction name="usingCfoutput" output="true">
TEXT WITHIN usingCfoutput():<br>
<cfoutput>#generateContent()#</cfoutput>
</cffunction>
<cffunction name="usingWriteOutput" output="true">
TEXT WITHIN usingWriteOutput():<br>
<cfscript>writeOutput(generateContent());</cfscript>
</cffunction>
<cffunction name="generateContent" output="false">
<cfset var s = "">
<cfsavecontent variable="s">
BEFORE CFOUTPUT<br>
<cfoutput>IN OUTPUT<br></cfoutput>
AFTER CFOUTPUT<br>
</cfsavecontent>
<cfreturn s>
</cffunction>
<cfsetting enablecfoutputonly="true">
<cfoutput>Calling usingCfoutput():<br></cfoutput>
<cfset usingCfoutput()>
<cfoutput><hr></cfoutput>
<cfoutput>Calling usingWriteOutput():<br></cfoutput>
<cfset usingWriteOutput()>
Basically we've got:
- a function
generateContent()
, which generates and captures some text, returning it; - a function
usingCfOutput()
that callsgenerateContent()
from within<cfoutput>
tags; - another function
usingWriteOutput()
which does the same thing, except viawriteOutput()
.
- Oh, and I have a cheeky little
<cfsetting>
tag in there too.
Here's the output:
Calling usingCfoutput():
BEFORE CFOUTPUT
IN OUTPUT
AFTER CFOUTPUT
Calling usingWriteOutput():
IN OUTPUT
So when using
usingCFoutput()
, the <cfoutput>
tags around the call to generateContent()
are enough to fulfill the enablecfoutputonly
restriction that <cfsetting>
has set. So everything within generateContent()
counts as being in <cfoutput>
tags.However when using
usingWriteOutput()
, the writeOutput()
around the call to generateContent()
does not confer enough "outputness" to count towards fulfilling the enablecfoutputonly
restriction.Now I know the setting is
enablecfoutputonly
, and I fully expect Adobe to go "well duh, it does what it says", and then close any ticket I raise as "NotABug/AsDesigned", but I think that's horseshit. writeOutput()
is supposed to be the equivalent of <cfoutput>
, so it should work the same here. Oh, actually... it's even documented as supposedly working the way I expect it to:writeOutput()
:Appends text to the page-output stream. This function writes to the page-output stream regardless of conditions established by the cfsetting tag.So I guess this is a bug then. I shall raise it accordingly.
Another thing I notice is that
output="true"
on a function is also documented as follows:yes: the entire function body is processed as if it were in a cfoutput tag. Variables names surrounded by number signs (#) are automatically replaced with their values.
So even if my
writeOutput()
wasn't enough in my example above, the output="true"
should have worked equivalently. I added a third function to the test code thus:<cffunction name="usingOutputTrue" output="true">
TEXT WITHIN usingWriteOutput():<br>
<cfscript>writeOutput(generateContent());</cfscript>
</cffunction>
And I took the
output="true"
off the other functions. Their behaviour did not change as a result of that, and usingOutputTrue()
behaved like usingWriteOutput()
. So: wrong.I suppose the fly in the ointment here is the
<cfsavecontent>
. Because in this situation nothing's really being output. It's being captured. However I think the documented intent of writeOutput()
and output="true"
ought to have them behave the same was as <cfoutput>
tags.I changed my code slightly to not use
<cfsavecontent>
:<cffunction name="usingCfoutput">
TEXT WITHIN usingCfoutput():<br>
<cfoutput>#generateContent()#</cfoutput>
</cffunction>
<cffunction name="usingWriteOutput">
TEXT WITHIN usingWriteOutput():<br>
<cfscript>writeOutput(generateContent());</cfscript>
</cffunction>
<cffunction name="usingOutputTrue" output="true">
TEXT WITHIN usingWriteOutput():<br>
<cfscript>writeOutput(generateContent());</cfscript>
</cffunction>
<cffunction name="generateContent">
<cfset var s = "">
BEFORE CFOUTPUT<br>
<cfoutput>IN OUTPUT<br></cfoutput>
AFTER CFOUTPUT<br>
<cfreturn s>
</cffunction>
(The calling code was the same). And it behaves the same as before:
Calling usingCfoutput():
BEFORE CFOUTPUT
IN OUTPUT
AFTER CFOUTPUT
Calling usingWriteOutput():
IN OUTPUT
Calling usingOutputTrue():
IN OUTPUT
So it's not
<cfsavecontent>
. It's just "CFML not working properly" (I say "CFML", because Railo and OpenBD behave the same as ColdFusion here).I've raised a bug for this: 3694950.
--
Adam