So you want to create a ModelGlue:Unity application? ( Part 4 )

Previously in this series, we installed the ModelGlue:Unity framework and the ColdSpring framework. We used the ModelGlueApplicationTemplate as the skeleton, added our basic flow and navigation. Finally we can save and list contacts Our Contact-O-Matic is moving right along.

In the last segment, we tested the 'failure' path and were routed back to the form. We also tested the 'success' path and were routed to the contact list. Open the ContactFormBean.cfc located in *ContactManagerMG/Model and edit the validate function (You did check the validate box in the rooibos generator like the last series said, didn't you ;) )

Our validate function should have the returntype of boolean. We will pass in a structure to hold any error messages and check the lengths of our two properties ContactName and ContactType. Your validate function should look like this:

view plain print about
1<cffunction name="validate" access="public" returntype="boolean" output="false">
2    <cfargument name="Errors" type="struct" required="true" />
3    <cfset var tempErrors = structNew() />
4    <cfif NOT len( trim( getContactName() ) ) >
5        <cfset tempErrors['ContactName'] = "Please enter a name for your contact" />
6    </cfif>
7    <cfif NOT len( trim( getContactType() ) )>
8        <cfset tempErrors['ContactType'] = "Please enter a contact type for your contact" />
9    </cfif>        
10    
11    <cfif structCount( tempErrors ) >
12        <cfset structAppend( arguments.Errors, tempErrors ) />
13        <cfreturn false />
14    <cfelse>
15        <cfreturn true />        
16    </cfif>
17
18</cffunction>

Perfect. We have some logic to find out if the entered data is valid. Now we add logic to the controller to only let valid data be saved. If the data is not valid, we will return the user to the form so they can fix it. Open your Controller.cfc located in *ContactManagerMG/controller and find the function named handleContactForm.

As you can see, we currently fill the ContactFormBean using makeEventBean. At that point, all matching values in the event have been loaded. We will validate right after the makeEventBean function. Our validate function takes a struct as an argument so we pass in a new struct. Then based on the return of the validate function, we either add the 'success' or the 'failure' result.

view plain print about
1<cffunction name="handleContactForm" access="public" returnType="void" output="false">
2 <cfargument name="event" type="any">
3 <cfset var ContactFormBean = getModelGlue().getBean( "ContactFormBean" ) />
4 <cfset var ContactService = getModelGlue().getBean( "ContactService") />
5 <cfset var ContactList = ContactService.getContactList() />
6 <cfset var ErrorStruct = structNew () />
7 <cfset var isValid = false />
8
9 <cfset arguments.event.makeEventBean( ContactFormBean ) />
10 <cfset isValid = ContactFormBean.validate( ErrorStruct ) />
11
12 <cfif isValid >
13     <cfset arrayAppend( ContactService.getContactList(), ContactFormBean ) />
14     <cfset arguments.event.setValue( "ContactFormBean", ContactFormBean ) />
15     <cfset arguments.event.addResult("Success") />
16 <cfelse>
17     <cfset arguments.event.setValue("ErrorStruct", ErrorStruct) />
18      <cfset arguments.event.addResult("Failure") />
19 </cfif>
20    
21</cffunction>

Before you run your code, be sure to append &init=true in the URL. It is important to remember to clear the ModelGlue scope each time you change the ModelGlue.xml, ColdSpring.xml, any controller functions, or anything stored in ColdSpring.

Now when you add a contact, the contact is added to the list. If you submit a blank form, you stay on the form. This works well from a flow point of view but isn't very user friendly. We have error messages in a struct, lets put them on the screen for the user to see. Note, in the 'failure' path of the handleContactForm function, we placed the ErrorStruct in the event. The 'failure' result takes us back to the form. Thus, open 'frmContact.cfm' located at *ContactManager/Model and pull the ErrorStruct out of the event. We'll add in a default struct just to make our output cleaner

view plain print about
1<cfset ErrorStruct = viewstate.getValue("ErrorStruct", structNew()) />

Then right above the form, check to see if the struct has any values and loop over them on the screen.

view plain print about
1<cfoutput>
2    
3    <cfif structCount( ErrorStruct ) GT 0 >
4        <cfloop collection="#ErrorStruct#" item="errorType">
5            <li>#ErrorStruct[ errorType ]#</li>
6        </cfloop>
7    </cfif>
8    
9<form id="ContactForm" action="#myself#SubmitContactForm" method="post">
10    <input type="hidden" name="contactID" value="#ContactFormBean.getContactID()#" />
11Name: <input type="text" name="ContactName" value="#ContactFormBean.getContactName()#"><br />
12Type: <input type="text" name="ContactType" value="#ContactFormBean.getContactType()#"><br />
13    <input type="submit" name="submit" value="Submit" />    
14
15</form>
16</cfoutput>

Reload your application and try to submit the blank form. Look ma, error messages!

Hey the validation works!

You could make your validation rules as sophisticated as you like. Perhaps checking to make sure the ContactName starts with a 'D' or the ContactType is 'Friend' as we all know the business rules in an application do change. The nice part about this form of development, is a modification to the validation rules only affects the ContactFormBean. No other files need to be altered to accomplish this. Don't believe me? Lets give it a try

Say our boss comes in and demands only allowing friends into the ContactList. We simply open the ContactFormBean.cfc located at *ContactManagerMG/Model, change the ContactType rule from 'required' to 'friends only' and add an appropriate message.

Old

view plain print about
1<cfif NOT len( trim( getContactType() ) )>
2    <cfset tempErrors['ContactType'] = "Please enter a contact type for your contact" />
3</cfif>

New

view plain print about
1<cfif NOT getContactType() IS 'friend')>
2    <cfset tempErrors['ContactType'] = "Only friends allow in here." />
3</cfif>

Reload your application and try to add an enemy.

Only Friends allowed here!

Change it back to our original 'required' rule, save the file and Reload your application once again. Not too shabby eh?

In this series, we learned how and where to validate our form data. We also learned how to route the user based on the results of their request. The Contact-O-Matic is coming along nicely.

There are no comments for this entry.

Add Comment Subscribe to Comments

8/19/08 10:13 AM # Posted By Fernando Lopez

I'm going through this tutorial for a second time, now that I have a better idea of Beans and other concepts.
Small question/comment on the function validate() shouldn't the tempErrors be a "var" as in < cfset var tempErrors=structNew() /> ?

If that was intended could you explain why? wouldn't TempErrors be created at the "Variables" level?

Fernando


8/19/08 11:09 AM # Posted By Dan Wilson

Good Catch. It is extremely bad form to let a variable leak outside of the intended scope.

I've updated the code so as to reflect the best practice.


12/26/08 2:01 PM # Posted By Kevin

I'm going through these for the first time, it makes sense but will take some effort to get really familiar with MVC & OO for me.

I did notice that you used a variable called isValid and although it is var'd I'd still recommend not naming vars after built in CF functions, for code readability if nothing else. Awesome tutorials, I'm learning a LOT


5/20/09 12:09 AM # Posted By John Ramon

Dan found a small code error

<cfif NOT getContactType() IS 'friend')>
<cfset tempErrors['ContactType'] = "Only friends allow in here." />
</cfif>

should be

<cfif NOT (getContactType() IS 'friend')>
<cfset tempErrors['ContactType'] = "Only friends allow in here." />
</cfif>


Add Comment Subscribe to Comments