How in one line to extend ColdFusion by writing CFC's

ColdFusion 9

There have always been ways to extend ColdFusion through custom tags (and its variations like cfmodule) or by adding a library cfc or by including a file before every page.

I now present another way;

  • a way to write a cfc
  • place it in a folder
  • and call it via the new operator. 

And its all done by one setting:

this.customtagpaths = pathToExtensionFolder!

Lets see it in action.  First, set up an Application.cfc like so:

component
{
     this.customtagpaths = getDirectoryFromPath( GetCurrentTemplatePath() ) & "languageExtension/";
}

Then in the langaugeExtension folder add as many cfc's as you want for my example I included one called Invoke.cfc (yes, I've wanted a script based version of this for a while! ;) ):

component {
function first() {
     return "Sam";
}
}

In the root folder I created a test.cfm with the following code:

<cfscript>
a = new languageExtension.Invoke();
writeDump(a);
 
i = new Invoke();
writeDump(i);
o=i.first();
writeOutput(o);
</cfscript>

Being in the root folder the first line should always work.  Nothing exciting there.  But whats cool is line 4 where variable i is set with no path to Invoke().  And it works.  Here is a screenshot:

Next I created a sub folder structure to see if this would still work further down the chain.

Folder Set Up

And here is the code for dirB/test.cfm:

<cfscript>
i = new Invoke();
writeDump(i);
o=i.first();
writeOutput(o);
</cfscript>

Which works as well!  Here is its screenshot:

Dump of dirB/test.cfm

You can also place extra CFCs in the servers root CustomTags folder and use new on them.  I think this is a bad idea.  Its better to write applications that can be dropped anywhere and are not dependent on special server set ups.

So a pretty easy way to more natively expand upon the ColdFusion language and while I mention this.customtagpaths above it is also possible thanks to the new operator introduced in 9.

Using ORM Event Handler to easily and automatically add audit information

ColdFusion 9, ORM

Using the event handling features in ORM in ColdFusion 9 makes it easy to automatically add audit information such as last updated and last modified by to all objects, well technically tables, in the database.  I'm about to launch my first ColdFusion 9 application and the technique below has worked well and sped up development.

Step 1: Decide on audit colum names

There really is no right or wrong way here.  Go for something readable and easily understandable (for those lucky future developers who will look at your code!).  Once you pick them add them as properties to your CFC:

component persistent="true" {
property name="teamID" fieldtype="id" generator="native" generated="always";
property name="teamName" ormtype="string";
property name="dateCreated" ormtype="timestamp";
property name="dateModified" ormtype="timestamp";
property name="createdBy" ormtype="integer";
property name="lastModifiedBy" ormtype="integer";
}

Step 2: Turn on Event Handling and Hander

In your Application.cfc in addition to ormEnabled=true, turn on event handling and an event handler like so:

this.ormsettings = { eventHandling=true, eventHandler="myEventHandler" };

The eventHandler points to a valid CFC "myEventHandler.cfc" which is what we will create next.

Step 3: Create an Event Handler CFC (See I told ya!)

The event handler must implement CFIDE.orm.IEventHandler. CFBuilder makes this easy, add a new ColdFusion Component file and on the New ColdFusion Component screen under ‘Implements’ click on ‘Add’, and select CFIDE.orm.IEventHandler. If you script style components, as I do, click the ‘Generate Script Style Code’ option.
 
Your new file will look like this:
component implements="CFIDE.orm.IEventHandler"
{
         public void function preDelete( any entity)
         {
 
         }
         public void function preInsert( any entity)
         {
 
         }
         public void function preLoad( any entity)
         {
 
         }
         public void function postDelete( any entity)
         {
 
         }
         public void function postLoad( any entity)
         {
 
         }
         public void function preUpdate( any entity, Struct oldData)
         {
 
         }
         public void function postUpdate( any entity)
         {
 
         }
         public void function postInsert( any entity)
         {
 
         }
}

Step 4: Add code to preInsert and preUpdate functions

The preInsert and preUpdate functions in the event handler CFC are the last functions that get run before ColdFusion hands over to Hibernate for persistence (a fancy way of saying saving to database).  All of the functions in eventHandler take in the entity as an argument called entity (if you are new to cfscript within the parenthesis its saying a type of any and an argument called entity).  We simply call the various functions and pass in the values.  I found I got an error at first matching the session userID to createBy and lastModifiedBy and needed to use JavaCast.  [Update Feb 6 '10: This bug is scheduled to be fixed in 9.0.1] After making a change to myEventHandler.cfc run ormReload() (I've gotten used to having this in onRequestStart and commenting it out when not needed).

