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>