Introducing the ColdFusion 9 ORM Event Handler
Usually when you build applications, you want to have some kind of logging. A classic example of this is to log when an object has been deleted (removed from the database). Thankfully ColdFusion 9 has a feature called Event Handling which is really useful when you want to log events. So how do you use it?
First of all you need to be using Persisted Entities and then enable the eventhandling orm setting in your Application.cfc like this:
/**
* I am the Application.cfc
* @output false
*/
component
{
this.name = "eventhandlerdemo";
// define the application wide datasource
this.datasource = "cfartgallery";
// enable hibernate support for this application
this.ormenabled = "true";
// create a struct of ORM settings
this.ormsettings = {};
// turn on event handling
this.ormsettings.eventhandling = true;
}
Now ColdFusion will look at your Persisted Entities for one of these methods depending on which event is happening:
- preLoad(): This method is called before the load operation or before the data is loaded from the database.
- postLoad(): This method is called after the load operation is complete.
- preInsert(): This method is called just before the object is inserted.
- postInsert(): This method is called after the insert operation is complete.
- preUpdate(Struct oldData): This method is called just before the object is updated. A struct of old data is passed to this method to know the original state of the entity being updated.
- postUpdate(): This method is called after the update operation is complete.
- preDelete(): This method is called before the object is deleted.
- postDelete(): This method is called after the delete operation is complete.
The names are self explainitory so I won't describe each one. If you want to know more read the livedocs
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WS33331E6A-B64C-4089-8A41-AEB3A4133D59.html
Going back to my example of logging a deletion, we would need to have a CFC that includes the postDelete() method, something like this:
/**
* I am a Art Persisted Entity
* @output false
* @table ART
* @persistent true
*/
component
{
// identifier
property name="ArtID" fieldtype="id" generator="native" ;
// properties
property name="ArtName" ;
property name="Description" ;
property name="Price" ;
property name="LargeImage" ;
property name="IsSold" ;
property name="Artist" fieldtype="many-to-one" fkcolumn="ArtistID" cfc="Artist";
/**
* I am called after the delete operation is complete.
* @output false
*/
public void function postDelete()
{
// writeLog is the cfscript equililent of cflog
writeLog( type="Information", file="ormevent.log", text="Art entity #this.getArtID()# deleted" );
}
}
That was easy, but it would get a bit tedious having to add this method to each Entity. Luckily ColdFusion also has an application-wide event handler. To set this up is easy, just add in a new ormsetting in the Application.cfc so that we now have:
/**
* I am the Application.cfc
* @output false
*/
component
{
this.name = "eventhandlerdemo";
// define the application wide datasource
this.datasource = "cfartgallery";
// enable hibernate support for this application
this.ormenabled = "true";
// create a struct of ORM settings
this.ormsettings = {};
// turn on event handling
this.ormsettings.eventhandling = true;
this.ormsettings.eventhandler = "my.cfc.path.EventHandler";
}
Now we need to create the EventHandler.cfc. It is important to note that the EventHandler needs to impliment the cfide.orm.IEventHandler interface. Here is a simple one that logs all ORM events:
/**
* Application wide event handler for ORM operations
* @output false
* @implements cfide.orm.IEventHandler
*/
component
{
/**
* This method is called before the data is loaded from the DB.
*/
public void function preLoad( any entity )
{
logEvent( "preload", entity );
}
/**
* This method is called after the load operation is complete.
*/
public void function postLoad( any entity )
{
logEvent( "postload", entity );
}
/**
* This method is called just before the object is inserted.
*/
public void function preInsert( any entity )
{
logEvent( "preinsert", arguments.entity );
}
/**
* This method is called after the insert operation is complete.
*/
public void function postInsert( any entity )
{
logEvent( "postinsert", arguments.entity );
}
/**
* This method is called just before the object is updated. A struct of old data is passed to this method to know the original state of the entity being updated
*/
public void function preUpdate( any entity, Struct oldData )
{
logEvent( "preupdate", arguments.entity );
}
/**
* This method will be called after the update operation is complete.
*/
public void function postUpdate( any entity )
{
logEvent( "postupdate", arguments.entity );
}
/**
* This method is called before the object is deleted.
*/
public void function preDelete( any entity )
{
logEvent( "predelete", arguments.entity );
}
/**
* This method is called after the delete operation is complete.
*/
public void function postDelete( any entity )
{
logEvent( "postdelete", arguments.entity );
}
/**
* Writes operation details to the log.
* @output false
*/
private void function logEvent( required string event, required cfc )
{
// arguments.event : Name of the event being called.
// arguments.cfc : The cfc being acted upon.
var message = "Entity: #getMetaData( arguments.cfc ).fullname#, Event: #arguments.event#";
Trace( text=message );
WriteLog( type="event", file="ormevent.log", text=message );
}
}
There you have it, an application wide logging for orm events. This example is pretty basic, but hopefully it's given you some idea of the power of this feature.
- Posted in:
- ColdFusion
- OOP


Comment by Kevan Stannard – July 14, 2009
Comment by John Whish – July 14, 2009
Comment by Nick – July 14, 2009
Comment by John Whish – July 14, 2009
Comment by John Whish – July 14, 2009
I am using pretty much the same logging type system as this exept i write the log to a table called 'Audit', I create the audit object in the postInsert() event trigger, set the properties and call entitySave('Audit'). The event gets triggered and i can dump the audit object and all looks perfect but it does not get saved to the database and i have no idea why. I am really scratching my head with this one and cannot find any information. Would you have any ideas?
Comment by Gavin Stewart – July 24, 2009
I'm not at my dev workstation so I can't test it out but I can see that you could end up with a problem if your logging class is a persisted entity, as when you try to do anything with it you'll be firing the event handler each time. The other thing that happens with the way that hibernate is handled in CF9 is that commits only happen when the request ends, or you force it to commit by using ORMFlush() (or wrap it in a transaction) so it might be something to do with that.
You might actually be better off with a straightforward cfquery if all you want to do is save the info in the database as using an object has no real benefit.
Hope that helps, let me know.
Comment by John Whish – July 24, 2009
This morning has really been my first proper assessment of the ORM implementation within CF and I really can't praise it enough, it really does seem so very intuitive! Adobe have done an excellent job of all this.
Rob
Comment by Robert Rawlins – August 22, 2009
Comment by John Whish – August 24, 2009