By Peter Bell

Programmatic Config Files and Automagic Configuration

Something I was getting really tired of in my framework was that every time I added a new feature (controller) or custom data type, not only did I need to write the CFC, but I also had to add the bean definition to my config file. With the programmatic config file in LightWire, I was able to write a script to automagically instantiate and inject all of the custom data types and features by looking at all of the CFC's in the appropriate directories . . .

I start by getting a list of all of the CFC's in a given directory (so I can implement this as a generalized solution):

<cffunction name="getDistinctObjectList" returntype="string" hint="I return a distinct list of objects in a given directory for both an application and the framework." output="false">
   <cfargument name="FileDotPath" required="true" type="string" hint="The file path relative to the application/framework root with dots as directory delimiters.">
   <cfset var ObjectList = "">
   <cfset var ApplicationObjectList = "">
   <cfset var FrameworkDirectoryPath = variables.LightBaseDirectoryPath & variables.DirectoryDelimiter & "framework" & variables.DirectoryDelimiter & Replace(FileDotPath, ".", variables.DirectoryDelimiter, "all")>
   <cfset var ApplicationDirectoryPath = variables.ApplicationDirectoryPath & variables.DirectoryDelimiter & Replace(FileDotPath, ".", variables.DirectoryDelimiter, "all")>

   <cfdirectory action="list" directory="#FrameworkDirectoryPath#" name="ObjectList">
   <cfset ObjectList = ReplaceNoCase(valuelist(ObjectList.name), ".cfc","","all")>
   <cfdirectory action="list" directory="#FrameworkDirectoryPath#" name="ApplicationObjectList">
   <cfoutput query="ApplicationObjectList">
      <cfif NOT ListFindNoCase(ObjectList, Name)>
         <cfset ObjectList = ListAppend(ObjectList, Name)>
      </cfif>
   </cfoutput>
   <cfset ObjectList = ReplaceNoCase(ObjectList, ".cfc","","all")>
   <cfreturn ObjectList>
</cffunction>

Then to implement this for a data types, I do the following:

<cfscript>
var DataTypeList = "";
var DataTypeName = "";
Project = CreateObject("component","lightbase.applications.#Application.name#.config.ApplicationConfig").init();
// DATA TYPES
DataTypeList = getDistinctObjectList("com.datatype.types");
// Data type (facade) addSingleton("lightbase.framework.com.datatype.DataType");
addMixinProperty("DataType","DataTypeList",DataTypeList);

// All of the data type singletons
For (ConfigCount = 1; ConfigCount lte listlen(DataTypeList); ConfigCount = ConfigCount + 1)
{
   // Get current object name    DataTypeName = ListGetAt(DataTypeList, ConfigCount);
   If (FileExistsinApplication("com.datatype.types.#DataTypeName#"))
   {addSingleton("lightbase.applications.#Application.Name#.com.datatype.types.#DataTypeName#","#DataTypeName#DataType");}
   Else
   {addSingleton("lightbase.framework.com.datatype.types.#DataTypeName#","#DataTypeName#DataType");};
   // Inject app config and value list service to all data types    addConstructorDependency("#DataTypeName#DataType", "ApplicationConfig");
   addMixinDependency("#DataTypeName#DataType", "ValueListService");
   // And mix all data types into the data type service    addMixinDependency("DataType", "#DataTypeName#DataType");
};
</cfscript>

I've left in a bunch of additional bits of code to show a real world example rather than something completely stripeped down, but hopefully the sample is still simple enough to show that anyone can start writing their own little automagic scripts - just beware - as with c++, you can "blow your whole darned leg off".

Did I mention that I *like* programmatic config files for Dependency Injection :->

Thoughts?

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