The amazing adventures of Doug Hughes

Validat 101 :: An Example

With In the previous articles in this series, we looked at all of the different concepts that went into developing Validat and making it as flexible as possible.  In this last article, I want to actually show how easy it is to implement Validat into a form validation scenario.  Validat could easily be used to validate business objects or in other data validation scenarios as well, but for now, we will just look at a form validation situation as I expect that will be the most common usage.

The Requirements

There are a few things that need setting up in order to get Validat working.

  • Validat Source – You can get the latest on Validat using your favorite Subversion client from http://svn.alagad.com/Validat/trunk.  As the project progresses, zip files will be made available via the project site for major releases.
  • ColdSpring Framework – Validat utilizes the factory design pattern and by default, the ColdSpring Framework.  The Bleeding Edge version of ColdSpring is required as there are several new features that have name make it into the main release yet.  ColdSpring can be found at http://www.coldspringframework.com.
  • ColdFusion Mappings – The following ColdFusion mappings are necessary and can be setup via the ColdFusion Administrator or your Application.cfc file if you are running ColdFusion 8.
    • /coldspring – Points to the root directory of the ColdSpring framework
    • /validat – Points to the src folder within the Validat distribution

With that out of the way, we are ready to build our example.

The Form

First off, we need a form to collect data to be validated.  There is nothing fancy here, just plain HTML.

<form action="submit.cfm" method="post" name="simpleForm1">
    <fieldset>
        <div class="formField">
            <label for="firstName">First Name:</label>
            <input type="text" name="firstName" id="firstName" class="inputText" />
            <div class="fieldMsg">required, less than 100 characters</div>
        </div>
        <div class="formField">
            <label for="middleName">Middle Name:</label>
            <input type="text" name="middleName" id="middleName" class="inputText" />
            <div class="fieldMsg">optional, less than 100 characters</div>
        </div>
        <div class="formField">
            <label for="lastName">Last Name:</label>
            <input type="text" name="lastName" id="lastName" class="inputText" />
            <div class="fieldMsg">required, less than 100 characters</div>
        </div>
        <div class="formField formButtons">
            <input type="submit" name="action" value="Submit" class="inputButton" />
            <input type="reset" value="Reset" class="inputButton" />
        </div>
    </fieldset>   
</form>

In this form, we have three text input fields … firstName, middleName, and lastName.  Now, in the submit.cfm script, we want to validate these fields and display any errors that might be found.

Validat Rules

Before we can validate the form data from our form, we need to tell Validat what data it is to be expecting and how to validate that data.  For this example, we will just use the configuration XML document mentioned on the first article in this series. 

To setup the configuration, we are going to create a file called validat.xml.  The name can be anything you want, this just makes it obvious as to what it is.

<validat>
 
    <!– validation rule definitions –>
    <validationRules>
       <rule name="length" validator="validateLength">
            <arg name="min" value="0" />
            <arg name="max" value="100" />
        </rule>
    </validationRules>
    <!– data set definitions –>
    <dataSets>
 
        <dataSet name="user">
 
            <dataElement name="firstName" required="true" message="errors.validation.user.firstName.required" >
                <assert rule="length" >
                    <!– optionally, additional arguments can be provided to the validator function –>
                    <arg name="min" value="1" />
                    <arg name="max" value="100" />
                    <message name="invalid" value="errors.validation.user.firstName.invalidLength" />
                </assert>
            </dataElement>
            <dataElement name="middleName" required="false" >
                <assert rule="length" >
                    <arg name="min" value="1" />
                    <arg name="max" value="100" />
                    <message name="invalid" value="errors.validation.user.middleName.invalidLength" />
                </assert>
            </dataElement>
            <dataElement name="lastName" required="true" message="errors.validation.user.lastName.required" >
                <assert rule="length" >
                    <arg name="min" value="1" />
                    <arg name="max" value="100" />
                    <message name="invalid" value="errors.validation.user.lastName.invalidLength" />
                </assert>
            </dataElement>
 
        </dataSet>
 
    </dataSets>
</validat>       

The first section of this file contains the validation rules that we will be using – in this case we will just be testing for fields within a specified length.   The second section of this file contains the data set definition, which we are calling the ‘user’ data set.   Within this data set definition, it shows there will be three data elements that are validated.   The data collection we pass to Validat might well have more than these three data elements, but these there are all that Validat will check. 

According to the data element definitions, both the firstName and lastName data elements are required and all three data elements must have a length between 1 and 100.  The data element definition for middle name looks a bit weird in that it is not required, but it must have a length between 1 and 100.  The way Validat works is that it will check the required state first and if the data value is not required AND it does not contain any data, it will skip the rest of the assertions.  If the data value is required OR it does contain data, then the assertions will be processed.

If you want to read more about this configuration file and its layout, check out the first article in this series.

The ColdSpring Configuration

Quickly before we get to the form script, we need to let ColdSpring know how to instantiate the Validat service object when we request it.   In your ColdSpring.xml file – or you can just create a new one in the same folder if you don’t have one already – insert the following XML snippet.

