Reactor and Aliased Linked Relationships

Earlier today Doug Sims posted about the difference between "relate" and "link" in Reactor's XML configuration. After reading Doug's post I thought I'd share an issue I ran into earlier this week using linked relationships.

(Disclaimer: I've just started to use Reactor this week. I needed to prototype a security system and decided to finally give Model-Glue Unity with Reactor a try. I wanted to use Model-Glue's scaffolding to quickly build the system's administrator interface. I ran into a few issues along the way, one of which this post details.)

Anyway, my Reactor configuration file looked like this:

<reactor>
<objects>

<object name="user">
<hasMany name="role">
<link name="userRole" />
</hasMany>
</object>

<object name="role">
<hasMany name="user">
<link name="userRole" />
</hasMany>
<hasMany name="role" alias="childRoles">
<link name="roleContent" from="parentRole" to="childRole" />
</hasMany>
<hasMany name="role" alias="parentRoles">
<link name="roleContent" from="childRole" to="parentRole" />
</hasMany>
<hasMany name="permission" alias="childPermissions">
<link name="roleContent" from="parentRole" to="childPermission" />
</hasMany>
</object>

<object name="permission">
<hasMany name="role">
<link name="roleContent" from="childPermission" to="parentRole" />
</hasMany>
</object>

<object name="userRole">
<hasOne name="user">
<relate from="userID" to="userID" />
</hasOne>
<hasOne name="role">
<relate from="roleID" to="roleID" />
</hasOne>
</object>

<object name="roleContent">
<hasOne name="role" alias="parentRole">
<relate from="roleID" to="roleID" />
</hasOne>
<hasOne name="role" alias="childRole">
<relate from="objectID" to="roleID" />
</hasOne>
<hasOne name="permission" alias="childPermission">
<relate from="objectID" to="permissionID" />
</hasOne>
</object>

</objects>
</reactor>

This may look a little complicated, but basically it just says that a user can have multiple roles, and roles can be composed of roles or permissions. In other words roles can be nested in other roles. (I was able to use this schema because I was using MS SQL with uniqueidentifiers as the table primary keys. More on that in a later post...)

To manage these objects I did basic MG scaffolding like so:

<modelglue>

...

<event-handlers>

...

<scaffold object="user" />
<scaffold object="role" />
<scaffold object="permission" />

</event-handlers>
</modelglue>

I was able to view the scaffolded edit screens, however whenever I tried to save a permission to a role I got an error stating that the setpermission method could not be found for my roleContentRecord. I opened up the Reactor generated project roleContentRecord.cfc, and sure enough it had methods named setparentRole, setparentRole, and setchildPermision but none named setpermission. Reactor was generating the record's methods based on the relationship alias, however the iterator used during saving was using the relationship name. A little digging and was able to track down the issue in Reactor's core iterator.cfc (/reactor/iterator/iterator.cfc). Starting at line 452 I changed the following code from:

<!--- if this is a linked iterator then add a new object of the type that links this object to the parent to the linkIterator --->
<cfif getLinked()>
<!--- create a new object to link the new record to the linked object --->
<cfinvoke component="#getLinkIterator().add()#" method="set#getAlias()#">
<cfinvokeargument name="#getAlias()#" value="#Record#" />
</cfinvoke>

<cfelse>
<!--- set the parent of this record --->
<cfset Record._setParent(this) />

</cfif>

to:

<!--- if this is a linked iterator then add a new object of the type that links this object to the parent to the linkIterator --->
<cfif getLinked()>

<cfset linkRelationship = getLinkRelationshipMetadata() />

<!--- create a new object to link the new record to the linked object --->
<cfinvoke component="#getLinkIterator().add()#" method="set#linkRelationship.alias#">
<cfinvokeargument name="#linkRelationship.alias#" value="#Record#" />
</cfinvoke>

<cfelse>
<!--- set the parent of this record --->
<cfset Record._setParent(this) />

</cfif>

If a relationship doesn't have an alias it is set to the relationship's name in the linkRelationshipMetadata so this seems to work fine for all relationships.

Again, I've only been using Reactor a few days so if anyone has input on this issue please let me know. I could be totally missing something here. If I don't here anything I plan to submit this a bug on the Reactor site.

Update

I was able to reproduce this issue outside of Model-Glue Unity so I went ahead and submitted a Reactor ticket.

Comments
sal's Gravatar ya know what, I had this same problem on a previous application. Good Post! Have to keep this in mind when using reactor again...
# Posted By sal | 6/5/07 6:19 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.