My Take on Transfer ORM Event Model - BeforeCreate Example
Posted At : May 21, 2008 8:25 AM | Posted By : Bob Silverberg
Related Categories: ColdFusion, Coldspring, Transfer
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:
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:
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:
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:
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.
Bob