It was quite a pain trying to find a decent template system to use in Coldfusion. I finally landed on Freemarker, because I had used it’s syntax before. I had to jump through some hurdles to finally figure out how to effectively use it, so here I will share how I did it.
Download JavaLoader:
http://javaloader.riaforge.org/
Download Freemarker:
http://freemarker.sourceforge.net/freemarkerdownload.html
I use JavaLoader because I do not always have control over the Coldfusion environment that my applications will run on.
Here is the cfc
<cfcomponent name="FreeMarker" output="no">
<cfscript>
instance=StructNew();
instance.ID=CreateUUID();
instance.Out=createObject("java", "java.io.StringWriter").init();
instance.Map=StructNew();
instance.JavaLoader="";
</cfscript>
<cffunction name="init" hint="Constructor" access="public" returntype="FreeMarker" output="false">
<cfargument name="JavaLoader" type="any" required="yes">
<cfscript>
instance.JavaLoader=arguments.JavaLoader;
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="setContent" access="public" returntype="FreeMarker" output="false">
<cfargument name="Template" type="string" required="yes">
<cfscript>
instance.Content=createObject("java", "java.io.StringReader").init(arguments.Template);
instance.Template=instance.JavaLoader.create("freemarker.template.Template").init("FMT_" & instance.ID, instance.Content);
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="process" access="public" returntype="string" output="false">
<cfscript>
instance.Template.process(instance.Map, instance.Out);
instance.Out.flush();
</cfscript>
<cfreturn instance.Out.toString() />
</cffunction>
<cffunction name="putInt" access="public" returntype="FreeMarker" output="false">
<cfargument name="name" type="string" required="true" />
<cfargument name="in" type="numeric" required="true" />
<cfscript>
instance.Map[arguments.name]=JavaCast("int", arguments.in);
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="putString" access="public" returntype="FreeMarker" output="false">
<cfargument name="name" type="string" required="true" />
<cfargument name="in" type="string" required="true" />
<cfscript>
instance.Map[arguments.name]=JavaCast("string", arguments.in);
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="putArray" access="public" returntype="FreeMarker" output="false">
<cfargument name="name" type="string" required="true" />
<cfargument name="in" type="array" required="true" />
<cfscript>
instance.Map[arguments.name]=arguments.in;
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="putStruct" access="public" returntype="FreeMarker" output="false">
<cfargument name="name" type="string" required="true" />
<cfargument name="in" type="struct" required="true" />
<cfscript>
instance.Map[arguments.name]=arguments.in;
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="putQuery" access="public" returntype="FreeMarker" output="false">
<cfargument name="name" type="string" required="true" />
<cfargument name="in" type="query" required="true" />
<cfscript>
instance.Map[arguments.name]=QueryToArray(arguments.in);
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="getMap" access="public" returntype="struct" output="false">
<cfreturn instance.Map />
</cffunction>
<!--- ===================================== --->
<!--- Got from Ben Nadel: http://www.bennadel.com/blog/124-Ask-Ben-Converting-a-Query-to-an-Array.htm --->
<cffunction name="QueryToArray" access="private" returntype="array" output="false"
hint="This turns a query into an array of structures.">
<!--- Define arguments. --->
<cfargument name="Data" type="query" required="yes" />
<cfscript>
// Define the local scope.
var LOCAL = StructNew();
// Get the column names as an array.
LOCAL.Columns = ListToArray( ARGUMENTS.Data.ColumnList );
// Create an array that will hold the query equivalent.
LOCAL.QueryArray = ArrayNew( 1 );
// Loop over the query.
for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount ; LOCAL.RowIndex = (LOCAL.RowIndex + 1)){
// Create a row structure.
LOCAL.Row = StructNew();
// Loop over the columns in this row.
for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen( LOCAL.Columns ) ; LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){
// Get a reference to the query column.
LOCAL.ColumnName = LOCAL.Columns[ LOCAL.ColumnIndex ];
// Store the query cell value into the struct by key.
LOCAL.Row[ LOCAL.ColumnName ] = ARGUMENTS.Data[ LOCAL.ColumnName ][ LOCAL.RowIndex ];
}
// Add the structure to the query array.
ArrayAppend( LOCAL.QueryArray, LOCAL.Row );
}
// Return the array equivalent.
return( LOCAL.QueryArray );
</cfscript>
</cffunction>
</cfcomponent>