public void function preInsert( any entity)
{
     entity.setCreatedBy( JavaCast( "int", session.userID ) );
     entity.setLastModifiedBy( JavaCast( "int", session.userID ) );
     entity.setDateCreated( now() );
     entity.setDateModified( now() );
}

The preUpdate function is very similar except just has the setLastModifiedBy and setDateModified calls.  If all your entities don't have the audit properties/columns use this technique for checking if the function exists.

Lets see it in action.

Using the Team object from above:

<cfset t = entityNew( "Team" )>
<cfset t.setTeamName( "Arsenal" )>
<cfset entitySave( t )>

Thats all the code needed.  Here's a screenshot of the database after insert that shows all the audit data.

Database with Audit Information

2010: Speaking at CFUnited and an Adobe Community Professional!

CFUnited, ColdFusion 9, Adobe Community Professional

In the past few days I've received some pretty exciting news.  First I got word that I have been selected to speak at CFUnited on ColdFusion One Liners.  I gave this topic at CFinNC and am looking forward to building on the feedback I received and some new ideas for CFUnited this year.  I've never given a presentation again so I'm looking forward to a chance to make it better.

Second I got chosen as an Adobe Community Professional.  This is a real honor to be amongst a group of community members that I admire a great deal.  I'm looking forward to learning from them and passing on as much as possible.  The first thing I want to do is create a series of screencasts about my experiences with ColdFusion 9.

Adding ExtJS Effects to cfwindow

ColdFusion 9, ExtJs

Underneath the hood cfwindow uses ExtJS to make modal windows.  This means with a little bit of JavaScript its possible to add effects to a cfwindow.  First lets create a cfwindow:

<cfwindow name="myWindow" title="My Window" initshow="true">
<div id="windowContent">
     Some text about how cool something is.<br><br>
     Some text about how cool something is.<br><br>
     Some text about how cool something is.<br><br>
</div>
</cfwindow>

 

Nothing special here.  To tie it in with some ExtJS effects we need to get at its inners using the ColdFusion.Window.getWindowObject() function.  In the example below once we get the window object we add a listener to it using the shorthand ExtJs notation of "on" to look for when the mouse enters and leaves the window.  When the mouse enters we log to the console the id of the element (it can be useful to know the id of it) and then perform a highlight effect on the windowContent div.  When the mouse leaves we hide the window.

<script type="text/javascript">
Ext.onReady(function(){
var myWin = ColdFusion.Window.getWindowObject( 'myWindow' );
myWin.getEl().on( {
     'mouseenter': function(){     
          console.log(this.id);
          Ext.get('windowContent').highlight(    
          "ffff9c", { endColor: "ffffff"     });
     },
     'mouseleave': function(){ ColdFusion.Window.hide( 'myWindow' );}
});
});
</script>

 

Thats it!  ExtJs has a bunch of cool effects that can be applied to an element.

Here's a short screencast showing the code above in action:

Dynamically injecting data into an Object

ColdFusion, ColdFusion 8, ColdFusion 9
I like to write as little code as possible (that’s the whole point of coding, right?) and recently, since I started working with ORM, have found the need to inject data into an object. Often with an ORM object -- though this isn’t limited just to ORM -- you create a new object then have lines of setXXX functions like so:
 
s = entityNew( 'Sample' );
s.setAge( form.age );
s.setFirstname( form.firstname );
 
Well I got pretty bored of writing all those setXXX lines. So I wrote a function to do it. (This is not the only way or necessarily the best way but I thought I would put it out there).
 
<cffunction name="injectInto">
<cfargument name="obj" required="true" hint="I am an object for injecting">
<cfargument name="st" required="true" hint="I am a structure of data.">
<cfloop collection="#arguments.st#" item="local.key">
            <cfif structKeyExists( obj, "set#local.key#" )>
                        <cfinvoke component="#arguments.obj#" method="set#local.key#" >
                        <cfinvokeargument name="#local.key#" value="#arguments.st[ local.key ]#">
                        </cfinvoke>
            </cfif>
