|
One last thing. A few people who
will remain nameless are working on improvements to reactor’s overall
speed. Apparently they’ve had big successes! These updates will
be committed when they’re ready and do not impact the BC status. Doug From:
[EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Doug Hughes Good evening everyone! I’m happy to announce that I’ve committed a
number of changes and fixes tonight. Here’s a quick rundown: 1) Jared’s
bugs from the other day related to reflexive relationships. 2) The changes
to transactions which were detailed earlier today. 3) The changes
to the oo query which stemmed from Ray’s email earlier today. 4) Big changes
related to validation and the dictionary objects which impact records.
I’ll detail these below. Validation… The reactorFactory now has a new method,
createValidator(). This generates and returns a new validator object.
(More on validators in a sec) When you call createDictionary() on the reactorFactory
(which you would not typically do, but which the framework does for you) it
doesn’t generate an object, it generates an xml document. Previous
versions of reactor had the root node of the dictionary xml documents being
“dictionary”. This has changed to the alias of the object.
So, if you have any dictionary objects you will need to open each xml file and
update the root node to be the correct alias for the object or you will not get
your defined messages back. There’s a new object ErrorCollection which replaces
the ValidationErrorCollection (which had previously been stolen from
Model-Glue). In my opinion the object has a simpler
interface. Dump the object to get all the details. You can call
getErrors() to get an array of all errors. This will have elements with
the structure of {alias}.{field}.{specificError}. For example
User.firstName.notProvided. These match up to the nodes in the dictionary
object. Coincide, the error collection contains a reference to a
dictionary which can be used to automatically translate the errors. Simply
call getTranslatedErrors() on the errorCollection. There’s also the
standard hasErrors() method. When Record objects are validated the validation cascades to
dirty children. So if you have a user who hasMany addresses, when you
call user.validate() it will validate any addresses that are dirty. The validate method on the record object no longer returns
the error collection. You should remove the generated validate method
from all your custom objects. Move the logic into the custom validator
objects. When you call YourRecord.validate() the record creates an
instance of the validator and passes itself to it. The resulting
ErrorCollection is placed in an instance variable in the record. This
allows for the following methods on the record: validated() – Indicates if the record has been
validated ever. hasErrors() – Indicates if the record has
errors. If the record has not been validate this will throw errors. _getErrorCollection() – returns the error
collection. If the record has not been validate this will throw errors. The project validators are somewhat complex.
There’s a base validate method. This calls methods to validate each
field. Each of those methods call methods that validate specific
properties of the field. For example, a validator for a user object might
have a validate method that calls validateFirstName and validateLastName.
ValidateFirstName would call validateFirstNameProvided and
validateFirstNameLength. So, if you wanted to change how one particular property of a
field is validated you would essentially copy the method out of the project
file into your custom file and the edit it as needed. For example, in the
blog sample application the validateArticleProvided method checks to make sure
that the entry has a length. However, I want it to strip out html before
checking. This is what the custom validator looks like: <cfcomponent hint="I am the validator object for the
Entry object. I am generated, but not overwritten if I exist. You
are safe to edit me."
extends="reactor.project.ReactorBlog.Validator.EntryValidator">
<!--- Place custom code here, it will not be overwritten --->
<!--- validateArticleProvided --->
<cffunction name="validateArticleProvided"
access="public" hint="I validate that the article field was
provided" output="false"
returntype="reactor.util.ErrorCollection">
<cfargument name="EntryRecord" hint="I am the EntryRecord to
validate." required="no"
type="reactor.project.ReactorBlog.Record.EntryRecord" />
<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.EntryRecord._getDictionary())#"
/>
<cfset
var article = Trim(ReReplaceNoCase(arguments.EntryRecord.getArticle(),
'(<(.|\n)+?>)|&.+?;|\r|\n|\t', "", "all")) />
<!--- make sure the user actually provided an article --->
<cfif NOT Len(article)>
<cfset arguments.ErrorCollection.addError("Entry.article.notProvided")
/>
</cfif>
<cfreturn arguments.ErrorCollection />
</cffunction> </cfcomponent> If you wanted to add an additional level of validation to a
property you would create your own validate method and then override the
field’s validate method. Tell it to call super.validate() and then
call your custom methods. The following is from the blog sample
too. When a new user is added it checks to make sure the username wasn’t
already used: <cfcomponent hint="I am the validator object for the
User object. I am generated, but not overwritten if I exist. You
are safe to edit me."
extends="reactor.project.ReactorBlog.Validator.UserValidator">
<!--- Place custom code here, it will not be overwritten --->
<!--- validateUsername --->
<cffunction name="validateUsername" access="public"
hint="I validate the username field" output="false"
returntype="reactor.util.ErrorCollection">
<cfargument name="UserRecord" hint="I am the UserRecord to
validate." required="no"
type="reactor.project.ReactorBlog.Record.UserRecord" />
<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.UserRecord._getDictionary())#"
/>
<cfset super.validateUsername(arguments.UserRecord,
arguments.ErrorCollection) />
<!--- validate username is unique --->
<cfset validateUsernameIsUnique(arguments.UserRecord,
arguments.ErrorCollection)>
<cfreturn arguments.ErrorCollection />
</cffunction>
<!--- validateUsernameIsUnique --->
<cffunction name="validateUsernameIsUnique"
access="public" hint="I validate that the username field is
unique" output="false"
returntype="reactor.util.ErrorCollection">
<cfargument name="UserRecord" hint="I am the UserRecord to
validate." required="no"
type="reactor.project.ReactorBlog.Record.UserRecord" />
<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.UserRecord._getDictionary())#"
/>
<cfset var UserGateway =
_getReactorFactory().createGateway("User") />
<!--- insure that another user with the same username does not already exist
--->
<cfif UserGateway.validateUserName(arguments.UserRecord.getUserId(),
arguments.UserRecord.getUserName())>
<cfset arguments.ErrorCollection.addError("User.username.duplicateName")
/>
</cfif>
<cfreturn arguments.ErrorCollection />
</cffunction>
</cfcomponent> So, to avoid errors you’ll need to move all your
validation logic into validator objects and fix the dictionary objects. As always, delete your project files too! Doug |
- [Reactor For CF] Yet another big update committed Doug Hughes
- RE: [Reactor For CF] Yet another big update committed Doug Hughes

