Monthly Archives: November 2010

Using Freemarker in Coldfusion

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>

Download the full example here