<beans>
    <import resource="/validat/config/validat.xml" />
    <bean id="validat" class="validat.validat" >
        <constructor-arg name="factory">
            <ref bean="csFactory" />
        </constructor-arg>
        <constructor-arg name="pathToConfigXML">
            <value>validat.xml</value>
        </constructor-arg>
    </bean>
</beans>

The first import tag is what requires the bleeding edge version of ColdSpring as it imports the default ColdSpring configuration for Validat.  This default configuration sets up all of the validators and data transformers that come with the Validat distribution.

The Validat bean element sets the dot notation class path to the Validat service object and passes a couple of arguments to its constructor.  The first is a pointer to the ColdSpring bean factory itself as Validat uses a bean factory to create instances of the validators and data transformers as needed.  By changing this argument value, you could easily put another bean factory implementation in place of ColdSpring if you desired.  The second argument is the path to the Validat XML configuration file we created above.  At this point, it is assumed everything is in the same folder, so a relative path is used.

The Form Submit Script

Now that Validat is configured and knows to validate the data in the form, we just need to set it loose.  Our original form submitted to a file called submit.cfm, so that is the next and last file we will need to create.

First off, the tough part – validating the data.

<!— initialize the ColdSpring bean factory —>
<cfset csFactory = createObject("component", "coldspring.beans.DefaultXmlBeanFactory").init() />
<cfset csFactory.loadBeansFromXmlFile(expandPath("../_common/coldspring.xml"), true) />
 
<!— get an instance of the Validat validation engine —>
<cfset formValidator = csFactory.getBean(‘validat’) />
 
<!— validate the form and collect any errors —>
<cfset errorCollection = formValidator.validate(‘user’, form) />

But that is only 4 lines of code !!! 

Yep, that is all Validat needs and the first two are just setting up the ColdSpring bean factory instance.  The third line of code uses the ColdSpring bean factory to get an instance of Validat and then all of the work is done in the forth line of code.  To validate a collection of data, we simply pass the name of the data set that we are validating the data against, along with the collection of data being validated to the validate method and in return, we get a collection of errors that were found.  That’s it!

The Error Collection

The error collection is an object that comes with Validat and is simply a container for the validation errors found by Validat.  In has a very simple API that allows you to quickly check if it contains errors and to retrieve those errors.

In the above example, to display a message if errors were found would require the following code snippet:

<cfif errorCollection.hasErrors() >
    One or more errors were found in the data you submitted.
</cfif>

To retrieve the list of errors for a given form field and convert them into a list of errors to be displayed, you would use the following code snippet;

<cfif arrayLen(errorCollection.getErrorsByDataElement(‘firstName’)) GT 0 >
    <cfset arrErrors = errorCollection.getErrorsByDataElement(‘firstName’) />
    <cfset fieldErrors = "" />
    <cfloop from="1" to="#arrayLen(arrErrors)#" index="errorPtr">
        <cfset listAppend( fieldErrors, arrErrors[errorPtr].message, ‘<br/>’ ) />
    </cfloop>
<cfelse>
    <cfset fieldErrors = "" />
</cfif>

And with that, you have a complete form validation solution.

Wrap Up

This article wraps up the Validat 101 series.  If you want to find more information about Validat or try it our for yourself, check out the following sites.

Comments on: "Validat 101 :: An Example" (5)

  1. Dan G. Switzer, II said:

    I’m very interested in what your doing with the Validat library. I just wish there wasn’t the dependency on ColdSpring. It just seems like configuration of the Validation rules is spread out over 2 many files.

    I’d rather see 1 XML file for configuring validation rules and use a seperate XML file for handling the dataSet.

    Maybe I’m really missing the mark, but it would seem like it would be easier to port key library component from one project to the next.

    It would be great as well if you could load multiple XML files with the validationRules. That way you can build a base library of the really common tasks and then create project specific validation libraries.

    To me it feels more like ColdSpring complicates the usage more than it helps. Granted, it means there’s more work that Valid has to maintain, but it just seems like it would simpify things in the long run.

    But I may be way offbase…

    Like

  2. Ryan Heldt said:

    There isn’t any XML config files or ColdSpring hooks, but I have a simple validation CFC up on RIAForge (http://validation.riaforge.org). Right now, it’s more data-based validation than rule-based, but it might be more what you’re looking for.

    Like

  3. Mark Mazelin said:

    Jeff:

    I can’t seem to get the Validat download to work. I tried adding and SVN Repository within eclipse (using subeclipse plugin) with this url:
    http://svn.alagad.com/Validat/trunk
    but I keep getting these errors:
    RA layer request failed
    svn: PROPFIND request failed on ‘/Validat/trunk’
    svn: PROPFIND of ‘/Validat/trunk’: could not connect to server (http://svn.alagad.com)

    Any ideas? Am I doing something wrong? I’m coming through a proxy server at work–perhaps that is the issue?

    Like

  4. Mark Mazelin said:

    Jeff:

    The ColdSpring Framework URL you listed at the top of this entry is incorrect: it should be .org, not .com. Here is the correct one:

    http://www.coldspringframework.org/

    Like

  5. Mark Mazelin said:

    Ignore my svn issue. I tried from home (no proxy) and it worked fine. Perhaps the subeclipse plugin ignores eclipse’s proxy settings…

    Like

Comments are closed.

Tag Cloud