Data validation in its most simplest terms is applying one or more validation rules to a piece of data. A validation rule might be as simple as making sure a value exists for a required field, it it could more complicated by taking multiple data values and testing them together for certain criteria. Each different application has different data that needs validating and different validation rules of varying complexity that need to be tested. So, in the development of Validat, we chose to create what are call Validators.
What is a Validator?
A validator is a single validation rule which when provided with one or more data values, validates those data values and returns true if the validation passes or returns an error message if the validation fails.
A validator is implemented a simple ColdFusion component that follows a prescribed interface. We did not want to limit the use of Validat to ColdFusion 8, so we did not implement interfaces. Instead, there is a single component called validator.cfc that all validator components extend.
The Interface
Within each validator component are two methods – a init constructor and a single method called validate. It is possible that other methods could be added to support the validation process, but these two methods are required by the API. If you open up any of the validators that come with Validat, the init function does not do much in most cases. The validate function is where the real work is done.
Deconstructing a Validator
Lets take one of the validators that comes with Validat – the alpha validator and break it down to see how it works. The following code is contained in the validateAlpha.cfc component (comments have been stripped).
<cfcomponent
displayname="validateAlpha"
output="false"
hint="Alphabetic string validation rule."
extends="validator">
<!— ———————————————————— —>
<!— constructor —>
<cffunction name="init" access="public" returntype="validateAlpha"
hint="The default constructor for the validator rule, returning the initialized validator rule instance">
<!— call the base constructor —>
<cfset super.init() />
<!— return the initialized validatoin rule —>
<cfreturn this />
</cffunction> <!— end: init() —>
<!— ———————————————————— —>
<!— public methods —>
<!—
function: validate
description: Check to see if the data value contains only alpha characters ( A-Z, a-z ).
—>
<cffunction name="validate" access="public" output="false" returntype="string"
hint="Check to see if the data value contains only alpha characters ( A-Z, a-z ).">
<cfargument name="data" type="any" required="true" hint="The data to be validated" />
<cfargument name="args" type="struct" required="false" default="#structNew()#" hint="The addtional arguments necessary to validate the data" />
<cfargument name="dependencies" type="struct" required="false" default="#structNew()#" hint="The additional dependencies necessary to validate the data" />
<!— check to see if the data value represents a simple string value —>
<cfif NOT isSimpleValue( arguments.data ) >
<cfthrow type="validat.invalidData" message="validat: The validation rule ‘validateAlpha’ only accepts simple data types." />
</cfif>
<!— check to see if the data value contains only alpha characters ( A-Z, a-z ). —>
<cfif NOT reFind(‘[^A-Za-z]’, arguments.data) >
<cfreturn true />
</cfif>
<cfreturn "invalid" />
</cffunction> <!— end: validate() —>
</cfcomponent>
In the <cfcomponent tag, the only thing to really take notice of is the fact that as mentioned before, this component extends the validator object.
The first method of the validator is the init constructor which is public and returns the current validateAlpha object instance after any configuration has been done. In this simple example, the init method calls super.init() which means that it calls the init method on the extended validator object. Then, it just returns the current object.
The second method of the validator is the validate method which performs the real validation work. The interface for this method states that it accepts the data value to be validated, an optional structure of arguments necessary to validate the data, and an optional structure of dependencies necessary to validate the data. The data value is fairly self explanatory, but lets look at the other two arguments.
The arguments structure contains one or more key value pairs for various arguments used in the validation process. An argument might include something like a minimum or maximum value or a list of values to check against. In the case of this validator, no arguments are provided.
The dependencies structure contains one or more key value pairs for various dependencies used in the validation process. A dependency is another data value (data element) that is used with the current data value in the validation process. For example, in testing to see if a state is valid, you would also be dependent upon the country specified as well.
The body of the validate method contains the various checks upon the data value and based upon those checks returns either true or in this case ‘invalid’. The body of this method could include calls to other methods, calls to other objects such as a data access object, etc.
The Big Picture
If you have followed the first two parts of this series, then you have already seen a couple of references to validators. If you create a new validator, the first thing you need to do is register it with the Validat ColdSpring XML configuration file (/src/config/validat.xml). In this configuration file is a section for validators and all of the included validator objects are setup here. To add a new validator object, just add a new line like below to the validat.xml file.
<bean id="validateAlpha" class="validat.validationRules.validateAlpha" />
The bean id value must be unique, but can be anything of your choosing. The class value is the dot notation path to your validator cfc. Remember your bean id as you will need it in the next part.
The second place your validator must be registered is in the data definition that was discussed in the previous part of this series. The data definition contains mappings for all of the validation rules that can be applied to data elements. This mapping looks something like this.
<validationRules>
<rule name="alpha" validator="validateAlpha" />
</validationRules>
The rule element specifies a name for the validator and the validator attribute contains the bean id you created in the ColdSpring XML file. Your validator is now registered and ready to use.
When the Validat data validation engine is processing the data definition upon validation, every time it comes to an assertion element, it takes rule name for that assertion element, matches it to a validation rule, then uses ColdSpring to retrieve an instance of the corresponding validator cfc. It then calls the validate method on that cfc, passing in the current data value and any arguments or dependencies. After getting the result from the validate method, it moves on to the next assertion and the next data element until the entire data set has been processed.
Wrap Up
Validators are just one example of how flexible and customizable the Validat data engine can be. In the next part of this series, we will take a look at Data Transformers which allow Validat to validate any type of data – whether it be a collection of form data, a bean object, or anything else you can come up with. Until then ….