Cfinclude w/runonce

Using latest Lucee 5.4.6.9 in Debian docker container.

Currently our app runs on Adobe ColdFusion 2021 and I’m trying to see how much effort it would be to convert to Lucee.
App is currently a mix of older legacy code and newer modern FW/1 code.

Having an issue with cfinclude. We do things like this:

<cfinclude template="/admin/modules/queryDumpLib.cfm" runonce="true">

Where the included file contains some code - maybe a combination of JS and CFML - in this case it will take a query and display it in a dataTable.

runonce works fine in ColdFusion but in Lucee it causes the app to error saying it can’t find code which exists in the include. If I simplify the included file to just have a string of text it still doesn’t display. Removing ‘runonce’ and it works fine.

The docs here mention so I assume it should work :slight_smile:

I would first look at your permissions for your Debian box.
does the file have the correct permissions?
Does your include work without run once set to true
Does your code run at all?
Is your code path correct?

Depending on your configuration of lucee, it could literally be looking for /admin/queryDump…/
off the main root of your OS, when you really want it from /var/www/…

To clarify - the include works:

  • in Adobe ColdFusion (with or without the runonce attribute)
  • in Lucee (only without the runonce attribute)

So it’s not a permission or path issue. It’s something to do with runonce.

I don’t remember whether I wrote the following function because I had the same problem or some other reason such as maybe it was before the runonce option existed, but here’s what I use:

function includeOnce(required string pathToInclude) {
	if (isNull(Request.sIncluded)) Request.sIncluded = {};
	if (isNull(Request.sIncluded[Arguments.pathToInclude])) {
		Request.sIncluded[Arguments.pathToInclude] = true;
		include Arguments.pathToInclude;
	}
}
1 Like

Can you please try using the tag-based <cfinclude template="test.cfm" runonce="true"/> instead of the using script format ‘include "test.cfm" true;’. Here is the related ticket: Jira.

2 Likes

To follow up on this - thanks for ticket link! The work around mentioned there

cfinclude(template="test.cfm", runonce="true");

Seems to work correctly

2 Likes

I started with Allaire ColdFusion way back in '97 so yeah I’m 99% certain (or 97%? lol) that I wrote my custom function before the runonce argument existed. At least I like that story much better than the one where I neglected to fully read all of the documentation of each upgrade. :grinning:

I still like my includeOnce() function for code readability, but I have updated it to be simply a wrapper for the native function.

While doing that I tested and confirmed what I found to be unexpected behavior of the native function. I thought it should include again when inside a component method due to its separate scope, but this test shows that runonce applies to the entire request.

This observation is mostly for theoretical purposes since including a file in a component is not a common use case, but it’s interesting to know!

include-once.cfm (in two parts to maintain syntax highlighting)

<cfscript>
Request.includeOnce = includeOnce;
Request.includeOnceCustom = includeOnceCustom;
objIncludeOnceTest = new includeOnceTest();

echo('TESTING NATIVE cfinclude with runonce=true<br>')
cfinclude(template="include-once-native.cfm", runonce=true);
cfinclude(template="include-once-native.cfm", runonce=true);
objIncludeOnceTest.testNative();

echo('<br>');
echo('TESTING WRAPPER includeOnce()<br>')
includeOnce("include-once-wrapper.cfm");
includeOnce("include-once-wrapper.cfm");
includeOnce("include-once-wrapper.cfm");
objIncludeOnceTest.testWrapper();

echo('<br>');
echo('TESTING CUSTOM includeOnceCustom()<br>')
includeOnceCustom("include-once-custom.cfm");
includeOnceCustom("include-once-custom.cfm");
objIncludeOnceTest.testCustom();

echo('<br>(The hellos from the methods are just to prove they are called.)');
function includeOnce(required string pathToInclude) {
	cfinclude(template=Arguments.pathToInclude, runonce=true);
}

function includeOnceCustom(required string pathToInclude) {
	if (isNull(Request.sIncluded)) Request.sIncluded = {};
	if (isNull(Request.sIncluded[Arguments.pathToInclude])) {
		Request.sIncluded[Arguments.pathToInclude] = true;
		include Arguments.pathToInclude;
	}
}
</cfscript>

includeOnceTest.cfc

component {
	private function hello(required string method) {
		echo('hello from includeOnceTest method: test#Arguments.method#<br>');
	}
	function testNative() {
		this.hello('Native');
		cfinclude(template="include-once-native.cfm", runonce=true);
	}
	function testWrapper() {
		this.hello('Wrapper');
		Request.includeOnce("include-once-wrapper.cfm");
	}
	function testCustom() {
		this.hello('Custom');
		Request.includeOnceCustom("include-once-custom.cfm");
	}
}

include-once-native.cfm

<cfscript>
echo('hello from include-once-native.cfm<br>');
</cfscript>

include-once-wrapper.cfm

<cfscript>
echo('hello from include-once-wrapper.cfm<br>');
</cfscript>

include-once-custom.cfm

<cfscript>
echo('hello from include-once-custom.cfm<br>');
</cfscript>

RESULT

TESTING NATIVE cfinclude with runonce=true
hello from include-once-native.cfm
hello from includeOnceTest method: testNative()

TESTING WRAPPER includeOnce()
hello from include-once-wrapper.cfm
hello from includeOnceTest method: testWrapper()

TESTING CUSTOM includeOnceCustom()
hello from include-once-custom.cfm
hello from includeOnceTest method: testCustom()

(The hellos from the methods are just to prove they are called.)