Skip navigation.

reactor

MG:Unity - Calling your own custom reactor gateway methods using a Generic list

| |

Are you guys using the ModelGlue generic list? A basic generic list (using reactor as the orm) calls the getByFields() method in the reactor gateway for the object you specify.

for example, if you broadcast this message in your eventhandler:

<message name="modelglue.genericList">
<argument name="object" value="user" />
<argument name="criteria" value="userID" />
</message>

Would call getByFields(UserID={userIDValueInTheViewState})

and stuff the results into the viewstate.



Well, If you need complex query results (joins etc), you can specify the gateway method to call and modelglue will pass on the criteria as arguments to your custom method.

<message name="modelglue.genericList">
<argument name="object" value="user" />
<argument name="criteria" value="userID" />
<argument name="gatewayMethod" value="getUserInfo" />
</message>

Then ModelGlue will take the results and stuff them into the viewstate just like any other generic list.



Reactor.xml: Understanding the difference between 'relate' and 'link'

|

One of my favorite features of reactor (besides everything) is the ability to set up hasOne and HasMany relationships in your reactor.xml file and then be able to use iterators and get other related records and data from the record you are working with. setting up these relationship seems to be an area of confusion for people as they get started with reactor.

Relationships:

There are two basic relationship types: hasOne and HasMany to decide from. this should be an easy task if you already have a basic plan for the app. It may help if you imagine yourself as the object...I am a user object and I 'have many' roles or I am a user and I 'have one' address.

Relationship Types:

Inside the hasOne or hasMany tag, you can define the relationship type.

There are two basic types of reactor.xml relationship types, Reactor syntax calls these 'relate' and 'link'
This is HOW the objects are related. Either a direct relationship(relate) or through a linking table (link)

relate

This is when the Primary key(PK) of one table is used as a foreign key in a second table. This is the one to use if you are only involving 2 tables -with no linking table in the middle. In the below example the 'UserID' PK in the User table is a foreign key in the Reports table. In this instance the user 'Has Many' Reports using a relate tag:

<object name="User" >
    <hasMany name="Report">
        <relate from="UserID" to="UserID" />
    </hasMany>
</object>

this is the easiet to set up in reactor as you just need only define the two objects with a tag within the hasOne or hasMany

link

the 'link' syntax is for when you have a table in the middle like in the case of a user table, a role table and a table that links userID's to RoleID's (UserRole table) This requires three reactor object definitions. in this example: User, Role and UserRole
the user and role both 'have many' of each other:

<object name="User">
    <hasMany name="Role">
        <link name="UserRole" />
    </hasMany>
</object>
<object name="Role">
    <hasMany name="User">
        <link name="UserRole" />
    </hasMany>
</object>

The linking table (UserRole) has 2 hasOne definitions, relating back to the 2 PK's

<object name="UserRole">
    <hasOne name="User">
        <relate from="UserID" to="UserID" />
    </hasOne>
    <hasOne name="Role">
        <relate from="RoleID" to="RoleID" />
    </hasOne>
</object>

Reactor Tip: Super.validate()

|

Using super.validate to add custom validation to reactor:

If you have been copying the entire validate method from the reactor/project/XXX/validator to your extended object to overload the validate method and add extended custom validation, there is a much cleaner and more elegant way to do this. But first, lets cover some reactor validation basics:

Basic Reactor Validation information

Reactor generates basic validation methods based on database metadata. These validations are held in the base validator objects inside the reactor/project folder.
Reactor provides 2 cfc's that extend the base objects, located in the validator subfolder in your "mapping" directory path(set in your reactor configuration). There is one nonDB specific CFC which is also extended by a DB specific one (with the dbtype appended to the filename). Unless you are doing some database specific stuff on your validations You can use the nonDB specific CFC.

Extending Validation

To add extended validation you will need to write a custom function in one of the extended validator CFC's.

In my example below, we will add validation to check to see if one property of a populated record object is a valid choice based on another property. Here is my validation function

<CFFUNCTION name="validateSkyIsBlue" access="public"  output="false" returntype="reactor.util.ErrorCollection">
<CFARGUMENT name="weatherRecord" hint="I am the Record to validate." required="no" type="reactor.project.MemberManager.Record.weatherRecord" />
<CFARGUMENT name="ErrorCollection" hint="I am the error collection to populate. If not provided a new collection is created." required="no" type="reactor.util.ErrorCollection" default="#createErrorCollection(arguments.weatherRecord._getDictionary())#" />
<!--Blue is only allowed as a selection for Sky for people  whose weathercode = 5-->
<CFIF  arguments.weatherRecord.getsky() is "Blue" and arguments.weatherRecord.getweathercode() neq 5 >
<CFSET arguments.ErrorCollection.addError("weather.sky.noBlueAllowed") /> </CFIF>
<CFRETURN arguments.ErrorCollection />
</CFFUNCTION>

(in my dictionary xml files, i added a definition for weather.sky.noBlueAllowed)

To call this method, we need to overload the validate() method to include this validation as well as the reactor generated validation methods. There are two ways to accomplish this, you can copy the entire contents of the validate method from the base object (which I reluctantly admit I was doing until a few weeks ago), Or you can use the "super" keyword to call the base validate method. You will need to pass in the record and the error collection. Here is my validate method as it exists in the extended object:

<CFFUNCTION name="validate" access="public" hint="I validate an  record" output="false" returntype="reactor.util.ErrorCollection">
<CFARGUMENT name="weatherRecord" hint="I am the Record to validate." required="no" type="reactor.project.WeatherManager.Record.weatherRecord" />
<CFARGUMENT name="ErrorCollection" hint="I am the error collection to populate. If not provided a new collection is created." required="no" type="reactor.util.ErrorCollection" default="#createErrorCollection(arguments.weatherRecord._getDictionary())#" />
<CFSET validateSkyIsBlue(arguments.weatherRecord, arguments.ErrorCollection) />
<CFSET super.validate(arguments.weatherRecord, arguments.ErrorCollection) />
<CFRETURN arguments.ErrorCollection />
</CFFUNCTION>

One error collection is returned containg any or all validation errors.
The benefit of doing this as opposed to copying the validate method from the base object is that now you need to make no change to catch validation for new and modified fields in the database.

Syndicate content