Model Glue Form Validation
I've been working on a app with a couple of forms and wanted to break the validation rules into different group of rules e.g.
1. Rules for address
2. Rules for personal information
3. Rules specific per form.
What this allows me to do is is per validation call in the controller just use the validators i need.
How I am doing it:
1. Create a controller called validator.cfc
2. Create you validation.cfc's i.e.
- validator_Personal.cfc
- validator_address.cfc
- validator_other.cfc
Your validation cfc's should look like this:
<cfcomponent>
<cffunction name="validate" returnType="ModelGlue.Util.ValidationErrorCollection">
<cfargument name="formFields">
<cfset var val = createObject("component", "ModelGlue.Util.ValidationErrorCollection").init() />
<cfif structKeyExists(formFields, "address1") AND not len(trim(formFields.address1))>
<cfset val.addError("address1", "Please enter the first line of your address.") />
</cfif>
</cffunction>
</cfcomponent>
3. In validator controller create a listener which has calls the validator objects e.g.
<cffunction name="validateDetails" access="Public" returnType="ModelGlue.Core.Event"
output="false" hint="I am an event handler.">
<cfargument name="event" type="ModelGlue.Core.Event" required="true">
<!--- These are added here for clarity. Usually they should go in the init() --->
<cfset variables.validatePersonal = createObject("component", "model.validator_Personal") >
<cfset variables.validateAddress = createObject("component", "model.validator_address")>
<!--- Validate the values --->
<cfset valReq = variables.validatePersonal.validate(arguments.event.getAllValues()) />
<cfset valAddress = variables.validateAddress.validate(arguments.event.getAllValues()) />
<!--- here we bring to the sets of rules together into on value--->
<cfset valReq.merge(valAddress) />
<!--- Now we set the result --->
<cfif valReq.hasErrors()>
<cfset arguments.event.addResult("inValid") />
<cfset arguments.event.setValue("validation", valReq.getErrors()) />
<cfelse>
<cfset arguments.event.addResult("valid") />
</cfif>
<cfreturn arguments.event />
</cffunction>
4. To finish it off, in your form you need the usual viewState calls
<!--- Gets any validation errors --->
<cfset val = viewState.getValue("validation", structNew()) />
Feed
Twitter
Recent tunes
I had been doing this in my ModelGlue.xml :
<results>
<result name="ValidationError" do="registrationForm" redirect="false" />
<result do="view.template" />
</results>
My problem stems from that redirect being false though. I noticed that when I do that, my main template gets queued more than once in the MG debug information. This is causing my CFMenuItems to get some minor duplication. If I set the redirect to true then the page renders 100% correctly but then I no longer have access to the validation structure.
Interesting enough my ViewState.getValue('LASTNAME') still returns what I typed in with the return type set to true or false.
This is how I do my validation now. Basically I have the form loop back on to its own event. At that point I run the validation rules. If they fail then I redisplay the view, otherwise I redirect them to the next page.
<!-- Have the form loop back on to this event -->
<event-handler name="DisplayCustomerDetailsEvents">
<broadcasts>
<!-- This only runs when the form has been submitted -->
<message name="validateCustomerDetails" />
</broadcasts>
<results>
<result do="view.template" />
<!-- If validateCustomerDetails() is successful then move on -->
<result name="success" do="successful" redirect="true" />
</results>
<views>
<include name="body" template="direct/dspCustomerdetails.cfm" />
</views>
</event-handler>
Does this help?