Photo from Chile

My Take on Transfer ORM Event Model - BeforeCreate Example

Paul Marcotte wrote a blog entry describing how to automatically set a CreatedDate and ModifiedDate in your Transfer Objects when they are saved to the database. It is very well written and provides a great description of the problem, how Transfer observers work, and a solution.

I have used Transfer observers in a different manner, so I added a comment with a brief description to the blog entry. Dan Wilson suggested that it was too bad that such useful information was buried in a blog comment, so I decided to post it here as well. For the background, please check out Paul's entry.

The difference in my approach is that I create an observer which then watches for changes to all Transfer Objects, rather than adding the observer to a particular Transfer Object via its decorator. The code inside the BeforeCreateObserver looks like this:

view plain print about
1<cffunction name="actionBeforeCreateTransferEvent" access="public" returntype="void" output="false" hint="I do stuff before an object is persisted for the first time.">
2    <cfargument name="event" hint="The event object" type="transfer.com.events.TransferEvent" required="Yes" />
3
4    <!--- Get a reference to the Object about to be persisted --->
5    <cfset var theTO = arguments.event.getTransferObject() />
6
7    <!--- Set the CreatedDate, if possible --->
8    <cfif StructKeyExists(theTO,"setCreatedDate")>
9        <cfset theTO.setCreatedDate(now()) />
10    </cfif>
11
12</cffunction>

Note that because this method will be called for all Transfer Objects just before they are created, you can also add code that only deals with specific classes as well. An updated example would be:

view plain print about
1<cffunction name="actionBeforeCreateTransferEvent" access="public" returntype="void" output="false" hint="I do stuff before an object is persisted for the first time.">
2    <cfargument name="event" hint="The event object" type="transfer.com.events.TransferEvent" required="Yes" />
3
4    <!--- Get a reference to the Object about to be persisted --->
5    <cfset var theTO = arguments.event.getTransferObject() />
6
7    <!--- Set the CreatedDate, if possible --->
8    <cfif StructKeyExists(theTO,"setCreatedDate")>
9        <cfset theTO.setCreatedDate(now()) />
10    </cfif>
11
12    <!--- If it is a User TO, set the RegisteredDate --->
13    <cfif theTO.getClassName() eq "user.user">
14        <cfset theTO.setRegisteredDate(now()) />
15    </cfif
16</cffunction>

If you have a number of different classes for which you need to do different things, you could replace the second cfif with a cfswitch.

Now, the question is, how do we tell Transfer to use this BeforeCreateObserver? I like to have Coldspring do it for me. Many thanks to Brian Kotek and his TDOBeanInjectorObserver for pointing me in the right direction regarding getting Coldspring to play nice.

First we need a few entires in our Coldspring.xml file. Note that your path names may be different:

view plain print about
1<bean id="transferFactory" class="transfer.TransferFactory">
2    <constructor-arg name="datasourcePath"><value>model/config/datasource.xml.cfm</value></constructor-arg>
3    <constructor-arg name="configPath"><value>model/config/transfer.xml.cfm</value></constructor-arg>
4    <constructor-arg name="definitionPath"><value>/TransferTemp</value></constructor-arg>
5</bean>
6
7<bean id="Transfer" factory-bean="transferFactory" factory-method="getTransfer" />
8
9<bean id="TransferBeforeCreateObserver" class="model.util.TransferBeforeCreateObserver"></bean>
10
11<bean id="ObserverInjector" class="model.util.ObserverInjector" lazy-init="false">
12    <constructor-arg name="Transfer"><ref bean="Transfer" /></constructor-arg>
13    <constructor-arg name="BeforeCreateObserver"><ref bean="TransferBeforeCreateObserver" /></constructor-arg>
14</bean>

These beans define our TransferFactory, a Transfer object (which is created via the Factory), our BeforeCreateObserver, and finally an injector for our observer. This last piece is what allows Coldspring to automatically add the Observer to the Transfer object when the application is initialized.

We've already seen the code for the TransferBeforeCreateObserver, so here's the code for the init of the ObserverInjector, which is all we really need it to do:

view plain print about
1<cffunction name="init" access="public" returntype="any" hint="I am used to add the observer to Transfer.">
2    <cfargument name="Transfer" type="transfer.com.Transfer" required="true" />
3    <cfargument name="BeforeCreateObserver" type="any" required="true" />
4    <cfset arguments.Transfer.addBeforeCreateObserver(arguments.BeforeCreateObserver) />
5    <cfreturn this />
6</cffunction>

If you wanted to add multiple observers you could add more arguments and corresponding adders (e.g., BeforeUpdateObserver). Also, if you wanted to add multiple observers to the same event, you could pass in a Coldspring map, and loop through it.

TweetBacks
Comments
Great post. The init function is missing that you indicate by writing "We've already seen the code for the TransferBeforeCreateObserver, so here's the code for the init of the ObserverInjector, which is all we really need it to do:" I see it in the html source, but not on the page itself.
# Posted By Nando | 5/21/08 9:53 AM
Thanks Nando! I've fixed that glitch.

Bob
# Posted By Bob Silverberg | 5/21/08 9:57 AM