Monday, May 26, 2008

Using a Transfer decorator to get related records within the same table

 

One of the benefits of using the Transfer ORM in your application is that if you define the relationships between your tables in the Transfer XML configuration file, you can retrieve any objects related to your current object through a variety of functions.

However, sometimes you need to relate records within the same table. For example, in my current project, I have a table of item records which need to be arranged in a hierarchy of unknown depth: one set of items could have two levels of hierarchy, another three levels. Each item, therefore, can have one parent item above it (identified by a parentId field in the record) in the hierarchy and any number of children below it (and all the child records have the current item's ID as their parentId value).

How can you use Transfer to access these in-table relationships? One way is by using a decorator object. As the Transfer documentation explains, a decorator is a CFC file you write yourself that extends the TransferDecorator CFC that comes with Transfer. You associate your decorator with the Transfer object that represents the table in your Transfer configuration file so that when a Transfer object for a record in that table is generated, the functions you define in your decorator become part of that object. So say I define a Transfer object called "Item" in the package "example". Here is the XML in the Transfer configuration file:

The decorator to be called is the itemDecorator.cfc in the "com" directory. I want to have two new functions in the decorator, one that returns a Transfer object for the parent record, and one that returns an array of Transfer objects representing each child record. Here's the code:

In a decorator CFC that extends the TransferDecorator CFC, you can access the current item's Transfer object all of its functions via the getTransferObject() function, and you can access the main Transfer object via the getTransfer() function. So the single statement in the getMyParentItem() function in the decorator CFC is equivalent to:

 
<cfset parentItemObject= transfer.get("example.Item",currentItemObject.getParentId())>

The getMyChildItems() function is slightly more complicated because it needs to retrieve a recordset of child objects first, using the listByProperty() function of the main Transfer object (again, provided via the getTransfer() function within the decorator), then loop through those records, creating a Transfer object for each child record and appending it the array returned by the function.

What if the item record in question is either at the top of the item hierarchy or at the bottom? If there is no parent item, the Transfer object returned by the getMyParentItem() function will have an itemId of 0 (the default value for an empty numeric primary key) and empty values for all of the other properties, so you can test for that condition. If there are no child items, the array returned by the getMyChildItems() function will simply be empty.

This is only the second Transfer decorator I've ever written, so there may be a better way of going about it, but it gets the job done with just two short functions added on to existing object functions provided by Transfer. I like it when things are this easy.

No comments:

Post a Comment