</cfloop>
</cffunction>
 
First off this is all in tags as there is no invoke function in cfscript. Originally the if structKeyExists line was a try and catch. That worked but felt a little like overkill so I experimented around and found that structKeyExists works as I blogged about. I also tried using getComponentData which returns all functions but again this felt heavy to me.
 
So, what does the function do? It takes in an object that you want injected and a structure of data to inject into it, loops over that data, checks to see if the object publicly wants it and if so uses cfinvoke to give it to the object. The above code now becomes:
 
s = entityNew( 'Sample' );
s injectInto( s, form );
 
But what if you have data in multiple structures; form, url, request for instance? 
 
<cffunction name="injectInto">
<cfargument name="obj" required="true" hint="I am an object for injecting">
<cfloop from="1" to="#structCount( arguments )#" index="local.collection" >
            <cfif isStruct( arguments[ local.collection ] )>
                        <cfloop collection="#arguments[ local.collection ]#" item="local.key">
                                    <cfif structKeyExists( obj, "set#local.key#" )>
                                                <cfinvoke component="#arguments.obj#" method="set#local.key#" >
                                                <cfinvokeargument name="#local.key#" value="#arguments[ local.collection ][ local.key ]#">
                                                </cfinvoke>
                                    </cfif>
                        </cfloop>
            </cfif>
</cfloop>
</cffunction>
 
The above function will take in any number of structures and inject their data into the object. You may notice that the function only has one argument even though I just said it can have an endless number of arguments. That’s because I am going to programatically deal with them.
 
Regardless of how many arguments a ColdFusion function has defined it will always take in everything you give it. (Its generous like that! ;) ) If the arguments are not named then they take a number in the arguments structure. Let’s call the above function and then dump its arguments passed into injectInto.
 
//setting up some “fake” structures for form, url and request
f = { age="23" };
u = { firstname="Sam", age="21" };
r= { userID=2134132 };
sObj = new Sample();
injectInto( sObj, f, u, r );
 
 
As you can see the only named argument is the first one passed in – obj, the others get numbers for names. This is useful as it preserves the order they are passed and means we can loop over them and inject their data into the object which going back to the injectInto function is exactly what happens.

Using StructKeyExists to find if an object has a function

ColdFusion, ColdFusion 8, ColdFusion 9
Recently I have needed to dynamically know if an object has a public function. I found this can be achieved using structKeyExists. First, lets set up a cfc:
 
component accessors="true"
{
property name="firstname";
property name="age";
 
private function getaddress() {
            return variables.address;
}
private function setaddress( address ) {
            variables.address = arguments.address;
}
}
 
Or if you prefer a tag based cfc:
 
<cfcomponent accessors="true">
 
<cfproperty name="firstname">
<cfproperty name="age">
 
<cffunction name="getaddress" access="private">
            <cfreturn variables.address>
</cffunction>
<cffunction name="setaddress" access="private">
            <cfset variables.address = arguments.address>
</cffunction>
 
</cfcomponent>
 
An object of this cfc will have 6 functions, 4 public ( getFirstname(), setFirstname(), getAge(), setAge() ) and 2 private ( getAddress(), setAddress() ).
 
Now based on getting errors when leaving off the parenthesis from a function call, I thought I would try and see if I could use structKeyExists to test if a function exists.
 
<cfset s = new Sample()>
 
<cfif structKeyExists( s, "setFirstname" )>
            The function setFirstname EXISTS!!<br>
<cfelse>
            The function setFirstname can not be accessed or does not exist<br>
</cfif>
 
<cfif structKeyExists( s, "setAddress" )>
            The function setAddress EXISTS!!<br>
<cfelse>
            The function setAddress can not be accessed or does not exist<br>
</cfif>
 
This will output:
 
The function setFirstname EXISTS!!
The function setAddress can not be accessed or does not exist
 
I was a little surprised it worked and can’t decide if its hackey or cool (or if hackey is even a word!). Next up I’ll show why I wanted to do this and use it dynamically.

Search

Twitter
You should follow me on Twitter here
About Me
I am a 34-year old Web Developer specializing in ColdFusion. I live and work in downtown Washington, DC with my wife and two daughters. Read more About Me

2007 CFeMmy Best Newcommer winner
As voted on by fellow CF Bloggers.