User Input Validation II - ColdBox Series Part 9b

After a week of being sick I am finally getting back on track with my blogging. This is going to be one of the final entries in my Building an Application with ColdBox series. There are a lot of other things I want to blog about. I will still blog on ColdBox topics, just separate from this series.

Last time we talked about how to go about validation. Validation is a really complicated subject that I am still struggling with. I understand the concepts of the different ways of doing it, I just cannot seem to make the time to figure out how I want to do it. I think I will be looking at ValidateThis! in the near future.

In the meantime, we are going to do some pretty rudimentary validation to keep this project moving. I have decided to create a bean that can validate its own data, but then to continue using the BeanFactory plugin to populate the bean. This is not the best way to do this, in my opinion, but it is A way to do it. The main thing I want to show here is how to use the MessageBox plugin and how to persist data from one event handler to another.

So first we are going to modify the validate() method in our List.cfc.

    <cffunction name="validate" access="public" returntype="array" output="false">
        <cfargument name="formData" type="struct" required="true" />
        <cfset var errors = arrayNew(1) />
        <!--- name --->
        <cfif NOT StructKeyExists(formData,"name") OR NOT Len(>
            <cfset ArrayAppend(errors, "You must enter a name") />

        <!--- priority --->
        <cfif NOT StructKeyExists(formData,"priority") OR NOT ListFind("1,2,3",formData.priority)>
            <cfset ArrayAppend(errors, "You must choose a priority") />
        <cfreturn errors />


Here we are accepting the form data submitted by the user as a struct and returning an array of error messages. Again, this is very simple data validation and you will want to look at other ways to handle this and use the way that is best for you. I am looking at ways of using a validation object so that my business objects are not determining the application's validation requirements, as is the case here.

Next, we are going to modify our event handler to call this validation method and pass in the form data.

    <cffunction name="doAddList" access="public" returntype="void" output="false">
        <cfargument name="Event" required="true" type="coldbox.system.beans.requestcontext" />
        <cfset var rc = event.getCollection()>
        <cfset var listBean = variables.todoService.newList() />        
        <cfset var errors = listBean.validate(rc) />
        <cfif NOT ArrayLen(errors)>
            <cfset getPlugin('beanFactory').populateBean(listBean) />
            <cfset variables.todoService.saveList(listBean) />
            <cfset getPlugin("messagebox").setMessage("info", "List Saved")>
            <cfset setNextEvent('list.allLists') />
            <cfset getPlugin("messagebox").setMessage("error", "Errors:<br />", errors) />

            <cfset setNextEvent('list.addList',"",false,"name,priority") />

Here we have added a few things. We've added a local error array that we assign the results of our validate() method that we just created in our list bean.

Next we see if there are any error messages in there. If there are no errors, then we populate the bean and save it, as we did before, but then we are adding a message to the MessageBox plugin before we pass it on to the next event, list.allLists. We'll look at how to render the message in a moment.

The setMessage() method of the MessageBox plugin takes three arguments.

  1. The first argument tells ColdBox what kind of message to render. The choices are "info", "error" and "warning"
  2. The second argument is a string for a single error message
  3. The third argument is for an array of error messages if you have more than one to display.

If there are error messages then we use the MessageBox plugin to set the array of errors messages and then we direct the user back to the addList event.

Notice the additional parameters in the setNextEvent() method. Here, we are telling setNextEvent() to set 'list.addList' as the next event, not to pass any additional URL parameters, not to add the URL token, and then the last parameter is to tell the controller to persist the listed values from the RequestContext(Event) to the next event, because we want them to be pre-filled in the listForm when we return the user to the form.

Next we need to add the code to render messages from the MessageBox plugin, if any exist:

    <cfset WriteOutput(getPlugin("messageBox").renderit(true))>

Paste this code at the top of the listForm.cfm and allLists.cfm views. If there is a message box, it will render it, if not, then nothing will show up. The "true" parameter being passed into the renderit() method tells the MessageBox plugin to clear the messages so they don't show up again.

In my next post, I will probably wrap this series up and attach the finished application. Anything new I add will probably be a review of something we have already done, so there is not much point in doing step-by-step any further. If I do come across something that we have not discussed, I will add it to the final post.

RichardH's Gravatar Your 'ColdBox Series' guide really helped me learning ColdBox & ColdSpring.

Thank you!
# Posted By RichardH | 1/18/09 3:18 PM
Matt G's Gravatar I am very excited to get started with Coldbox...thank you for taking the time to do this!!
# Posted By Matt G | 2/20/09 10:09 AM
Steve's Gravatar Thanks for your help last night Jason. I just finished the tutorial; it has really helped me have a basic understanding of how ColdBox works. Great Stuff!!!
# Posted By Steve | 5/17/09 10:43 PM
Clayton Davis's Gravatar Jason,
What a relief to see this series on ColdBox; Luis does a great job with his docs but I needed that "step-up" from the world of procedural CF. Everything makes sense now! I will be starting on my first procedural-to-OO transition tonight, so I will definitely be back to read more.

Clayton Davis
# Posted By Clayton Davis | 5/24/09 2:46 PM
Jason Dean's Gravatar @Clayton, wow! Thanks. I'm glad to know that you got that kind of help from this. I know it helped solidify it for me to write it. Good luck in your project. Refactoring can be tough.
# Posted By Jason Dean | 5/24/09 3:17 PM
Glyn Jackson's Gravatar before this line:
errors = listBean.validate(rc)

would it not be better to use populateBean?
# Posted By Glyn Jackson | 8/15/09 9:43 AM
Jason Dean's Gravatar @Glyn,

I don;t think it would be. Form data validation is a hot topic and can be done in several way. The reason I do not populate the bean before I validate the data is simple. I do not know if it is valid data yet, so I do not want it in the bean.

If the data in my bean is strongly typed (which usually it it is) then what happens if someone entered the string "jQuery Rulez!!" into a number field? Or they enter 10/20/1975 into a number field? It's going to throw an exception.

So I insist on validating before I try to populate the bean.
# Posted By Jason Dean | 8/16/09 8:36 AM
Fastele's Gravatar Jason,
This has been a great tutorial. I have learnt so much within a short space of time.

Thanks a lot.
# Posted By Fastele | 9/3/09 5:10 PM
Brad's Gravatar Just finished your "User Input Validation II - ColdBox Series Part 9b" this is the BEST ColdBox Series on the web. I was wondering if you ever get a chance to finsh this series up? I didn't see " ColdBox Series Part 9c" or "ColdBox Series Part 10". Thanks again, excellent job!

# Posted By Brad | 6/6/10 3:32 AM
Jason Dean's Gravatar @Brad,

Thanks for the kind words. This is the furthest made it on the series and honestly, I don't see myself going much further with it.

This should be enough to get you going though. From here I would think you should be able to figure out a lot of the rest or at least know what to look for int he ColdBox docs.
# Posted By Jason Dean | 6/6/10 9:57 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner