Creating A CFC Generator Object With Illudium

In my last post I showed the raw code that you would need to call the Illudium PU-36 Code Generator outside of it's Flex front-end. That code is just ripe for abstraction. Really all you want is an object with a method signature that takes maybe a com-path, datasource, and table name and does the work of generating the CFCs for you right? OK, now that we're all agreed. The CFC is attached in a zip (just click the "download" link down yonder).

And here is some sample code showing how easy it is to use now that it's packaged up.

<cfset generator = CreateObject('component','_testing.CFC.generator') />
<cfset generator.init('YOURCFADMINPASSWORD','_testing.CFC.generated') />
<cfset generator.GenerateTableCFCs(DataSource='YOURDATASOURCE', Table='SOMETABLE') />

There is one thing that you might want to change depending on your usage. The generator is set up to generate two sets of CFCs based off of two Illudium template sets. A base/volatile set and a custom/non-volatile set. It will always overwrite the base/volatile set. But, it will only write the custom/non-volatile set if it does not exist.

Disclaimer: You will most likely need to edit the CFC a little for pathing issues. And this will not work unless you have patched Illudium per my previous article.(Or until Brian rolls the patch in, which i think he's gonna).

Illudium - Outside Its Flex Front-End

So now you know why I needed a database abstraction system. You also know that I chose the Illudium PU-36 Code Generator because of it's templating system. Having the templating system gave me full control to generate exactly the kind of CFCs that I wanted. I'll go over some of the ways that I modified the stock templates in another post in this series.

The biggest issue I had with Illudium was that it very quickly became tedious to have to go into the Flex interface, re-enter all the information in the form and re-generate the CFCs every time I made a tweak to the templates. And let's be honest. It's going to be an iterative process to get the templates right.

So, I decided to see if I could call the CFCs that back the GUI outside of it. Then, I would be able to run a script and quickly re-generate the CFCs whenever I wanted to. If I remember right, I found what CFC and method were being called by watching the new monitoring tools in CF8. Then I started digging into the code that the Illudium remote facade calls. I mocked up the code that should work to get back a package of generated code for one table. But, it didn't work right away. I had to change a little bit of the code in one method of codeService.cfc to get it working. Oddly, the file pathing seems to change when something is being called by remoting vs. CreateObject().

Below is the updated code for that method. I've also attached a zip that has a patch file if you'd like to just patch the cfc in Eclipse.

<cffunction name="processCFMTemplate" access="private" output="false" returntype="string">
   <cfargument name="template" type="string" required="true" />
   <cfargument name="xmlTable" required="true" type="xml" />
   
   <cfset var content = "" />
   <cfset var root = arguments.xmlTable.root />
   <cfset var tempFileName = "#createUUID()#.cfm" />
   <cfset var tempDirPath = getDirectoryFromPath(getCurrentTemplatePath()) & "temp" />
   
   <cfif not directoryExists(tempDirPath)>
      <cfdirectory action="create" directory="#tempDirPath#">
   </cfif>
   
   <!--- write the cfm to a hard file so it can be dynamically evaluated --->
   <cffile action="write" file="#tempDirPath#/#tempFileName#" output="#arguments.template#" />
   <cfsavecontent variable="content">
      <cfinclude template="temp/#tempFileName#" />
   </cfsavecontent>
   <cfset content = replaceList(content,"<%,%>,%","<,>,##") />
   <cffile action="delete" file="#tempDirPath#/#tempFileName#" />
   
   <cfreturn content />
</cffunction>

Also, here is what the code for calling Illudium outside of the GUI looks like.

<!--- Path to Illudium xsl folder --->
<cfset xslBasePath = "/cfcgenerator/xsl/" />
<!--- Start of path to generated CFCs --->
<cfset ObjectStore = "com.generated.test" />

<cfset DataSource = "YOURDSNAME" />
<cfset Table = "ATABLENAME" />

<!--- Load Illudium PU-36 Code Generator Service --->
<cfset gs = createObject("component","cfcgenerator.com.cf.model.generatorService").init(xslBasePath) />
<cfset gs.setAdminPassword("YOURCFADMINPASSWORD") />

<cfscript>
   /* Illudium wants a path that doesn't include the trailing '/' */
   rootPath = mid(ExpandPath('/'),1,len(ExpandPath('/'))-1);
   
   /* Illudium Args */
   args = {
      dsn = DataSource,
      componentPath = ObjectStore & '.' & DataSource & '.' & Table,
      table = Table,
      projectPath = 'dealerpeak_base',
      stripLineBreaks = 'yes',
      rootPath = rootPath
   };
   basecode = gs.getGeneratedCFCs(argumentCollection=args);
</cfscript>

<!--- Separate folder for each Datasource --->
<cfset DataSourceDir = rootPath & '/' & replace(ObjectStore,'.','/','all') & '/' & DataSource />

<!--- Make sure datasource directory is there --->
<cfif NOT directoryExists(DataSourceDir)>
   <cfdirectory action="create" directory="#DataSourceDir#">
</cfif>
<!--- Create CFC files --->
<cfloop from="1" to="#arrayLen(basecode)#" index="i">
   <cffile action="write" file="#basecode[i].getFilePath()#" output="#basecode[i].getContent()#" />
</cfloop>

So, have fun playing with the Illudium PU-36 Code Generator! I'll be back soon to discuss bundling this up into a CFC generator object.

Impetus For A Database Abstraction System

I wrote a bit ago about using Brian Rinaldi's Illudium PU-36 Code Generator for a project at work. There was actually a pretty good response to the post. And people seemed interested in how I was using Illudium (outside of it's Flex front-end). So, this will be the first post in a series about building a database abstraction system.

So, what was the impetus for all of this? I work on a massive Fusebox 3 application. A large portion of it was written before CFMX. So, most of our database access is in qry_xxx.cfm files. This is OK. At least it's fairly organized. The first time this was really not OK was when we started experimenting with Flex and remoting. For remoting, you really need to use CFCs. But, we really didn't want to just cut and paste the same query into a CFC and have to maintain it in two places. And we really didn't have the time or man-power to rewrite all our data access. So, we basically gave up the idea.

Then our application got bigger and bigger. We hired more people. And there was more not-OK-ness. Like, I'm sick of writing the same boiler plate SQL for every new table I make. And it's actually sort of a pain for multiple developers to go see if somewhere in our massive application the query that they want is already written. So, for some time now, I have been really wanting to find a solution to standardize our database access.

I tried at one point using Doug Hughes' Reactor framework. But, there were some issues with getting it to pick up schema changes on a live server under load. Also, my boss wasn't really a fan of it's black-box-ness. Transfer is cool too. But, it has that same black-box-ness.

So, for requirements at work, what I really needed was:

  • Something to generate CFCs that would handle our database access.
  • For the CFCs to be easily found and read once generated.
  • For there to be a way for us to customize the functionality of the objects.

At some point I found the Illudium PU-36 Code Generator. It fit the bill because it uses a templating system. So, you can customize the code that it generates. In my next post I'll go over using Illudium outside of it's Flex front-end.

BlogCFC was created by Raymond Camden. This blog is running version 5.6.002.