# Introduction

This module is a server side rules validation engine that can provide you with a unified approach to object, struct and form validation. You can construct validation constraint rules and then tell the engine to validate them accordingly.

## System Requirements

* Lucee 5+
* ColdFusion 2016+

## Introduction

ColdBox validation is based on a way to declaratively specify validation rules for properties or fields in an object or form. The constraints can exist inside of the target object or you can define object and form constraints in your ColdBox [configuration file](/v1.x/overview/declaring-constraints/configuration-file) so you can reuse validation constraints or as we call them: **shared constraints**.

You can then use 2 simple validation methods and report on the results: `validate(), validateOrFail()`

## Professional Open Source

![Ortus Solutions, Corp](/files/-LWbz0FwX9mtBeSrsDFI)

The ColdBox ORM Module is a professional open source software backed by [Ortus Solutions, Corp](https://www.ortussolutions.com/) offering services like:

* Custom Development
* Professional Support & Mentoring
* Training
* Server Tuning
* Security Hardening
* Code Reviews
* [Much More](https://www.ortussolutions.com/)

### HONOR GOES TO GOD ABOVE ALL

Because of His grace, this project exists. If you don't like this, then don't read it, it's not for you.

> "Therefore being justified by **faith**, we have peace with God through our Lord Jesus Christ: By whom also we have access by **faith** into this **grace** wherein we stand, and rejoice in hope of the glory of God." Romans 5:5


# Installation

## Instructions

Just drop into your **modules** folder or use [CommandBox](https://www.ortussolutions.com/products/commandbox) to install

`box install cbvalidation`

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`. It will also register several helper methods that can be used throughout the ColdBox application.

## Mixins - Helper Methods

The module will also register two methods in your handlers/interceptors/layouts/views

* `validate()`
* `validateOrFail()`
* `getValidationManager()`

```javascript
/**
* Validate an object or structure according to the constraints rules.
* @target An object or structure to validate
* @fields The fields to validate on the target. By default, it validates on all fields
* @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
* @locale The i18n locale to use for validation messages
* @excludeFields The fields to exclude in the validation
* 
* @return cbvalidation.model.result.IValidationResult
*/
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail(){
	return getValidationManager().validateOrFail( argumentCollection=arguments );
}

/**
* Retrieve the application's configured Validation Manager
*/
function getValidationManager()
```


# Configuration

Here are the module settings you can place in your `ColdBox.cfc` by using the `validation` settings structure:

{% code title="config/Coldbox.cfc" %}

```javascript
validation = {
    // The third-party validation manager to use, by default it uses CBValidation.
    manager = "class path",
    // You can store global constraint rules here with unique names
    sharedConstraints = {
        name = {
            field = { constraints here }
        }
    }

}
```

{% endcode %}

| Key                 | Type                             | Required | Default                                 | Description                                                                                                                    |
| ------------------- | -------------------------------- | -------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `manager`           | instantiation path or WireBox ID | false    | `cbValidation.models.ValidationManager` | You can override the module manager with your own implementation. Just use an instantiation path or a valid WireBox object id. |
| `sharedConstraints` | struct                           | false    | `{}`                                    | This structure will hold all of your shared constraints for forms or/and objects.                                              |

{% hint style="danger" %}
**Important:** The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`
{% endhint %}


# Declaring Constraints

You can define constraints in several locations:

1. [Configuration file](/v1.x/overview/declaring-constraints/configuration-file)
2. [Inside domain object](/v1.x/overview/declaring-constraints/domain-object)
3. [A-la-carte](/v1.x/overview/declaring-constraints/a-la-carte-via-event-handlers)

When validating using  `validate(), validateOrFail()` you have to specify a **target**, but specifying a **constraint** in your call is optional.

## Constraints Discovery

When you call the validation methods with NO `constraints` passed explicitly, then the validation module will following this lookup procedure:

* Lookup your constraints in `myTarget.constraints` struct in your target object or struct.
* If you specify your constraint parameter as a string, the validator will lookup a shared constraint in your configuration file.
* If you specify your constraint parameter as a struct, this struct will directly server as your set of constraints, so you can specify your constraints on the fly,  or specify an alternative set of constraints in your model, e.g `User.constraints` vs `User.signInConstraints`


# Configuration File

You can optionally register shared constraints in your [ColdBox configuration](https://github.com/ortus/cbox-validation/tree/cc7e4d96663e1732860bcea678a632286d72e87e/Configuration/README.md) file under the `validation` directive. This means you register them with a **unique** **name** of your choice and its value is a collection of constraints for properties in your objects or forms.&#x20;

Later on you will reference the key **name** in your handlers or wherever in order to validate the object or form. Here is an example:

### Declaration

```javascript
validation = {
    sharedConstraints = {
        sharedUser = {
            fName = {required=true},
            lname = {required=true},
            age   = {required=true, max=18 }
            metadata = {required=false, type="json"}
        },
        loginForm = {
            username = {required=true}, password = {required=true}
        },
        changePasswordForm = {
            password = {required=true,min=6}, password2 = {required=true, sameAs="password", min=6}
        }
    }
}
```

As you can see, our constraints definition describes the set of rules for a property on ANY target object or form.

### Usage

You can then use the keys for those constraints in the validation calls:

```javascript
validate( target, "sharedUser" );

validate( rc, "loginForm" );

validate( rc, "changePasswordForm" );
```


# Domain Object

Within any domain object you can define a public variable called `constraints` that is a assigned an implicit structure of validation rules for any fields or properties in your object.

### Declaration

{% code title="models/User.cfc" %}

```javascript
component persistent="true"{

    // Object properties
    property name="id" fieldtype="id" generator="native" setter="false";
    property name="fname";
    property name="lname";
    property name="email";
    property name="username";
    property name="password";
    property name="age";

    // Validation
    this.constraints = {
        // Constraints go here
    }
}
```

{% endcode %}

We can then create the validation rules for the properties it will apply to it:

{% code title="config/User.cfc" %}

```javascript
component persistent="true"{

    ...

    // Validation
    this.constraints = {
        fname = { required = true },
        lname = { required = true},
        username = {required=true, size="6..10"},
        password = {required=true, size="6..8"},
        email = {required=true, type="email"},
        age = {required=true, type="numeric", min=18}
    };
}
```

{% endcode %}

That easy! You can just declare these validation rules and ColdBox will validate your properties according to the rules. In this case you can see that a password must be between 6 and 10 characters long, and it cannot be blank.

{% hint style="info" %}
By default all properties are of type **string** and **not** required
{% endhint %}

### Usage

You can then use them implicitly

```javascript
validate( myUser );
```


# A-la-carte

You can also define your constraints on the fly right where you are doing your validation.

In this sample we validate the public request context `rc`. This sample validates all fields in the `rc`.  If you need more control you can specify the `fields` parameter (default all) or the `includeFields` and `excludeFields` parameters in your `validate()` call.

```javascript
// sample REST API create user
function create( event, rc, prc ){
	var validationResult = validate( 
		target = rc,
		constraints = { 
			username = { required = true },
			email = { required = true, type = "email" },
			password = { required = true }
		}
	)
	if ( !validationResult.hasErrors() ) {
		UserService.createUser(rc.username, rc.email, rc.password);
		prc.response.setData( UserService.readUser(username=rc.username) );
	} else {
		prc.response
			.setError( true )
			.addMessage( validationResult.getAllErrors())
			.setStatusCode( STATUS.BAD_REQUEST )
			.setStatusText( "Validation error" );
	}
}
```


# Available Constraints

Below are all the currently supported constraints. If you need more you can create your own [Custom validators](/v1.x/advanced/custom-validators).

```javascript
propertyName = {
	// required field or not, includes null values
	required : boolean [false],
	
	// specific type constraint, one in the list.
	type  : (ssn,email,url,alpha,boolean,date,usdate,eurodate,numeric,GUID,UUID,integer,string,telephone,zipcode,ipaddress,creditcard,binary,component,query,struct,json,xml),

	// size or length of the value which can be a (struct,string,array,query)
	size  : numeric or range, eg: 10 or 6..8
	
	// range is a range of values the property value should exist in
	range : eg: 1..10 or 5..-5
	
	// regex validation
	regex : valid no case regex
	
	// same as another property
	sameAs : propertyName
	
	// same as but with no case
	sameAsNoCase : propertyName
	
	// value in list
	inList : list

	// value is unique in the database via the cborm module, it must be installed
	unique : true
	
	// discrete math modifiers
	discrete : (gt,gte,lt,lte,eq,neq):value
	
	// UDF to use for validation, must return boolean accept the incoming value and target object, validate(value,target):boolean
	udf = variables.UDF or this.UDF or a closure.
	
	// Validation method to use in the target object must return boolean accept the incoming value and target object 
	method : methodName
	
	// Custom validator, must implement coldbox.system.validation.validators.IValidator
	validator : path or wirebox id, example: 'mypath.MyValidator' or 'id:MyValidator'
	
	// min value
	min : value
	
	// max value
	max : value
}
```

## Reference

| Constraint     | Type                              | Default |                                                                                                                                                                                                                                               |
| -------------- | --------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `required`     | boolean                           | false   | Whether the property must have a non-null value                                                                                                                                                                                               |
| `type`         | string                            | string  | Validates that the value is of a certain format type. Our included types are: ssn,email,url,alpha,boolean,date,usdate,eurodate,numeric,GUID,UUID,integer,string,telephone,zipcode,ipaddress,creditcard,binary,component,query,struct,json,xml |
| `size`         | numeric or range                  | ---     | The size or length of the value which can be a struct, string, array, or query. The value can be a single numeric value or our cool ranges. Ex: size=4, size=6..8, size=-5..0                                                                 |
| `range`        | range                             | ---     | Range is a range of values the property value should exist in. Ex: range=1..10, range=6..8                                                                                                                                                    |
| `regex`        | regular expression                | ---     | The regular expression to try and match the value with for validation. This is a no case regex check.                                                                                                                                         |
| `sameAs`       | propertyName                      | ---     | Makes sure the value of the constraint is the same as the value of another property in the object. This is a case sensitive check.                                                                                                            |
| `sameAsNoCase` | propertyName                      | ---     | Makes sure the value of the constraint is the same as the value of another property in the object with no case sensitivity.                                                                                                                   |
| `inList`       | string list                       | ---     | A list of values that the property value must exist in                                                                                                                                                                                        |
| `discrete`     | string                            | ---     | Do discrete math in the property value. The valid values are: eq,neq,lt,lte,gt,gte. Example: discrete="eq:4" or discrete="lte:10"                                                                                                             |
| `udf`          | UDF or closure                    | ---     | I can do my own custom validation by doing an inline closure (CF 10 or Railo only) or a pointer to a custom defined function. The function must return boolean and accepts two parameters: value and target.                                  |
| `method`       | method name                       | ---     | The name of a method to call in the target object for validation. The function must return boolean and accepts two parameters: value and target.                                                                                              |
| `min`          | numeric                           | ---     | The value must be greater than or equal to this minimum value                                                                                                                                                                                 |
| `max`          | numeric                           | ---     | The value must be less than or equal to this maximum value                                                                                                                                                                                    |
| `validator`    | instantiation path or wirebox DSL | ---     | You can also build your own validators instead of our internal ones. This value will be the instantiation path to the validator or a wirebox id string. Example: validator="mymodel.validators.MyValidator", validator="id:MyValidator"       |

### Custom Validator

With the `validator` constraint you can specify your own custom validator, but if you need your own parameters for your validator this is a bit limited. You can also specify `YourOwnValidator` as constraint label where `YourOwnValidator` is a wirebox id string. In this  case you can specify your own parameters.&#x20;

See [Advanced Custom Validators](/v1.x/advanced/advanced-custom-validators) for details.

{% hint style="warning" %}
WARNING: You can't do a normal wirebox mapping for `YourOwnValidator` in your main application. A validator needs an `IValidator` interface from the `cbvalidation` module. When wirebox inspects the binder, the `cbvalidation` module is not loaded yet, so it will error. This can be solved by defining your custom validators in an own module (depending on `cbvalidation`) or by mapping your validator in the `afterConfigurationLoad()` method of your binder, e.g in `config/wirebox.cfc`
{% endhint %}


# Unique Constraints

## Usage

The `unique` constraint is part of the [cborm](https://github.com/coldbox/cbox-cborm) module. So make sure that the `cborm` module is installed first.

```bash
box install cborm
```

{% hint style="info" %}
See the [Advanced Custom Validators](/v1.x/advanced/advanced-custom-validators) for a uniqueness validator which is **not** dependent of ORM
{% endhint %}

## Declaring the Constraint

The constraints is mapped into WireBox as `UniqueValidator@cborm` so you can use in your constraints like so:

```javascript
{ fieldName : { validator: "UniqueValidator@cborm" } }
```

## Case Sensitivity

If you will be using the unique constraint, then the name of the property has to be **EXACTLY** the same case as the constraint name. To do this, use single or double quotes to declare the constraint name. Please see example below.

```javascript
this.constraints = {
  "username" = { required=true, validator: "UniqueValidator@cborm" },
  "email" = { required=true, validator: "UniqueValidator@cborm" }
};
```


# Constraint Custom Messages

By default if a constraint fails an error message will be set in the result objects for you in English. If you would like to have your own custom messages for specific constraints you can do so by following the constraint message convention:

```javascript
{constraintName}Message = "My Custom Message";
```

Just add the name of the constraint you like and append to it the work Message and you are ready to roll:

```javascript
username = { 
    required="true", 
    requiredMessage="Please enter the username", 
    size="6-8", 
    sizeMessage="The username must be between 6 to 8 characters" 
}
```


# Custom Message Replacements

We also setup lots of global `{Key}` replacements for your messages and also several that the core constraint validators offer as well. This is great for adding these customizations on your custom messages and also your i18n messages (Keep Reading):

## Global Replacements

* `{rejectedValue}` - The rejected value
* `{field or property}` - The property or field that was validated
* `{validationType}` - The name of the constraint validator
* `{validationData}` - The value of the constraint definition, e.g size=5..10, then this value is 5..10

## Validator Replacements

* `{DiscreteValidator}` - operation, operationValue
* `{InListValidator}` - inList
* `{MaxValidator}` - max
* `{MinValidator}` - min
* `{RangeValidator}` - range, min, max
* `{RegexValidator}` - regex
* `{SameAsValidator}`, `{SameAsNoCaseValidator}` - sameas
* `{SizeValidator}` - size, min, max
* `{TypeValidator}` - type

```javascript
username = { 
    required="true", 
    requiredMessage="Please enter the {field}", 
    size="6-8", 
    sizeMessage="The username must be between {min} and {max} characters" 
}
```


# Validating Constraints

Most likely you will be validating your objects at the controller layer in your ColdBox event handlers. All event handlers,layouts, views and interceptors have some new methods thanks to our module mixins.

```javascript
/**
* Validate an object or structure according to the constraints rules.
* @target An object or structure to validate
* @fields The fields to validate on the target. By default, it validates on all fields
* @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
* @locale The i18n locale to use for validation messages
* @excludeFields The fields to exclude in the validation
* 
* @return cbvalidation.model.result.IValidationResult
*/
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail(){
	return getValidationManager().validateOrFail( argumentCollection=arguments );
}

/**
* Retrieve the application's configured Validation Manager
*/
function getValidationManager()
```

You pass in your target object or structure, an optional list of fields or properties to validate only (by default it does all of them), an an optional constraints argument which can be the shared name or an actual constraints structure a-la-carte. If no constraints are passed, then we will look for the constraints in the target object as a public property called `constraints`. The `validate()` method returns a `cbvalidation.models.results.IValidationResult` type object, which you can then use for evaluating the validation.

```javascript
function saveUser(event,rc,prc){
    // create and populate a user object from an incoming form
    var user = populateModel( entityNew("User") );
    // validate model
    prc.validationResults = validate( user );

    if( prc.validationResults.hasErrors() ){
        // show errors
    }
    else{
        // save
    }

}
```

The return of validate model is our results interface which has cool methods like:

```javascript
interface{

    /**
    * Add errors into the result object
    * @error.hint The validation error to add into the results object
    */
    IValidationResult function addError(required IValidationError error);

    /**
    * Set the validation target object name
    */
    IValidationResult function setTargetName(required string name);

    /**
    * Get the name of the target object that got validated
    */
    string function getTargetName();

    /**
    * Get the locale
    */
    string function getLocale();

    /**
    * has locale information
    */
    boolean function hasLocale();

    /**
    * Set the validation locale
    */
    IValidationResult function setLocale(required string locale);


    /**
    * Determine if the results had error or not
    * @field.hint The field to count on (optional)
    */
    boolean function hasErrors(string field);

    /**
    * Clear All errors
    */
    IValidationResult function clearErrors();


    /**
    * Get how many errors you have
    * @field.hint The field to count on (optional)
    */
    numeric function getErrorCount(string field);

    /**
    * Get the Errors Array, which is an array of error messages (strings)
    * @field.hint The field to use to filter the error messages on (optional)
    */
    array function getAllErrors(string field);

    /**
    * Get an error object for a specific field that failed. Throws exception if the field does not exist
    * @field.hint The field to return error objects on
    */
    IValidationError[] function getFieldErrors(required string field);

    /**
    * Get a collection of metadata about the validation results
    */
    struct function getResultMetadata();

    /**
    * Set a collection of metadata into the results object
    */
    IValidationResult function setResultMetadata(required struct data);

}
```

Some of these methods return error objects which adhere to our Error Interface: `cbvalidation.models.result.IValidationError`, which can quickly tell you what field had the exception, what was the rejected value and the validation message:

```javascript
/**
* Set error metadata that can be used in i18n message replacements or in views
* @data.hint The name-value pairs of data to store in this error.
*/
IValidationError function setErrorMetadata(required any data);

/**
* Get the error metadata
*/
struct function getErrorMetadata();
/**
* Set the error message
* @message.hint The error message
*/
IValidationError function setMessage(required string message);

/**
* Set the field
* @message.hint The error message
*/
IValidationError function setField(required string field);

/**
* Set the rejected value
* @value.hint The rejected value
*/
IValidationError function setRejectedValue(required any value);

/**
* Set the validator type name that rejected
* @validationType.hint The name of the rejected validator
*/
IValidationError function setValidationType(required any validationType);

/**
* Get the error validation type
*/
string function getValidationType();

/**
* Set the validator data
* @data.hint The data of the validator
*/
IValidationError function setValidationData(required any data);

/**
* Get the error validation data
*/
string function getValidationData();

/**
* Get the error message
*/
string function getMessage();

/**
* Get the error field
*/
string function getField();

/**
* Get the rejected value
*/
any function getRejectedValue();
```


# Validating With Failures

In **cbValidation** 1.5 we introduced the `validateOrFail()` function.  This function works in similar manner to the `validate()` method, but instead of giving you the results object, it throws an exception.

| Incoming Target | Validation Fails | Result                                                                              |
| --------------- | ---------------- | ----------------------------------------------------------------------------------- |
| Object          | false            | Returns the same object                                                             |
| Object          | true             | Throws `ValidationException`                                                        |
| Struct          | false            | Returns the structure with ONLY the fields that were validated from the constraints |
| Struct          | true             | Throws `ValidationException`                                                        |

## Exception Extended Info

So your validation fails, where are the results? In the exception structure under the `extendedInfo` key.  We store the validation results as JSON in the extended info and then you can use them for display purposes:

```javascript
try{
    validateOrFail( target );
    service.save( target );
} catch( ValidationException e  ){
    return {
        "error" : true,
        "validationErrors" : deserializeJSON( e.extendedInfo )
    };
}
```

&#x20;


# Validating with shared constraints

We also have the ability to validate a target object or form with shared constraints from our configuration file. Just use the name of the key in the configuration form as the name of the `constraints` argument.

```javascript
    // validate user object
    prc.results = validateModel( target=user, constraints="sharedUser" );

    // validate incoming form elements in the RC or request collection
    prc.results = validateModel( target=rc, constraints="sharedUser" );
```

This will validate the object and `rc` using the `sharedUser` constraints.


# Validating with a-la-carte constraints

&#x20;We also have the ability to validate a target object with custom a-la-carte constraints by passing the constraints inline as an struct of structs. This way you can store these constraint rules anywhere you like.

```javascript
myConstraints = {
	login = { required=true, size=6..10 }, 
	password = { required=true, size=6..10 }
};
prc.results = validateModel( target=user, constraints=myConstraints );
```

&#x20;This will validate the object using the inline constraints that you built.


# Validating Custom Fields

You can also tell the validation manager to ONLY validate on certain fields and not all the fields declared in the validation constraints.

```javascript
prc.results = validateModel( target=user, fields="login,password" );
```

This will only validate the `login` and `password` fields.


# Displaying Errors

After validation you can use the same results object and use it to display the validation errors in your client side:

## Handlers:

```javascript
// store the validation results in the request collection
prc.validationResults = validate( obj );
```

## Views:

```markup
<-- Display all errors as a message box --->
#getInstance( "MessageBox@cbMessagebox" )
    .renderMessage( type="error", messageArray=prc.validationResults.getAllErrors() )#
```

If you want more control you can use the `hasErrors()` and iterate over the errors to display:

```javascript
<cfif prc.validationResults.hasErrors()>
    <ul>
    <cfloop array="#prc.validationResults.getErrors()#" index="thisError">
        <li>#thisError.getMessage()#</li>
    </cfloop>
    </ul>
</cfif>
```

You can even use the results object in your views to get specific field errors, messagesbox, etc.

## Common Methods

The following are some common methods from the validation result object for dealing with errors:

* `getResultMetadata()`
* `getFieldErrors( [field] )`
* `getAllErrors( [field] )`
* `getAllErrorsAsJSON( [field] )`
* `getAllErrorsAsStruct( [field] )`
* `getErrorCount( [field] )`
* `hasErrors( [field] )`
* `getErrors()`

The API Docs in the module (once installed) will give you the latest information about these methods and arguments.


# WireBox DSL & Integration

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`, which is the one you can inject and use anywhere you like.

```javascript
// get reference
property name="validationManager" inject="ValidationManager@cbvalidation";
```


# i18n Integration

## Internationalization

If you are using i18n (Internationalization and Localization) in your ColdBox applications you can also localize your validation error messages from the ColdBox validators.

{% hint style="info" %}
&#x20;**Info** You do not need to install the `cbi18n` module. This module is already a dependency of the `cbvalidation` module.
{% endhint %}

&#x20;You will do this by our lovely conventions for you resource bundle keys:

### &#x20;Objects:

```
{ObjectName}.{Field}.{ConstraintType}}=Message
```

### &#x20;Forms with Shared Constraints Name

```
{SharedConstraintName}.{Field}.{ConstraintType}=Message
```

### &#x20;Forms with No Shared Constraints

```
GenericForm.{Field}.{ConstraintType}=Message
```

### Key Replacements

We also setup lots of global `{Key}` replacements for your messages and also several that the core constraint validators offer as well:

#### Global Replacements

* `{rejectedValue}` - The rejected value
* `{field}` or property - The property or field that was validated
* `{validationType}` - The name of the constraint validator
* `{validationData}` - The value of the constraint definition, e.g size=5..10, then this value is 5..10
* `{targetName}` - The name of the user, shared constraint or form

#### i18n Validator Replacements

* `{DiscreteValidator}` - operation, operationValue
* `{InListValidator}` - inList
* `{MaxValidator}` - max
* `{MinValidator}` - min
* `{RangeValidator}` - range, min, max
* `{RegexValidator}` - regex
* `{SameAsValidator}`, `{SameAsNoCaseValidator}` - SameAs
* `{SizeValidator}` - size, min, max
* `{TypeValidator}` - type

#### **Examples**

```
blank=The field {property} must contain a value.
email=The field {property} is not a valid email address.
unique=The field {property} is not a unique value.
size=The field {property} was not in the size range of {size}.
inlist=The field {property} was not in the list of possible values.
validator=There was a problem with {property}.
min=The minimum value {min} was not met for the field {property}.
max=The maximum value {max} was exceeded for the field {property}.
range=The range was not met for the field {property}.
matches=The field {property} does not match {regex}.
numeric=The field {property} is not a valid number.
```


# Advanced Custom Validators

You can use multiple custom validators or pass in arbitrary data to custom validators by specifying the validator name as the key in the rules struct.

```javascript
//sample custom validator constraints
this.constraints = {
  myField = {
    UniqueInDB = { 
      table= "table_name", 
      column = 'column_name' 
    }    
  }
};
```

This example will look for a `UniqueInDBValidator` in WireBox and pass in `{ table = "table_name", column = "column_name" }` to the `validate` method.

```javascript
//sample validator
/**
* UniqueInDB validator. This checks and returns fals if value is already present in DB
*/
component singleton implements="cbvalidation.models.validators.IValidator" accessors="true"  {
	/**
	 * Constructor
	 */
	UniqueInDB function init(){
		variables.Name = "UniqueInDBValidator";
		return this;
	}
	
	/**
	* validate
	*/
	boolean function validate(
		required cbvalidation.models.result.IValidationResult validationResult,
		required any target,
		required string field,
		any targetValue,
		any validationData
	){
		//check validationdata
		if ( !IsStruct(validationData ) ) {
			throw(message="The validator data is invalid: #arguments.validationData#, it must be a struct with keys 'table' = 'tableName' and 'column' = 'columnName'");
		}
		//check validationdata
		if ( !structKeyExists(validationData,"table") || !structKeyExists(validationData,"column") ) {
			throw(message="The validator data is invalid: #serializeJSON(validationData)# it must be a struct with keys 'table' = 'tableName' and 'column' = 'columnName'");
		}

		var myParams = { table =validationData.table, column=validationData.column, columnvalue=targetValue };
		var sql = "Select #validationData.column# from #validationData.table# where #validationData.column# = :columnvalue";
		var myQuery = queryExecute(sql, myParams);
		// This sample only validates NEW records, additional code is necessary for EDITING existing records
		if  (myQuery.recordcount == 0) { 
			return true 
		} 
		// error messages definieren
		var args = {
			message="The value #targetValue# is not unique in your database",
			field=arguments.field,
			validationType=getName(),
			validationData=arguments.validationData
		};
		var error = validationResult.newError(argumentCollection=args).setErrorMetadata({table=validationData.table, column=validationData.column});
		validationResult.addError( error );
		return false;
	}

	/**
	* getName
	*/
	string function getName(){
		return variables.Name
	}
}
```

Using these advanced techniques you can build reusable validators that accept the data they need in the `validationData` struct. You can also include multiple custom validators just by specifying each of them as a key.

If you don't have any custom data to pass to a validator, just pass an empty struct (`{}`)

{% hint style="warning" %}
WARNING: You can't do a normal wirebox mapping for `YourOwnValidator` in your main application. A validator needs an `IValidator` interface from the `cbvalidation` module. When wirebox inspects the binder, the `cbvalidation` module is not loaded yet, so it will error. This can be solved by defining your custom validators in an own module (depending on `cbvalidation`) or by mapping your validator in the `afterConfigurationLoad()` method of your binder, e.g in `config/wirebox.cfc`
{% endhint %}


# Custom Validators

You can build also your own validators by implementing our interface `cbvalidaton.models.validators.IValidator` :

```javascript
/**
* Will check if an incoming value validates
* @validationResult.hint The result object of the validation
* @target.hint The target object to validate on
* @field.hint The field on the target object to validate on
* @targetValue.hint The target value to validate
*/
boolean function validate(required cbvalidation.models.result.IValidationResult validationResult, required any target, required string field, any targetValue, any validationData);

/**
* Get the name of the validator
*/
string function getName();
```

The arguments received are:

* `validationResults` : The validation result object
* `field` : The field or property in the object that is in validation
* `targetValue` : The value to test

Here is a sample validator:

```javascript
/**
********************************************************************************
Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp
www.coldbox.org | www.luismajano.com | www.ortussolutions.com
********************************************************************************
The ColdBox validator interface, all inspired by awesome Hyrule Validation Framework by Dan Vega
*/
component accessors="true" implements="cbvalidation.models.validators.IValidator" singleton{

    property name="name";

    MaxValidator function init(){
        name = "Max";    
        return this;
    }

    /**
    * Will check if an incoming value validates
    * @validationResult.hint The result object of the validation
    * @target.hint The target object to validate on
    * @field.hint The field on the target object to validate on
    * @targetValue.hint The target value to validate
    * @validationData.hint The validation data the validator was created with
    */
    boolean function validate(required cbvalidation.models.result.IValidationResult validationResult, required any target, required string field, any targetValue, string validationData){

        // Simple Tests
        if( !isNull(arguments.targetValue) AND arguments.targetValue <= arguments.validationData ){
            return true;
        }

        var args = {message="The '#arguments.field#' value is not less than #arguments.validationData#",field=arguments.field,validationType=getName(),validationData=arguments.validationData};
        var error = validationResult.newError(argumentCollection=args).setErrorMetadata({max=arguments.validationData});
        validationResult.addError( error );
        return false;
    }

    /**
    * Get the name of the validator
    */
    string function getName(){
        return name;
    }

}
```

{% hint style="warning" %}
WARNING: You can't do a normal wirebox mapping for `YourOwnValidator` in your main application. A validator needs an `IValidator` interface from the `cbvalidation` module. When wirebox inspects the binder, the `cbvalidation` module is not loaded yet, so it will error. This can be solved by defining your custom validators in an own module (depending on `cbvalidation`) or by mapping your validator in the `afterConfigurationLoad()` method of your binder, e.g in `config/wirebox.cfc`
{% endhint %}


# Custom Validation Managers

If you would like to adapt your own validation engines to work with ANY ColdBox application you can do this by implementing the following interfaces:

* Validation Manager : Implement the `cbvalidation.models.IValidationManager`. Then use the class path in your configuration file so it uses your validation manager instead of ours.
* Validation Results : Implement the `cbvalidation.models.result.IValidationResult`, which makes it possible for any ColdBox application to use your validation results.
* Validation Error : Implement the `cbvalidation.models.result.IValidationError`, which makes it possible for any ColdBox application to use your validation error representations.


# Introduction

This module is a server side rules validation engine that can provide you with a unified approach to object, struct and form validation. You can construct validation constraint rules and then tell the engine to validate them accordingly. You can also create validation profiles to create a more complex validation schema for fields.

## System Requirements

* Lucee 5+
* ColdFusion 2016+

## Introduction

ColdBox validation is based on a way to declaratively specify validation rules for **properties** or **fields** in an object or form. The **constraints** can exist inside of the target object or you can define object and form constraints in your ColdBox [configuration file](/v2.x/overview/declaring-constraints/configuration-file) so you can reuse validation constraints or as we call them: **shared constraints**. You can also create validation constraints on the fly or store them pretty much anywhere you like.

You can then use 2 simple validation methods and report on the results: `validate(), validateOrFail()`

## Professional Open Source

![Ortus Solutions, Corp](/files/-LWbz0FwX9mtBeSrsDFI)

The ColdBox ORM Module is a professional open source software backed by [Ortus Solutions, Corp](https://www.ortussolutions.com/) offering services like:

* Custom Development
* Professional Support & Mentoring
* Training
* Server Tuning
* Security Hardening
* Code Reviews
* [Much More](https://www.ortussolutions.com/)

### HONOR GOES TO GOD ABOVE ALL

Because of His grace, this project exists. If you don't like this, then don't read it, it's not for you.

> "Therefore being justified by **faith**, we have peace with God through our Lord Jesus Christ: By whom also we have access by **faith** into this **grace** wherein we stand, and rejoice in hope of the glory of God." Romans 5:5


# Release History

In this section you will find the release notes for each version we release under this major version.  If you are looking for the release notes of previous major versions use the version switcher at the top left of this documentation book.  Here is a breakdown of our major version releases.


# What's New With 2.1.0

* `feature` : Added `constraintProfiles` to allow you to define which fields to validate according to defined profiles: <https://github.com/coldbox-modules/cbvalidation/issues/37>
* `feature` : Updated `RequiredUnless` and `RequiredIf` to use struct literal notation instead of the weird parsing we did.
* `feature` : Added the `Unique` validator thanks to @elpete!
* `improvement` : Added `null` support for the `RequiredIf,RequiredUnless` validator values


# What's New With 2.0.0

## Features

* No more manual discovery of validators, automated registration and lookup process, cleaned lots of code on this one!
* New Validator: `Accepted` - The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
* New Validator: `Alpha` - Only allows alphabetic characters
* New Validator: `RequiredUnless` with validation data as a struct literal `{ anotherField:value, ... }`  -  The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed `value`.
* New Validator: `RequiredIf` with validation data as a struct literal `{ anotherField:value, ... }`  -  The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`.
* Accelerated validation by removing type checks. ACF chokes on interface checks

## Improvements

* Consistency on all validators to ignore null or empty values except the `Required` validator
* Formatting consistencies
* Improve error messages to describe better validation
* Get away from `evaluate()` instead use `invoke()`

## Compat & Bugs

* `Bugs` : Fixed lots of wrong type exceptions
* `Compat` : Remove ACF11 support


# About This Book

The source code for this book is hosted in GitHub: <https://github.com/ortus-docs/cbvalidation-docs>. You can freely contribute to it and submit pull requests. The contents of this book is copyright by [Ortus Solutions, Corp](http://www.ortussolutions.com) and cannot be altered or reproduced without author's consent. All content is provided *"As-Is"* and can be freely distributed.

* The majority of code examples in this book are done in `cfscript`.
* The majority of code generation and running of examples are done via **CommandBox**: The ColdFusion (CFML) CLI, Package Manager, REPL - <https://www.ortussolutions.com/products/commandbox>

## External Trademarks & Copyrights

Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.

## Notice of Liability

The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software and resources described in it.

## Contributing

We highly encourage contribution to this book and our open source software. The source code for this book can be found in our [GitHub repository](https://github.com/ortus-docs/cbvalidation-docs) where you can submit pull requests.

## Charitable Proceeds

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - <https://www.harvesting.org/>. So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

### Shalom Children's Home

![Shalom Children's Home](https://raw.githubusercontent.com/ortus-docs/logbox-docs/master/images/shalom.jpg)

**Shalom Children’s Home** is one of the ministries that is dear to our hearts located in El Salvador. During the 12 year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education and life skills training in a Christian environment. The home is supported by a child sponsorship program.

We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador that either have no families or have been abandoned. This is good earth to seed and plant.


# Author

## Luis Fernando Majano Lainez

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-LA-UVvG0NM7NpDzssBL%2F-Lk6BFGIHo1oV7R83_YL%2F-Lk6D1zW4YSdITH86ZYX%2FLuis%20F%20Majano.jpg?alt=media\&token=3106d0c5-15df-4fbe-ae5c-1bedd9a9363c)

Luis Majano is a Computer Engineer that has been developing and designing software systems since the year 2000. He was born in [San Salvador, El Salvador](http://en.wikipedia.org/wiki/El_Salvador) in the late 70’s, during a period of economical instability and civil war. He lived in El Salvador until 1995 and then moved to Miami, Florida where he completed his Bachelors of Science in Computer Engineering at [Florida International University](http://fiu.edu). Luis resides in Houston, Texas with his beautiful wife Veronica, baby girl Alexia and baby boy Lucas!

He is the CEO of [Ortus Solutions](http://www.ortussolutions.com), a consulting firm specializing in web development, ColdFusion (CFML), Java development and all open source professional services under the ColdBox and ContentBox stack. He is the creator of ColdBox, ContentBox, WireBox, MockBox, LogBox and anything “BOX”, and contributes to many open source ColdFusion/Java projects. You can read his blog at [www.luismajano.com](http://www.luismajano.com)

Luis has a passion for Jesus, tennis, golf, volleyball and anything electronic. Random Author Facts:

* He played volleyball in the Salvadorean National Team at the tender age of 17
* The Lord of the Rings and The Hobbit is something he reads every 5 years. (Geek!)
* His first ever computer was a Texas Instrument TI-86 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)
* He has a geek love for circuits, microcontrollers and overall embedded systems.
* He has of late (during old age) become a fan of organic gardening.

> Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!
>
> “Trust in the LORD with all your heart, and do not lean on your own understanding.” \
> &#x20;Proverbs 3:5

## Contributors

### Will de Bruin


# Installation

## Instructions

Just drop into your **modules** folder or use [CommandBox](https://www.ortussolutions.com/products/commandbox) to install

`box install cbvalidation`

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`. It will also register several helper methods that can be used throughout the ColdBox application.

## Mixins - Helper Methods

The module will also register two methods in your handlers/interceptors/layouts/views

* `validate()`
* `validateOrFail()`
* `getValidationManager()`

```javascript
/**
 * Validate an object or structure according to the constraints rules.
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return cbvalidation.model.result.IValidationResult
 */
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail()

/**
 * Retrieve the application's configured Validation Manager
 */
function getValidationManager()

```


# Configuration

Here are the module settings you can place in your `ColdBox.cfc` by using the `validation` settings structure:

{% code title="config/Coldbox.cfc" %}

```javascript
validation = {
    // The third-party validation manager to use, by default it uses CBValidation.
    manager = "class path",
    // You can store global constraint rules here with unique names
    sharedConstraints = {
        name = {
            field = { constraints here }
        }
    }

}
```

{% endcode %}

| Key                 | Type                             | Required | Default                                 | Description                                                                                                                    |
| ------------------- | -------------------------------- | -------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `manager`           | instantiation path or WireBox ID | false    | `cbValidation.models.ValidationManager` | You can override the module manager with your own implementation. Just use an instantiation path or a valid WireBox object id. |
| `sharedConstraints` | struct                           | false    | `{}`                                    | This structure will hold all of your shared constraints for forms or/and objects.                                              |

{% hint style="danger" %}
**Important:** The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`
{% endhint %}


# Declaring Constraints

## What are Constraints?

A constraint is by definition the following:

> The state of being restricted or confined within prescribed bounds.

That is exactly what you will create for specific fields. You will declare the constraints for one or more fields. Each constraint will be composed of one or more **validators** and **validation data**. The validation data is defined by the validator and can be of `any` type, the default is an empty struct (`{}`)

```javascript
// Define the field by name
// The contents are the constraints
fieldName1 = {
    validator1 = validationData,
    validator2 = validationData
},

fieldName2 = {
    validator1 = validationData,
    validator2 = validationData
}
```

These constraints can then be defined in many locations where cbValidation can read them.

## Defining Constraints

You can define constraints in several locations:

1. [Configuration file](/v2.x/overview/declaring-constraints/configuration-file)
2. [Inside a domain object](/v2.x/overview/declaring-constraints/domain-object)
3. [A-la-carte](/v2.x/overview/declaring-constraints/a-la-carte-via-event-handlers)

{% hint style="info" %}
When validating using `validate(), validateOrFail()` you have to specify a **target**, but specifying a **constraint** in your call is optional.
{% endhint %}

## Constraints Discovery

When you call the validation methods with **NO** `constraints` passed explicitly, then the validation module will discover the constraints using the following:

* Lookup your constraints in `myTarget.constraints` struct in your target object or struct.
* If you specify your constraint parameter as a **string**, the validator will lookup a shared constraint in your configuration file definitions.
* If you specify your constraint parameter as a **struct**, this struct will directly serve as your set of constraints, so you can specify your constraints on the fly,  or specify an alternative set of constraints in your model, e.g `User.constraints` vs `User.signInConstraints`


# Configuration File

Shared Constraints

You can optionally register constraints in your [ColdBox configuration](https://github.com/ortus/cbox-validation/tree/cc7e4d96663e1732860bcea678a632286d72e87e/Configuration/README.md) file under the `validation` directive. This means you register them with a **unique** **name** of your choice and its value is a collection of constraints for fields in your objects or forms. These will be called lovingly **Shared Constraints.**

Here is an example:

### Declaration

{% code title="config/ColdBox.cfc" %}

```javascript
validation = {
    sharedConstraints = {
        sharedUser = {
            fName = {required=true},
            lname = {required=true},
            age   = {required=true, max=18 }
            metadata = {required=false, type="json"}
        },
        loginForm = {
            username = {required=true}, password = {required=true}
        },
        changePasswordForm = {
            password = {required=true,min=6}, password2 = {required=true, sameAs="password", min=6}
        }
    }
}
```

{% endcode %}

As you can see, our constraints definition describes the set of rules for a property on ANY target object or form by unique key name.

### Usage

You can then use the keys for those constraints in the validation calls:

```javascript
validate( target, "sharedUser" );

validate( rc, "loginForm" );

validate( rc, "changePasswordForm" );
```


# Domain Object

Within any domain object you can define a public variable called `this.constraints` that is a assigned an implicit structure of validation rules for any fields or properties in your object.

### Declaration

{% code title="models/User.cfc" %}

```javascript
component persistent="true"{

    // Object properties
    property name="id" fieldtype="id" generator="native" setter="false";
    property name="fname";
    property name="lname";
    property name="email";
    property name="username";
    property name="password";
    property name="age";

    // Validation
    this.constraints = {
        // Constraints go here
    }
}
```

{% endcode %}

We can then create the validation rules for the properties it will apply to it:

{% code title="config/User.cfc" %}

```javascript
component persistent="true"{

    ...

    // Validation
    this.constraints = {
        fname = { required = true },
        lname = { required = true},
        username = {required=true, size="6..10"},
        password = {required=true, size="6..8"},
        email = {required=true, type="email"},
        age = {required=true, type="numeric", min=18}
    };
}
```

{% endcode %}

That easy! You can just declare these validation rules and ColdBox will validate your properties according to the rules. In this case you can see that a password must be between 6 and 10 characters long, and it cannot be blank.

{% hint style="info" %}
By default all properties are of type **string** and **not** required
{% endhint %}

### Usage

You can then use them implicitly when calling our validation methods:

```javascript
validate( myUser );
validateOrFail( myUser );
```


# A-la-carte

You can also define constraints a-la-carte. Meaning you can create them on the fly or store them as JSON or somewhere in a service. As long as it is a struct of constraints, that's all the validation methods accept via the `constraints` argument.

In this sample we validate the public request context `rc`. This sample validates all fields in the `rc`. If you need more control you can specify the `fields` parameter (default all) or the `includeFields` and `excludeFields` parameters in your `validate()` call.

```javascript
// sample REST API create user
    function create( event, rc, prc ){
        var validationResult = validate(
            target      = rc,
            constraints = {
                username : { required : true },
                email    : { required : true, type : "email" },
                password : { required : true }
            }
        )
        if ( !validationResult.hasErrors() ) {
            UserService.createUser( rc.username, rc.email, rc.password );
            prc.response.setData( UserService.readUser( username = rc.username ) );
        } else {
            prc.response
                .setError( true )
                .addMessage( validationResult.getAllErrors() )
                .setStatusCode( STATUS.BAD_REQUEST )
                .setStatusText( "Validation error" );
        }
    }
```


# Available Constraints

Below are all the currently supported constraints. If you need more you can create your own [Custom validators](/v2.x/advanced/advanced-custom-validators) as well.

```javascript
propertyName = {
        // The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
        accepted : any value,

        // The field must be alphanumeric ONLY
        alpha : any value,

        // discrete math modifiers
        discrete : (gt,gte,lt,lte,eq,neq):value

        // value in list
        inList : list,

        // max value
        max : value,

        // Validation method to use in the target object must return boolean accept the incoming value and target object 
        method : methodName,

        // min value
        min : value,

        // range is a range of values the property value should exist in
        range : eg: 1..10 or 5..-5,

        // regex validation
        regex : valid no case regex

        // required field or not, includes null values
        required : boolean [false],

        // The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`.
        requiredIf : {
            anotherfield:value, anotherfield:value
        }

        // The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed 
        requiredUnless : {
            anotherfield:value, anotherfield:value
        }

        // same as but with no case
        sameAsNoCase : propertyName

        // same as another property
        sameAs : propertyName

        // size or length of the value which can be a (struct,string,array,query)
        size  : numeric or range, eg: 10 or 6..8

        // specific type constraint, one in the list.
        type  : (alpha,array,binary,boolean,component,creditcard,date,email,eurodate,float,GUID,integer,ipaddress,json,numeric,query,ssn,string,struct,telephone,url,usdate,UUID,xml,zipcode),

        // UDF to use for validation, must return boolean accept the incoming value and target object, validate(value,target):boolean
        udf = variables.UDF or this.UDF or a closure.

        // Check if a column is unique in the database
        unique = {
            table : The table name,
            column : The column to check, defaults to the property field in check
        }

        // Custom validator, must implement coldbox.system.validation.validators.IValidator
        validator : path or wirebox id, example: 'mypath.MyValidator' or 'id:MyValidator'
}
```

## accepted

The field must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.

```javascript
terms = { accepted = true }
```

## alpha

The field must be alphabetical ONLY

```javascript
terms = { alpha = true }
```

## discrete

The field must pass certain discrete math operations using the format: `operator:value`

* `gt` - Greater than the value
* `gte` - Greater than or equal to the value
* `lt` - Less than the value
* `lte` - Less than or equal to the value
* `eq` - Equal to the value
* `neq` - Not equal to the value

```javascript
myField = { discrete = "gt:4" }
myField = { discrete = "eq:luis" }
myField = { discrete = "lte:1" }
```

## inList

The field must be in the included list

```javascript
myField = { inList = "red,green,blue" }
```

## max

The field must be less than or equal to the defined value

```javascript
myField = { max = 25 }
```

## method

The `methodName` will be called on the target object and it will pass in validationData and targetValue. It must return a boolean response: **true** = pass, **false** = fail.

```javascript
myField = { method = "methodName" }

function methodName( validationData, targetValue ){
    return true;
}
```

## min

The field must be greater than or equal to the defined value

```javascript
myField = { min = 8 }
```

## range

The field must be within the range values and the validation data must follow the range pattern: `min..max`

```javascript
myField = { range = "1..5" }
myField = { range = "5..-5" }
```

## regex

The field must pass the regular expression match with no case sensitivity

```javascript
myField = { regex = "^(sick|vacation|disability)$" }
```

## required

The field must have some type of value and not null.

```javascript
myField = { required=true }
myField = { required=false }
```

## requiredIf

the field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`.

```javascript
myField = { 
 requiredIf = {
  field2 = "test",
  field3 = "hello"
 }
}
```

## requiredUnless

The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed

```javascript
myField = { 
 requiredUnless = {
  field2 = "test",
  field3 = "hello"
 }
}
```

## sameAsNoCase

The field must be the same as another field with no case sensitivity

```javascript
myField = { sameAs = "otherField" }
```

## sameAs

The field must be the same as another field with case sensitivity

```javascript
myField = { sameAs = "otherField" }
```

## size

The field value size must be within the range values and the validation data must follow the range pattern: `min..max.` Value can be a (struct,string,array,query)

```javascript
myField = { size : 10 }
myFiedl = { size : "8..20" }
```

## type

One of the most versatile validators. It can test if the value is of the following specific types:

* alpha
* array
* binary
* boolean
* component
* creditcard
* date
* email
* eurodate
* float
* GUID
* integer
* ipaddress
* json
* numeric
* query
* ssn
* string
* struct
* telephone
* url
* usdate
* UUID
* xml
* zipcode

```javascript
myField = { type : "float" }
```

## udf

The field value will be passed to the declared closure/lambda to use for validation, must return **boolean** accept the incoming value and target object, `validate(value,target):boolean`

```javascript
myField = { udf = function( value, target ) { return true; } }
myField = { udf = (value,target) => true }
```

## unique

The field must be a unique value in a specific database table. The validation data is a struct with the following keys:

* `table` : The name of the table to check
* `column` : The column to check, defaults to the property field in check&#x20;

```javascript
myField = { unique = { table : "users", column : "username" } }
```

## validator

The field value will be passed to the validator CFC to be used for validation. Please see [Custom Validators](/v2.x/advanced/advanced-custom-validators)

```javascript
myField = { validator = "UniqueValidator@cborm" }
```


# Custom Message Replacements

We also setup lots of global `{Key}` replacements for your messages and also several that the core constraint validators offer as well. This is great for adding these customizations on your custom messages and also your i18n messages (Keep Reading):

## Global Replacements

* `{rejectedValue}` - The rejected value
* `{field or property}` - The property or field that was validated
* `{validationType}` - The name of the constraint validator
* `{validationData}` - The value of the constraint definition, e.g size=5..10, then this value is 5..10

## Validator Replacements

* `{DiscreteValidator}` - operation, operationValue
* `{InListValidator}` - inList
* `{MaxValidator}` - max
* `{MinValidator}` - min
* `{RangeValidator}` - range, min, max
* `{RegexValidator}` - regex
* `{SameAsValidator}`, `{SameAsNoCaseValidator}` - sameas
* `{SizeValidator}` - size, min, max
* `{TypeValidator}` - type

```javascript
username = { 
    required="true", 
    requiredMessage="Please enter the {field}", 
    size="6-8", 
    sizeMessage="The username must be between {min} and {max} characters" 
}
```


# Constraint Custom Messages

By default if a constraint fails an error message will be set in the result objects for you in English. If you would like to have your own custom messages for specific constraints you can do so by following the constraint message convention:

```javascript
{constraintName}Message = "My Custom Message";
```

Just add the name of the constraint you like and append to it the word Message and you are ready to roll:

```javascript
username = { 
    required="true", 
    requiredMessage="Please enter the username", 
    size="6-8", 
    sizeMessage="The username must be between 6 to 8 characters" 
}
```


# Validating Constraints

## Validation Methods: `validate(), validateOrFail()`

Most likely you will be validating your objects at the controller layer in your ColdBox event handlers. All event handlers, layouts, views and interceptors have some new methods thanks to our module mixins.

```javascript
/**
 * Validate an object or structure according to the constraints rules.
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return cbvalidation.model.result.IValidationResult
 */
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail()

/**
 * Retrieve the application's configured Validation Manager
 */
function getValidationManager()
```

You pass in your target object or structure, an optional list of fields or properties to validate only (by default it does all of them), and an optional constraints argument which can be the shared name or an actual constraints structure a-la-carte. If no constraints are passed, then we will look for the constraints in the target object as a public property called `constraints`. The `validate()` method returns a `cbvalidation.models.results.IValidationResult` type object, which you can then use for evaluating the validation.

```javascript
function saveUser( event, rc, prc ){
    // create and populate a user object from an incoming form
    var user = populateModel( entityNew("User") );
    // validate model
    prc.validationResults = validate( user );

    if( prc.validationResults.hasErrors() ){
        // show errors
    }
    else{
        // save
    }
}

function save( event, rc, prc ){
    userService
        .getOrFail( rc.id )
        .populate()
        .validateOrFail()
        .save();
}
```

## Validation Results

The return of validate model is our results interface which has cool methods like and can be found under `cbvalidation.models.result.IValidationResult`

```javascript
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * The ColdBox validation results interface, all inspired by awesome Hyrule Validation Framework by Dan Vega
 */
import cbvalidation.models.result.*;
interface{

    /**
     * Add errors into the result object
     * @error The validation error to add into the results object
     * @error_generic IValidationError
     *
     * @return IValidationResult
     */
    any function addError(required error);

    /**
     * Set the validation target object name
     * @return IValidationResult
     */
    any function setTargetName(required string name);

    /**
     * Get the name of the target object that got validated
     */
    string function getTargetName();

    /**
     * Get the validation locale
     */
    string function getValidationLocale();

    /**
     * has locale information
     */
    boolean function hasLocale();

    /**
     * Set the validation locale
     *
     * @return IValidationResult
     */
    any function setLocale(required string locale);


    /**
     * Determine if the results had error or not
     * @fieldThe field to count on (optional)
     */
    boolean function hasErrors(string field);

    /**
     * Clear All errors
     * @return IValidationResult
     */
    any function clearErrors();


    /**
     * Get how many errors you have
     * @fieldThe field to count on (optional)
     */
    numeric function getErrorCount(string field);

    /**
     * Get the Errors Array, which is an array of error messages (strings)
     * @fieldThe field to use to filter the error messages on (optional)
     */
    array function getAllErrors(string field);

    /**
     * Get an error object for a specific field that failed. Throws exception if the field does not exist
     * @fieldThe field to return error objects on
     *
     * @return IValidationError[]
     */
    array function getFieldErrors(required string field);

    /**
     * Get a collection of metadata about the validation results
     */
    struct function getResultMetadata();

    /**
     * Set a collection of metadata into the results object
     *
     * @return IValidationResult
     */
    any function setResultMetadata(required struct data);

}
```

## Validation Error Object

Some of these methods return error objects which adhere to our Error Interface: `cbvalidation.models.result.IValidationError`, which can quickly tell you what field had the exception, what was the rejected value and the validation message:

```javascript
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * The ColdBox validation error interface, all inspired by awesome Hyrule Validation Framework by Dan Vega
 */
import cbvalidation.models.result.*;
interface {

    /**
     * Set the error message
     * @messageThe error message
     */
    IValidationError function setMessage( required string message );

    /**
     * Set the field
     * @messageThe error message
     */
    IValidationError function setField( required string field );

    /**
     * Set the rejected value
     * @valueThe rejected value
     */
    IValidationError function setRejectedValue( required any value );

    /**
     * Set the validator type name that rejected
     * @validationTypeThe name of the rejected validator
     */
    IValidationError function setValidationType( required any validationType );

    /**
     * Get the error validation type
     */
    string function getValidationType();

    /**
     * Set the validator data
     * @dataThe data of the validator
     */
    IValidationError function setValidationData( required any data );

    /**
     * Get the error validation data
     */
    string function getValidationData();

    /**
     * Get the error message
     */
    string function getMessage();

    /**
     * Get the error field
     */
    string function getField();

    /**
     * Get the rejected value
     */
    any function getRejectedValue();

}
```


# Validating With Failures

In **cbValidation** 1.5 we introduced the `validateOrFail()` function.  This function works in similar manner to the `validate()` method, but instead of giving you the results object, it throws an exception of type `ValidationException`.

| Incoming Target | Validation Fails | Result                                                                              |
| --------------- | ---------------- | ----------------------------------------------------------------------------------- |
| Object          | false            | Returns the same object                                                             |
| Object          | true             | Throws `ValidationException`                                                        |
| Struct          | false            | Returns the structure with ONLY the fields that were validated from the constraints |
| Struct          | true             | Throws `ValidationException`                                                        |

## Exception Extended Info

So your validation fails, where are the results? In the exception structure under the `extendedInfo` key.  We store the validation results as JSON in the extended info and then you can use them for display purposes:

```javascript
try{
    validateOrFail( target );
    service.save( target );
} catch( ValidationException e  ){
    return {
        "error" : true,
        "validationErrors" : deserializeJSON( e.extendedInfo )
    };
}
```

&#x20;


# Validating with shared constraints

We also have the ability to validate a target object or form with shared constraints from our configuration file. Just use the name of the key in the configuration form as the name of the `constraints` argument.

```javascript
    // validate user object
    prc.results = validateModel( target=user, constraints="sharedUser" );

    // validate incoming form elements in the RC or request collection
    prc.results = validateModel( target=rc, constraints="sharedUser" );
```

This will validate the object and `rc` using the `sharedUser` constraints defined in the [configuration file:](/v2.x/overview/declaring-constraints/configuration-file#declaration) `config/Coldbox.cfc`


# Validating with a-la-carte constraints

&#x20;We also have the ability to validate a target object with custom a-la-carte constraints by passing the constraints inline as an struct of structs. This way you can store these constraint rules anywhere you like.

```javascript
var myConstraints = {
	login = { required=true, size=6..10 }, 
	password = { required=true, size=6..10 }
};
prc.results = validateModel( target=user, constraints=myConstraints );
```

&#x20;This will validate the object using the inline constraints that you built.


# Validating Custom Fields

You can also tell the validation manager to **ONLY** validate on certain fields and not all the fields declared in the validation constraints.

```javascript
prc.results = validateModel( target=user, fields="login,password" );
```

This will only validate the `login` and `password` fields.

## Custom Includes/Excludes

You can also use the following arguments:

* `includeFields` : The fields to include in the validation ONLY
* `excludeFields` : The fields to exclude in the validation

```javascript
prc.results = validateModel( 
    target=user, 
    includeFields="username,password", 
    excludeFields="id" 
);
```


# Validating With Profiles

cbValidation 2.x series introduced the ability to validate using field `profiles`.  This will allow you to define all your constraints but also define field profiles where you can define only certain fields to be validated if the profile name is used. &#x20;

## Defining Profiles

This is using the `this.constraintProfiles` struct literal:

```javascript
this.constraintProfiles = {
	"new" = "fname,lname,email,password",
	"update" = "fname,lname,email",
	"passUpdate" = "password,confirmpassword"
}
```

The **key** is the **name** of the profile and the **value** is a list of the fields to validate if the profile is targeted for validation.

## Validating Profiles

Every validation method: `validate(), validateOrFail()` has a `profiles` argument. You can then pass one or more to the argument so you can validate 1 or more profiles:

```javascript
var results = validateModel( target=model, profiles="update" )
var results = validateModel( target=model, profiles="update,passUpdate" )
```


# Displaying Errors

After validation you can use the same results object and use it to display the validation errors in your client side:

## Handlers:

```javascript
// store the validation results in the request collection
prc.validationResults = validate( obj );
```

## Views:

```markup
<-- Display all errors as a message box --->
#getInstance( "MessageBox@cbMessagebox" )
    .renderMessage( type="error", messageArray=prc.validationResults.getAllErrors() )#
```

If you want more control you can use the `hasErrors()` and iterate over the errors to display:

```javascript
<cfif prc.validationResults.hasErrors()>
    <ul>
    <cfloop array="#prc.validationResults.getErrors()#" index="thisError">
        <li>#thisError.getMessage()#</li>
    </cfloop>
    </ul>
</cfif>
```

You can even use the results object in your views to get specific field errors, messagesbox, etc.

## Common Methods

The following are some common methods from the validation result object for dealing with errors:

* `getResultMetadata()`
* `getFieldErrors( [field] )`
* `getAllErrors( [field] )`
* `getAllErrorsAsJSON( [field] )`
* `getAllErrorsAsStruct( [field] )`
* `getErrorCount( [field] )`
* `hasErrors( [field] )`
* `getErrors()`

The API Docs in the module (once installed) will give you the latest information about these methods and arguments.


# WireBox Integration

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`, which is the one you can inject and use anywhere you like.

```javascript
// get reference
property name="validationManager" inject="ValidationManager@cbvalidation";
```

{% hint style="info" %}
Remember you have the mixins available to you in your handlers/interceptors/layouts and views
{% endhint %}


# Custom Validators

If the core validators are not sufficient for you, then you can create your own custom validators. You can either leverage the `udf` validator and create your own closure/lambda to validate inline or create a reusable validator CFC

## Closure/Lambda Validator

If you use the `udf` validator, then you can declare your validation inline. Just create a closure/lambda that will be called for you at the time of validation. This closure/lambda will receive all the following arguments and MUST return a boolean indicator: **true** => passed, **false** => invalid

* `value` : The value to validate, can be null
* `target` : The object that is the target of validation

```javascript
slug : { 
    required : true, 
    udf : ( value, target ) => {
        if( isNull( arguments.value ) ) return false;
        return qb.from( "content" )
            .where( "slug", arguments.value )
            .when( this.isLoaded(), ( q ) => {
                arguments.q.whereNotIn( "id", this.getId() );
            } )
            .count() == 0;
    }
},
```

## Custom CFC Validator

You can also create a reusable CFC that can be shared in any ColdBox app as a validator. Create the CFC and it should implement our interface which can be found here: `cbvalidation.models.validators.IValidator` and it specifies just two functions your own validator must implement: `getName(), validate():`

{% code title="cbvalidation.models.validators.IValidator" %}

```java
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * The ColdBox validator interface, all inspired by awesome Hyrule Validation Framework by Dan Vega
 */
interface {

    /**
     * Will check if an incoming value validates
     * @validationResultThe result object of the validation
     * @targetThe target object to validate on
     * @fieldThe field on the target object to validate on
     * @targetValueThe target value to validate
     * @rules The rules imposed on the currently validating field
     */
    boolean function validate(
        required any validationResult,
        required any target,
        required string field,
        any targetValue,
        any validationData,
        struct rules
    );

    /**
     * Get the name of the validator
     */
    string function getName();

}
```

{% endcode %}

Here is a sample validator:

```javascript
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * This validator validates if a value is is less than a maximum number
 */
component accessors="true" singleton {

    property name="name";

    /**
     * Constructor
     */
    MaxValidator function init(){
        variables.name = "Max";
        return this;
    }

    /**
     * Will check if an incoming value validates
     * @validationResultThe result object of the validation
     * @targetThe target object to validate on
     * @fieldThe field on the target object to validate on
     * @targetValueThe target value to validate
     * @validationDataThe validation data the validator was created with
     */
    boolean function validate(
        required any validationResult,
        required any target,
        required string field,
        any targetValue,
        any validationData,
        struct rules
    ){
        // return true if no data to check, type needs a data element to be checked.
        if ( isNull( arguments.targetValue ) || ( isSimpleValue( arguments.targetValue ) && !len( arguments.targetValue ) ) ) {
            return true;
        }

        // Max Tests
        if ( arguments.targetValue <= arguments.validationData ) {
            return true;
        }

        var args = {
            message        : "The '#arguments.field#' value is not less than or equal to #arguments.validationData#",
            field          : arguments.field,
            validationType : getName(),
            rejectedValue  : ( isSimpleValue( arguments.targetValue ) ? arguments.targetValue : "" ),
            validationData : arguments.validationData
        };
        var error = validationResult.newError( argumentCollection = args ).setErrorMetadata( { max : arguments.validationData } );
        validationResult.addError( error );
        return false;
    }

    /**
     * Get the name of the validator
     */
    string function getName(){
        return variables.name;
    }

}
```

## Defining Custom Validators

You can use them in two approaches when defining them in your constraints:

1. Use the `validator` constraints which points to the Wirebox ID of your own custom validator object. Please note that if you use this approach you will not be able to pass validation data into the validator.
2. Use the WireBox ID as they key of your validator. Then you can pass your own validation data into the validator.

{% hint style="success" %}
Approach number 2 is much more flexible as it will allow you to declare multiple custom validators and each of those validators can receive validation data as well.
{% endhint %}

```javascript
//sample custom validator constraints
    this.constraints = {
        // Approach #1
        myField = {
            required : true, 
            validator : "MyCustomID" 
        },

        // Approach #2
        myField2 = {
            required : true, 
            UniqueInMyDatabase : {
                column : "column_name",
                table : "table_name",
                dsn : "myDatasource"
            },
            MyTimezoneValidator : true
        }
     };
```

{% hint style="success" %}
If you don't have any validation data to pass to a validator, just pass an empty struct (`{}`) or an empty string
{% endhint %}


# Unique ORM Validator

## Usage

The `unique` validator is part of the [cborm](https://github.com/coldbox/cbox-cborm) module. So make sure that the `cborm` module is installed first.

```bash
box install cborm
```

## Declaring the Constraint

The validator is mapped into WireBox as `UniqueValidator@cborm` so you can use in your constraints like so:

```javascript
{ 
    fieldName : { validator: "UniqueValidator@cborm" },
    // or
    fieldName : { "UniqueValidator@cborm" : {}  }
}
```

## Case Sensitivity

If you will be using this validator, then the name of the property has to be **EXACTLY** the same case as the constraint name. To do this, use single or double quotes to declare the constraint name. Please see example below.

```javascript
this.constraints = {
  "username" = { required=true, validator: "UniqueValidator@cborm" },
  "email" = { required=true, validator: "UniqueValidator@cborm" }
};
```

{% hint style="info" %}
This is done because we build the appropriate SQL to make sure the property name and the field name match.
{% endhint %}


# i18n Integration

## Internationalization

If you are using i18n (Internationalization and Localization) in your ColdBox applications you can also localize your validation error messages from the ColdBox validators.

{% hint style="info" %}
&#x20;**Info** You do not need to install the `cbi18n` module. This module is already a dependency of the `cbvalidation` module.
{% endhint %}

&#x20;You will do this by our lovely conventions for you resource bundle keys:

### &#x20;Objects:

```
{ObjectName}.{Field}.{ConstraintType}}=Message
```

### &#x20;Forms with Shared Constraints Name

```
{SharedConstraintName}.{Field}.{ConstraintType}=Message
```

### &#x20;Forms with No Shared Constraints

```
GenericForm.{Field}.{ConstraintType}=Message
```

### Key Replacements

We also setup lots of global `{Key}` replacements for your messages and also several that the core constraint validators offer as well:

#### Global Replacements

* `{rejectedValue}` - The rejected value
* `{field}` or property - The property or field that was validated
* `{validationType}` - The name of the constraint validator
* `{validationData}` - The value of the constraint definition, e.g size=5..10, then this value is 5..10
* `{targetName}` - The name of the user, shared constraint or form

#### i18n Validator Replacements

* `{DiscreteValidator}` - operation, operationValue
* `{InListValidator}` - inList
* `{MaxValidator}` - max
* `{MinValidator}` - min
* `{RangeValidator}` - range, min, max
* `{RegexValidator}` - regex
* `{SameAsValidator}`, `{SameAsNoCaseValidator}` - SameAs
* `{SizeValidator}` - size, min, max
* `{TypeValidator}` - type

#### **Examples**

```
blank=The field {property} must contain a value.
email=The field {property} is not a valid email address.
unique=The field {property} is not a unique value.
size=The field {property} was not in the size range of {size}.
inlist=The field {property} was not in the list of possible values.
validator=There was a problem with {property}.
min=The minimum value {min} was not met for the field {property}.
max=The maximum value {max} was exceeded for the field {property}.
range=The range was not met for the field {property}.
matches=The field {property} does not match {regex}.
numeric=The field {property} is not a valid number.
```


# Custom Validation Managers

If you would like to adapt your own validation engines to work with ANY ColdBox application you can do this by implementing the following interfaces:

* Validation Manager : Implement the `cbvalidation.models.IValidationManager`. Then use the class path in your configuration file so it uses your validation manager instead of ours.
* Validation Results : Implement the `cbvalidation.models.result.IValidationResult`, which makes it possible for any ColdBox application to use your validation results.
* Validation Error : Implement the `cbvalidation.models.result.IValidationError`, which makes it possible for any ColdBox application to use your validation error representations.

Then map it in your configuration file:

{% code title="config/Coldbox.cfc" %}

```javascript
validation = {
    // The third-party validation manager to use, by default it uses CBValidation.
    manager = "my.class.path"
}
```

{% endcode %}

|   |
| - |


# Introduction

This module is a server side rules validation engine that can provide you with a unified approach to object, struct and form validation. You can construct validation constraint rules and then tell the engine to validate them accordingly. You can also create validation profiles to create a more complex validation schema for fields.

## System Requirements

* Lucee 5+
* ColdFusion 2016+

## Introduction

ColdBox validation is based on a way to declaratively specify validation rules for **properties** or **fields** in an object or form. The **constraints** can exist inside of the target object or you can define object and form constraints in your ColdBox [configuration file](/v3.x-1/overview/declaring-constraints/configuration-file) so you can reuse validation constraints or as we call them: **shared constraints**. You can also create validation constraints on the fly or store them pretty much anywhere you like.

You can then use 2 simple validation methods and report on the results: `validate(), validateOrFail()`

## Professional Open Source

![Ortus Solutions, Corp](/files/-LWbz0FwX9mtBeSrsDFI)

The ColdBox ORM Module is a professional open source software backed by [Ortus Solutions, Corp](https://www.ortussolutions.com/) offering services like:

* Custom Development
* Professional Support & Mentoring
* Training
* Server Tuning
* Security Hardening
* Code Reviews
* [Much More](https://www.ortussolutions.com/)

## Discussion & Help

The Box Products discussion group and community can be found here:&#x20;

[https://community.ortussolutions.com/c/communities](https://community.ortussolutions.com/c/communities/contentbox/15)

### HONOR GOES TO GOD ABOVE ALL

Because of His grace, this project exists. If you don't like this, then don't read it, it's not for you.

> "Therefore being justified by **faith**, we have peace with God through our Lord Jesus Christ: By whom also we have access by **faith** into this **grace** wherein we stand, and rejoice in hope of the glory of God." Romans 5:5


# Release History

In this section you will find the release notes for each version we release under this major version.  If you are looking for the release notes of previous major versions use the version switcher at the top left of this documentation book.  Here is a breakdown of our major version releases.

## 3.x

Upgraded to leverage the new cbi18n v2.x module. New CFML engine compatiblities and moving to modernland!

## 2.x

Complete rewrite to script and including tons of new validations, rules and conventions. It also ended the era of ACF11 and Lucee 4.5 support.

## 1.x

Initial awesome release!


# What's New With 3.3.0

2022-JAN-12

### Nested Constraints

Nested structs can be validated using the `constraints` or `nestedConstraints` validator.

```javascript
validateOrFail(
    target = {
        "owner": { "firstName": "John", "lastName": "Doe" }
    },
    constraints = {
        "owner": {
            "constraints": {
                "firstName": { "required": true, "type": "string" },
                "lastName": { "required": true, "type": "string" },
            }
        }
    }
);
```

Using the `nestedConstraints` validator requires the item it is used on be a struct. Otherwise a validation error will occur.

\
When using `nestedConstraints` the field name of the errors will be the dot-delimited path of the target.

```javascript
validateOrFail(
    target = {
        "owner": { "firstName": "John" }
    },
    constraints = {
        "owner": {
            "constraints": {
                "firstName": { "required": true, "type": "string" },
                "lastName": { "required": true, "type": "string" },
            }
        }
    }
);

// ValidationError -> { 
    field: "owner.lastName", 
    message: "The `lastName` field is required" 
}
```

The field name change also applies to `items` or `arrayItem` validators.

```javascript
validateOrFail(
    target = {
        "luckyNumbers": [ 7, "not a number", 11 ]
    },
    constraints = {
        "luckyNumbers": {
            "items": {
                "required": true,
                "type": "numeric"
            }
        }
    }
);

// ValidationError -> { 
field: "luckyNumbers[2]", 
message: "The 'item' has an invalid type, expected type is numeric" 
}
```

The field name changes will allow you to match the validation errors to your fields in your forms.\
While **cbValidation** can nest constraints down as far as you'd like to go, remember that each nested level increases complexity.

### Array and Struct Shorthand Syntax

To make defining array item and nested constraint validators easier, you can use a shorthand on the field name, like so:

```javascript
validateOrFail(
    target = {
        "owner": {
            "firstName": "John",
            "lastName": "Doe",
            "luckyNumbers": [ 7, 11, 21 ],
            "addresses": [
                {
                    "streetOne": "123 Elm Street",
                    "city": "Anytown",
                    "state": "IL",
                    "zip": 60606
                }
            ]
        }
    },
    constraints = {
        "owner.firstName": { "required": true, "type": "string" },
        "owner.lastName": { "required": true, "type": "string" },
        "owner.luckyNumbers.*": { "required": true, "type": "numeric" },
        "owner.addresses.*.streetOne": { "required": true, "type": "string" },
        "owner.addresses.*.streetTwo": { "required": false, "type": "string" },
        "owner.addresses.*.city": { "required": true, "type": "string" },
        "owner.addresses.*.state": { "required": true, "type": "string", "size": 2 },
        "owner.addresses.*.zip": { "required": true, "type": "numeric", "size": 5 }
    }
);
```

Dot-delimited strings represent nested structs while the asterisk (`*`) represents an array of items. This shorthand syntax is expanded to the equivalent syntax above before validating. Use whichever you prefer.

### Validator Aliases

A few of the built-in validators now have an alias in addition to the long form validator name:

```javascript
{
    "items": "arrayItem",
    "constraints": "nestedConstraints"
}
```

Co-authored by [@garciadev](https://github.com/garciadev)

### Added

* Allow UDF and Method Validators to Utilize Error Metadata by @homestar9 (<https://github.com/coldbox-modules/cbvalidation/pull/48>)
* Validator Aliases
* Array and Struct Shorthand Syntax
* Nested Constraints

### Fixed

* Date Comparisons Fail if Compare field is empty #58 thanks to @nockhigan: <https://github.com/coldbox-modules/cbvalidation/pull/58>


# What's New With 3.2.0

2021-NOV-12

### Added

* Migrations to github actions
* ACF2021 Support and automated testing

### Fixed

* Binary Type validator was not working fixed by @nockhigan

### Changed

* Formatting goodness by <andreas.eppinger@webwaysag.ch>


# What's New With 3.1.0

2021-MAY-15

### \[3.1.0] => 2021-MAY-15

#### Added

* New validator: `ArrayItem` which can validate an array's items and make sure all the items pass validation against a specific constraints schema.
* New validator: `DateEquals` which can help you validate that a target value is a date and is the same date as the validation date or other field
* New validator: `After` which can help you validate that a target value is a date and is after the validation date
* New validator: `AfterOrEqual` which can help you validate that a target value is a date and is after or equal the validation date
* New validator: `Before` which can help you validate that a target value is a date and is before the validation date
* New validator: `BeforeOrEqual` which can help you validate that a target value is a date and is before or equal the validation date
* New `onError( closure ), onSuccess( closure )` callbacks that can be used to validate results using the `validate()` method and concatenate the callbacks.
* New `assert()` helper that can assit you in validating truthful expressions or throwing exceptions
* Two new helpers: `validateIsNullorEmpty()` and `validateHasValue()` so you can do simple validations not only on objects and constraints.
* `RequiredIf, RequiredUnless` can now be declared with a simple value pointing to a field. Basically testing if `anotherField` exists, or unless `anotherField` exists.
* New `BaseValidator` for usage by all validators to bring uniformity, global di, and helpers.

#### Changed

* The `IValidator` removes the `getName()` since that comes from the `BaseValidator` now.
* The `UniqueValidator` now supports both creation and update checks with new constraints.
* Removed hard interface requirements to avoid lots of issues across CFML engines. Moved them to the `interfaces` folder so we can continue to document them and use them without direct compilation.

#### Fixed

* Metadata for arguments did not have the right spacing for tosn of validators.
* Added the missing `rules` struct argument to several validators that missed it.


# What's New With 3.0.0

This is a major release as we have updated the internal cbi18n library from v1.x to v2.x and bringing compatibility issues on how you declare your localization settings in ColdBox.  Please see the compatibility guide here on how to update your localization settings. (<https://coldbox-i18n.ortusbooks.com/intro/release-history/whats-new-with-2.0.0#compatibility-updates>)

{% embed url="<https://coldbox-i18n.ortusbooks.com/intro/release-history/whats-new-with-2.0.0#compatibility-updates>" %}

{% hint style="warning" %}
If you are not using localization, then this is a seamless upgrade to you.
{% endhint %}


# What's New With 2.1.0

* `feature` : Added `constraintProfiles` to allow you to define which fields to validate according to defined profiles: <https://github.com/coldbox-modules/cbvalidation/issues/37>
* `feature` : Updated `RequiredUnless` and `RequiredIf` to use struct literal notation instead of the weird parsing we did.
* `feature` : Added the `Unique` validator thanks to @elpete!
* `improvement` : Added `null` support for the `RequiredIf,RequiredUnless` validator values


# What's New With 2.0.0

## Features

* No more manual discovery of validators, automated registration and lookup process, cleaned lots of code on this one!
* New Validator: `Accepted` - The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
* New Validator: `Alpha` - Only allows alphabetic characters
* New Validator: `RequiredUnless` with validation data as a struct literal `{ anotherField:value, ... }`  -  The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed `value`.
* New Validator: `RequiredIf` with validation data as a struct literal `{ anotherField:value, ... }`  -  The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`.
* Accelerated validation by removing type checks. ACF chokes on interface checks

## Improvements

* Consistency on all validators to ignore null or empty values except the `Required` validator
* Formatting consistencies
* Improve error messages to describe better validation
* Get away from `evaluate()` instead use `invoke()`

## Compat & Bugs

* `Bugs` : Fixed lots of wrong type exceptions
* `Compat` : Remove ACF11 support


# About This Book

The source code for this book is hosted in GitHub: <https://github.com/ortus-docs/cbvalidation-docs>. You can freely contribute to it and submit pull requests. The contents of this book is copyright by [Ortus Solutions, Corp](http://www.ortussolutions.com) and cannot be altered or reproduced without author's consent. All content is provided *"As-Is"* and can be freely distributed.

* The majority of code examples in this book are done in `cfscript`.
* The majority of code generation and running of examples are done via **CommandBox**: The ColdFusion (CFML) CLI, Package Manager, REPL - <https://www.ortussolutions.com/products/commandbox>

## External Trademarks & Copyrights

Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.

## Notice of Liability

The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software and resources described in it.

## Contributing

We highly encourage contribution to this book and our open source software. The source code for this book can be found in our [GitHub repository](https://github.com/ortus-docs/cbvalidation-docs) where you can submit pull requests.

## Charitable Proceeds

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - <https://www.harvesting.org/>. So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

### Shalom Children's Home

![Shalom Children's Home](https://raw.githubusercontent.com/ortus-docs/logbox-docs/master/images/shalom.jpg)

**Shalom Children’s Home** is one of the ministries that is dear to our hearts located in El Salvador. During the 12 year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education and life skills training in a Christian environment. The home is supported by a child sponsorship program.

We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador that either have no families or have been abandoned. This is good earth to seed and plant.


# Author

## Luis Fernando Majano Lainez

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-LA-UVvG0NM7NpDzssBL%2F-Lk6BFGIHo1oV7R83_YL%2F-Lk6D1zW4YSdITH86ZYX%2FLuis%20F%20Majano.jpg?alt=media\&token=3106d0c5-15df-4fbe-ae5c-1bedd9a9363c)

Luis Majano is a Computer Engineer that has been developing and designing software systems since the year 2000. He was born in [San Salvador, El Salvador](http://en.wikipedia.org/wiki/El_Salvador) in the late 70’s, during a period of economical instability and civil war. He lived in El Salvador until 1995 and then moved to Miami, Florida where he completed his Bachelors of Science in Computer Engineering at [Florida International University](http://fiu.edu). Luis resides in Houston, Texas with his beautiful wife Veronica, baby girl Alexia and baby boy Lucas!

He is the CEO of [Ortus Solutions](http://www.ortussolutions.com), a consulting firm specializing in web development, ColdFusion (CFML), Java development and all open source professional services under the ColdBox and ContentBox stack. He is the creator of ColdBox, ContentBox, WireBox, MockBox, LogBox and anything “BOX”, and contributes to many open source ColdFusion/Java projects. You can read his blog at [www.luismajano.com](http://www.luismajano.com)

Luis has a passion for Jesus, tennis, golf, volleyball and anything electronic. Random Author Facts:

* He played volleyball in the Salvadorean National Team at the tender age of 17
* The Lord of the Rings and The Hobbit is something he reads every 5 years. (Geek!)
* His first ever computer was a Texas Instrument TI-86 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)
* He has a geek love for circuits, microcontrollers and overall embedded systems.
* He has of late (during old age) become a fan of organic gardening.

> Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!
>
> “Trust in the LORD with all your heart, and do not lean on your own understanding.” \
> &#x20;Proverbs 3:5

## Contributors

### Will de Bruin


# Installation

## Instructions

Just drop into your **modules** folder or use [CommandBox](https://www.ortussolutions.com/products/commandbox) to install

`box install cbvalidation`

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`. It will also register several helper methods that can be used throughout the ColdBox application.

## Mixins - Helper Methods

The module will also register the following methods in your handlers/interceptors/layouts/views

* `validate()`
* `validateOrFail()`
* `getValidationManager()`
* `validatehasValue()`
* `validateIsNullOrEmpty()`
* `assert()`

```javascript
/**
 * Validate an object or structure according to the constraints rules.
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return cbvalidation.model.result.IValidationResult
 */
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail()

/**
 * Retrieve the application's configured Validation Manager
 */
function getValidationManager()

/**
 * Verify if the target value has a value
 * Checks for nullness or for length if it's a simple value, array, query, struct or object.
 */
boolean function validateHasValue( any targetValue )

/**
 * Check if a value is null or is a simple value and it's empty
 *
 * @targetValue the value to check for nullness/emptyness
 */
boolean function validateIsNullOrEmpty( any targetValue )

/**
 * This method mimics the Java assert() function, where it evaluates the target to a boolean value and it must be true
 * to pass and return a true to you, or throw an `AssertException`
 *
 * @target The tareget to evaluate for being true
 * @message The message to send in the exception
 *
 * @throws AssertException if the target is a false or null value
 * @return True, if the target is a non-null value. If false, then it will throw the `AssertError` exception
 */
boolean function assert( target, message="" )
```


# Configuration

You can configure the module by creating a `cbvalidation` key in the `config/Coldbox.cfc` `moduleSettings` structure

{% code title="config/Coldbox.cfc" %}

```javascript
moduleSettings = {
    cbValidation = {
        // The third-party validation manager to use, by default it uses CBValidation.
        manager = "class path",
        // You can store global constraint rules here with unique names
        sharedConstraints = {
            name = {
                field = { constraints here }
            }
        }
    
    }
}
```

{% endcode %}

#### manager

The `manager` key by default points to `cbValidation.models.ValidationManager`.  If you would like to override or decorate our manager, then you can set the classpath of the manager to use.  This manager must adhere to our interface: `cbvalidation.interfaces.IValidationManager`

**sharedConstraints**

This structure will hold all of your shared constraints for forms or/and objects that you can easily reference by name.  It's like declaring the constraints inline but storing them globally.

{% hint style="danger" %}
**Important:** The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`
{% endhint %}


# Declaring Constraints

## What are Constraints?

A constraint is by definition the following:

> The state of being restricted or confined within prescribed bounds.

That is exactly what you will create for specific fields. You will declare the constraints for one or more fields. Each constraint will be composed of one or more **validators** and **validation data**. The validation data is defined by the validator and can be of `any` type, the default is an empty struct (`{}`)

```javascript
// Define the field by name
// The contents are the constraints
fieldName1 = {
    validator1 = validationData,
    validator2 = validationData
},

fieldName2 = {
    validator1 = validationData,
    validator2 = validationData
}
```

These constraints can then be defined in many locations where cbValidation can read them.

## Defining Constraints

You can define constraints in several locations:

1. [Configuration file](/v3.x-1/overview/declaring-constraints/configuration-file)
2. [Inside a domain object](/v3.x-1/overview/declaring-constraints/domain-object)
3. [A-la-carte](/v3.x-1/overview/declaring-constraints/a-la-carte-via-event-handlers)

{% hint style="info" %}
When validating using `validate(), validateOrFail()` you have to specify a **target**, but specifying a **constraint** in your call is optional.
{% endhint %}

## Constraints Discovery

When you call the validation methods with **NO** `constraints` passed explicitly, then the validation module will discover the constraints using the following:

* Lookup your constraints in `myTarget.constraints` struct in your target object or struct.
* If you specify your constraint parameter as a **string**, the validator will lookup a shared constraint in your configuration file definitions.
* If you specify your constraint parameter as a **struct**, this struct will directly serve as your set of constraints, so you can specify your constraints on the fly,  or specify an alternative set of constraints in your model, e.g `User.constraints` vs `User.signInConstraints`


# Configuration File

Shared Constraints

You can optionally register constraints in your [ColdBox configuration](https://github.com/ortus/cbox-validation/tree/cc7e4d96663e1732860bcea678a632286d72e87e/Configuration/README.md) file under the `validation` directive. This means you register them with a **unique** **name** of your choice and its value is a collection of constraints for fields in your objects or forms. These will be called lovingly **Shared Constraints.**

Here is an example:

### Declaration

{% code title="config/ColdBox.cfc" %}

```javascript
validation = {
    sharedConstraints = {
        sharedUser = {
            fName = {required=true},
            lname = {required=true},
            age   = {required=true, max=18 }
            metadata = {required=false, type="json"}
        },
        loginForm = {
            username = {required=true}, password = {required=true}
        },
        changePasswordForm = {
            password = {required=true,min=6}, password2 = {required=true, sameAs="password", min=6}
        }
    }
}
```

{% endcode %}

As you can see, our constraints definition describes the set of rules for a property on ANY target object or form by unique key name.

### Usage

You can then use the keys for those constraints in the validation calls:

```javascript
validate( target, "sharedUser" );

validate( rc, "loginForm" );

validate( rc, "changePasswordForm" );
```


# Domain Object

Within any domain object you can define a public variable called `this.constraints` that is a assigned an implicit structure of validation rules for any fields or properties in your object.

### Declaration

{% code title="models/User.cfc" %}

```javascript
component persistent="true"{

    // Object properties
    property name="id" fieldtype="id" generator="native" setter="false";
    property name="fname";
    property name="lname";
    property name="email";
    property name="username";
    property name="password";
    property name="age";

    // Validation
    this.constraints = {
        // Constraints go here
    }
}
```

{% endcode %}

We can then create the validation rules for the properties it will apply to it:

{% code title="config/User.cfc" %}

```javascript
component persistent="true"{

    ...

    // Validation
    this.constraints = {
        fname = { required = true },
        lname = { required = true},
        username = {required=true, size="6..10"},
        password = {required=true, size="6..8"},
        email = {required=true, type="email"},
        age = {required=true, type="numeric", min=18}
    };
}
```

{% endcode %}

That easy! You can just declare these validation rules and ColdBox will validate your properties according to the rules. In this case you can see that a password must be between 6 and 10 characters long, and it cannot be blank.

{% hint style="info" %}
By default all properties are of type **string** and **not** required
{% endhint %}

### Usage

You can then use them implicitly when calling our validation methods:

```javascript
validate( myUser );
validateOrFail( myUser );
```


# A-la-carte

You can also define constraints a-la-carte. Meaning you can create them on the fly or store them as JSON or somewhere in a service. As long as it is a struct of constraints, that's all the validation methods accept via the `constraints` argument.

In this sample we validate the public request context `rc`. This sample validates all fields in the `rc`. If you need more control you can specify the `fields` parameter (default all) or the `includeFields` and `excludeFields` parameters in your `validate()` call.

```javascript
// sample REST API create user
    function create( event, rc, prc ){
        var validationResult = validate(
            target      = rc,
            constraints = {
                username : { required : true },
                email    : { required : true, type : "email" },
                password : { required : true }
            }
        )
        if ( !validationResult.hasErrors() ) {
            UserService.createUser( rc.username, rc.email, rc.password );
            prc.response.setData( UserService.readUser( username = rc.username ) );
        } else {
            prc.response
                .setError( true )
                .addMessage( validationResult.getAllErrors() )
                .setStatusCode( STATUS.BAD_REQUEST )
                .setStatusText( "Validation error" );
        }
    }
```


# Available Constraints

Below are all the currently supported constraints. If you need more you can create your own [Custom validators](/v3.x-1/advanced/advanced-custom-validators) as well.

```javascript
propertyName = {
        // The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
        accepted : any value
        
        // The field under validation must be a date after the set targetDate
        after : targetDate
        
        // The field under validation must be a date after or equal the set targetDate
        afterOrEqual : targetDate

        // The field must be alpha ONLY
        alpha : any value
        
        // The field under validation is an array and all items must pass this validation as well
        arrayItem : {
            // All the constraints to validate the items with
        }
        
        // The field under validation must be a date before the set targetDate
        before : targetDate
        
        // The field under validation must be a date before or equal the set targetDate
        beforeOrEqual : targetDate
        
        // The field under validation is a struct and all nested validation rules must pass
        constraints: {
           // All the constraints for the nested struct
        }
        
        // The field under validation must be a date that is equal the set targetDate
        dateEquals : targetDate
        
        // discrete math modifiers
        discrete : (gt,gte,lt,lte,eq,neq):value
        
        // the field must or must not be an empty value
        // needed because `required` counts empty strings as valid
        // and `type` ignores empty strings as "not required"
        empty : boolean [false]

        // value in list
        inList : list
        
        // An alias for arrayItem
        items : {
            // All the constraints to validate the items with
        }

        // max value
        max : value

        // Validation method to use in the target object must return boolean accept the incoming value and target object 
        method : methodName

        // min value
        min : value
        
        // An alias for constraints
        nestedConstraints: {
           // All the constraints for the nested struct
        }

        // range is a range of values the property value should exist in
        range : eg: 1..10 or 5..-5

        // regex validation
        regex : valid no case regex

        // required field or not, includes null values
        required : boolean [false]

        // The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`.
        requiredIf : {
            anotherfield:value, anotherfield:value
        }

        // The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed 
        requiredUnless : {
            anotherfield:value, anotherfield:value
        }

        // same as but with no case
        sameAsNoCase : propertyName

        // same as another property
        sameAs : propertyName

        // size or length of the value which can be a (struct,string,array,query)
        size  : numeric or range, eg: 10 or 6..8

        // specific type constraint, one in the list.
        type  : (alpha,array,binary,boolean,component,creditcard,date,email,eurodate,float,GUID,integer,ipaddress,json,numeric,query,ssn,string,struct,telephone,url,usdate,UUID,xml,zipcode),

        // UDF to use for validation, must return boolean accept the incoming value and target object, validate(value,target,metadata):boolean
        udf = variables.UDF or this.UDF or a closure.

        // Check if a column is unique in the database
        unique = {
            table : The table name,
            column : The column to check, defaults to the property field in check
        }

        // Custom validator, must implement coldbox.system.validation.validators.IValidator
        validator : path or wirebox id, example: 'mypath.MyValidator' or 'id:MyValidator'
}
```

## accepted

The field must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.

```javascript
terms = { accepted = true }
```

## after

The field under validation must be a value after a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested.

```javascript
startDate : { required:true, type:"date", after: dateAdd( "d", 1, now() ) }
```

Instead of passing a date, you may specify another field to compare against the date as well:

```javascript
endDate : { required:true, type:"date", after: "startDate" }
```

## afterOrEqual

The field under validation must be a value after or equal a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested.

```javascript
startDate : { required:true, type:"date", afterOrEqual: dateAdd( "d", 1, now() ) }
```

## alpha

The field must be alphabetical ONLY

```javascript
terms = { alpha = true }
```

## arrayItem

This validator is used to validate an array's items. It will iterate through each of the array's items and validate each item against the `validationData` constraints you pass in.

```cfscript
luckyNumbers = {
    required : true,
    type : "array",
    arrayItem : {
        required : true,
        type : "numeric"
    }
}
```

You may also specify `items` as an alias to `arrayItem`.

```cfscript
luckyNumbers = {
    required : true,
    type : "array",
    items : {
        required : true,
        type : "numeric"
    }
}
```

Any validation errors found will be named using the parent field name and array index.

```cfscript
var validationResult = validate(
    target = {
        "luckyNumbers": [ 7, 11, "not a number", 21 ]
    },
    constraints = {
        required : true,
        type : "array",
        items : {
            required : true,
            type : "numeric"
        }
    }
);
```

```json
// validationResult.getAllErrorsAsJson()
{
    "luckyNumbers[3]": ["The 'item' has an invalid type, expected type is numeric"]
}
```

You can validate nested structs by nesting a `constraints` validator.

```javascript
invoiceItems = {
    required : true,
    type : "array",
    arrayItem : {
        type : "struct",
        constraints : {
            logDate : { required : true, type : "date" },
            isBilled : { required: true, type : "boolean" },
            notes : { required: true }
        }
    }
}
```

There is a [shortcut notation available](/v3.x-1/overview/valid-constraints/nested-struct-and-array-field-name-shortcuts#nested-array-shorthand) for `arrayItem` that uses a specialized field name to skip nesting the constraints.

## before

The field under validation must be a value before a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested.

```javascript
endDate : { required:true, type:"date", before: "01/01/2022" }
```

Instead of passing a date, you may specify another field to compare against the date as well:

```javascript
startDate : { required:true, type:"date", before: "endDate" }
```

## beforeOrEqual

The field under validation must be a value before or equal a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested.

```javascript
endDate : { required:true, type:"date", beforeOrEqual: "01/01/2022" }
```

## constraints

This validator is used to validate a nested struct. The value of this validator are the constraints for the nested struct.

```cfscript
address = {
    "required": true,
    "type": "struct",
    "constraints": {
        "streetOne": { "required": true, "type": "string" },
        "streetTwo": { "required": false, "type": "string" },
        "city": { "required": true, "type": "string" },
        "state": { "required": true, "type": "string", "size": 2 },
        "zip": { "required": true, "type": "numeric", "size": 5 }
    }
}
```

Any validation errors found will be named using the parent field name and the child field name.

```cfscript
var validationResult = validate(
    target = {
        "address": {
            "streetOne" : "123 Elm Street",
            "streetTwo" : "",
            "city"      : "Anytown",
            "zip"       : "60606"
        }
    },
    constraints = {
        "address": {
            "required": true,
            "type": "struct",
            "constraints": {
                "streetOne": { "required": true, "type": "string" },
                "streetTwo": { "required": false, "type": "string" },
                "city": { "required": true, "type": "string" },
                "state": { "required": true, "type": "string", "size": 2 },
                "zip": { "required": true, "type": "numeric", "size": 5 }
            }
        }
    }
);
```

```json
// validationResult.getAllErrorsAsJson()
{
    "address.state": ["The 'state' field is required"]
}
```

`constraints` can be used as many levels deep as you need to go.

```cfscript
owner = {
    "firstName": { "required": true, "type": "string" },
    "lastName": { "required": true, "type": "string" },
    "address": {
        "required": true,
        "type": "struct",
        "constraints": {
            "streetOne": { "required": true, "type": "string" },
            "streetTwo": { "required": false, "type": "string" },
            "city": { "required": true, "type": "string" },
            "state": { "required": true, "type": "string", "size": 2 },
            "zip": { "required": true, "type": "numeric", "size": 5 }
        }
    }
}
```

`constraints` can also be combined with `items` to validate an array of structs.

```cfscript
invoiceItems = {
    required : true,
    type : "array",
    arrayItem : {
        type : "struct",
        constraints : {
            logDate : { required : true, type : "date" },
            isBilled : { required: true, type : "boolean" },
            notes : { required: true }
        }
    }
}
```

There is a [shortcut notation available](/v3.x-1/overview/valid-constraints/nested-struct-and-array-field-name-shortcuts#nested-struct-shorthand) for `constraints` that uses a specialized field name to skip nesting the constraints.

## dateEquals

The field under validation must be a value that is the same as the given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested.

```javascript
endDate : { required:true, type:"date", dateEquals: "01/01/2022" }
```

Instead of passing a date, you may specify another field to compare against the date as well:

```javascript
startDate : { required:true, type:"date", dateEquals: "createdDate" }
```

## discrete

The field must pass certain discrete math operations using the format: `operator:value`

* `gt` - Greater than the value
* `gte` - Greater than or equal to the value
* `lt` - Less than the value
* `lte` - Less than or equal to the value
* `eq` - Equal to the value
* `neq` - Not equal to the value

```javascript
myField = { discrete = "gt:4" }
myField = { discrete = "eq:luis" }
myField = { discrete = "lte:1" }
```

## empty

The field is not required but if it exists it cannot be empty.

```javascript
myField = { empty = false }
```

This is needed since [required](#required) validators allow empty strings when `false` while [type](#type) validators ignore empty values as valid. This means we can have a situation as follows:

```javascript
{
    "startDate": {
        "required": false,
        "type": "date"
    }
}
```

With these validation rules passing in `startDate = ""` would pass the validation! The empty validator helps us ensure that the value passed in is not empty (and, in this case, a date).

```javascript
{
    "startDate": {
        "required": false,
        "empty": false,
        "type": "date"
    }
}
```

The field still isn't required, but if it is passed the value must be a non-empty value and it must be parseable as a date.

## inList

The field must be in the included list

```javascript
myField = { inList = "red,green,blue" }
```

## items

See [arrayItem](#arrayitem).

## max

The field must be less than or equal to the defined value

```javascript
myField = { max = 25 }
```

## method

The `methodName` will be called on the target object and it will pass in validationData, targetValue, and metadata. It must return a boolean response: **true** = pass, **false** = fail.

Any data you place in the `metadata` structure will be set in the validation result object for later retrieval.

```javascript
myField = { method = "methodName" }

function methodName( validationData, targetValue, metadata ){
    metadata[ "customMessage" ] = "I am a custom message set via metadata.";
    return false;
}
```

## min

The field must be greater than or equal to the defined value

```javascript
myField = { min = 8 }
```

## nestedConstraints

See [constraints](#constraints).

## range

The field must be within the range values and the validation data must follow the range pattern: `min..max`

```javascript
myField = { range = "1..5" }
myField = { range = "5..-5" }
```

## regex

The field must pass the regular expression match with no case sensitivity

```javascript
myField = { regex = "^(sick|vacation|disability)$" }
```

## required

The field must have some type of value and not null.

```javascript
myField = { required=true }
myField = { required=false }
```

## requiredIf

The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`. The validation data can be a `struct` or a `string` representing the field to check.

```javascript
// Struct based
myField = { 
 // myField is required if field2 = test and field3 = hello
 requiredIf = {
  field2 = "test",
  field3 = "hello"
 }
}

// String Based
myField = {
 // myField is required if field3 exists and has a value.
 requiredIf = "field3"
}
```

## requiredUnless

The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed `value`. The validation data can be a `struct` or a `string` representing the field to check.

```javascript
myField = { 
 // myField is required unless field2 = test and field3 = hello
 requiredUnless = {
  field2 = "test",
  field3 = "hello"
 }
}

// String Based
myField = {
 // myField is required unless field3 exists and has a value.
 requiredUnless = "field3"
}
```

## sameAsNoCase

The field must be the same as another field with no case sensitivity

```javascript
myField = { sameAs = "otherField" }
```

## sameAs

The field must be the same as another field with case sensitivity

```javascript
myField = { sameAs = "otherField" }
```

## size

The field value size must be within the range values and the validation data must follow the range pattern: `min..max.` Value can be a (struct,string,array,query)

```javascript
myField = { size : 10 }
myFiedl = { size : "8..20" }
```

## type

One of the most versatile validators. It can test if the value is of the following specific types:

* alpha
* array
* binary
* boolean
* component
* creditcard
* date
* email
* eurodate
* float
* GUID
* integer
* ipaddress
* json
* numeric
* query
* ssn
* string
* struct
* telephone
* url
* usdate
* UUID
* xml
* zipcode

```javascript
myField = { type : "float" }
myField = { type : "json" }
myField = { type : "xml" }
```

## udf

The field value, the target object, and an empty metadata structure will be passed to the declared closure/lambda to use for validation. The UDF must return **boolean**, `validate( value, target, metadata ):boolean`. NOTE: The target object passed in is actually an instance of "GenericObject", not a struct. To access the underlying struct, use the getMemento() function and perfom any comparisons on that. See the example below.

Any data you place in the `metadata` structure will be set in the validation result object for later retrieval.

```javascript
myField = { udf = function( value, target, metadata ) { return true; } }
myField = { udf = (value ,target, metadata ) => true }
myField = { udf = function( value, target, metadata ) { 
    metadata[ "customMessage" ] = "This is a custom error message from within the udf";
    return false; 
}
myField = { udf = function( value, target, metadata ) {
    var myData = target.getMemento();
    return myData["blah"] == something && value > someNumber;
}
```

## unique

The field must be a unique value in a specific database table. The validation data is a struct with the following keys:

* `table` : The name of the table to check
* `column` : The column to check, defaults to the property field in check

```javascript
myField = { unique = { table : "users", column : "username" } }
```

## validator

The field value will be passed to the validator CFC to be used for validation. Please see [Custom Validators](/v3.x-1/advanced/advanced-custom-validators)

```javascript
myField = { validator = "UniqueValidator@cborm" }
```


# Custom Message Replacements

We also setup lots of global `{Key}` replacements for your messages and also several that the core constraint validators offer as well. This is great for adding these customizations on your custom messages and also your i18n messages (Keep Reading):

## Global Replacements

* `{rejectedValue}` - The rejected value
* `{field or property}` - The property or field that was validated
* `{validationType}` - The name of the constraint validator
* `{validationData}` - The value of the constraint definition, e.g size=5..10, then this value is 5..10

## Validator Replacements

* `{DiscreteValidator}` - operation, operationValue
* `{InListValidator}` - inList
* `{MaxValidator}` - max
* `{MinValidator}` - min
* `{RangeValidator}` - range, min, max
* `{RegexValidator}` - regex
* `{SameAsValidator}`, `{SameAsNoCaseValidator}` - sameas
* `{SizeValidator}` - size, min, max
* `{TypeValidator}` - type

```javascript
username = { 
    required="true", 
    requiredMessage="Please enter the {field}", 
    size="6-8", 
    sizeMessage="The username must be between {min} and {max} characters" 
}
```


# Constraint Custom Messages

By default if a constraint fails an error message will be set in the result objects for you in English. If you would like to have your own custom messages for specific constraints you can do so by following the constraint message convention:

```javascript
{constraintName}Message = "My Custom Message";
```

Just add the name of the constraint you like and append to it the word Message and you are ready to roll:

```javascript
username = { 
    required="true", 
    requiredMessage="Please enter the username", 
    size="6-8", 
    sizeMessage="The username must be between 6 to 8 characters" 
}
```


# Nested Struct and Array Field Name Shortcuts

Defining nested struct or array item validation can create very nested code. cbvalidation allows for a shortcut to define these structures using a custom field name instead.

## Nested Struct Shorthand

For a nested struct, this is done by defining the field as a dot-delimited field name following the nested structure.

```cfscript
var validationResult = validate(
    target = {
        "address": {
            "streetOne" : "123 Elm Street",
            "streetTwo" : "",
            "city"      : "Anytown",
            "state"     : "IL",
            "zip"       : "60606"
        }
    },
    constraints = {
        "address": { "required": true, "type": "struct" },
        "address.streetOne": { "required": true, "type": "string" },
        "address.streetTwo": { "required": false, "type": "string" },
        "address.city": { "required": true, "type": "string" },
        "address.state": { "required": true, "type": "string", "size": 2 },
        "address.zip": { "required": true, "type": "numeric", "size": 5 }
    }
);
```

This can be continued as many levels deep as necessary.

```cfscript
var validationResult = validate(
    target = {
        "owner": {
            "firstName": "John",
            "lastName": "Doe",
            "address": {
                "streetOne" : "123 Elm Street",
                "streetTwo" : "",
                "city"      : "Anytown",
                "state"     : "IL",
                "zip"       : "60606"
            }
        }
    },
    constraints = {
        "owner.firstName": { "required": true, "type": "string" },
        "owner.lastName": { "required": true, "type": "string" },
        "owner.address.streetOne": { "required": true, "type": "string" },
        "owner.address.streetTwo": { "required": false, "type": "string" },
        "owner.address.city": { "required": true, "type": "string" },
        "owner.address.state": { "required": true, "type": "string", "size": 2 },
        "owner.address.zip": { "required": true, "type": "numeric", "size": 5 }
    }
);
```

## Nested Array Shorthand

For a nested array, this is done by defining the field as a dot-delimited field name following the nested structure using an asterisk (`*`) to represent the items of the array.

```cfscript
var validationResult = validate(
    target = {
        "luckyNumbers": [ 7, 11, 21 ]
    },
    constraints = {
        "luckyNumbers.*": { "type": "numeric" }
    }
);
```

The struct and array shorthand can be combined, as well.

```cfscript
var validationResult = validate(
    target = {
        "owner": {
            "firstName": "John",
            "lastName": "Doe",
            "addresses": [
                {
                    "streetOne" : "123 Elm Street",
                    "streetTwo" : "",
                    "city"      : "Anytown",
                    "state"     : "IL",
                    "zip"       : "60606"
                }
            ]
        }
    },
    constraints = {
        "owner.firstName": { "required": true, "type": "string" },
        "owner.lastName": { "required": true, "type": "string" },
        "owner.addresses.*.streetOne": { "required": true, "type": "string" },
        "owner.addresses.*.streetTwo": { "required": false, "type": "string" },
        "owner.addresses.*.city": { "required": true, "type": "string" },
        "owner.addresses.*.state": { "required": true, "type": "string", "size": 2 },
        "owner.addresses.*.zip": { "required": true, "type": "numeric", "size": 5 }
    }
);
```


# Validating Constraints

## Validation Methods: `validate(), validateOrFail()`

Most likely you will be validating your objects at the controller layer in your ColdBox event handlers. All event handlers, layouts, views and interceptors have some new methods thanks to our module mixins.

```javascript
/**
 * Validate an object or structure according to the constraints rules.
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return cbvalidation.model.result.IValidationResult
 */
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail()

/**
 * Retrieve the application's configured Validation Manager
 */
function getValidationManager()
```

You pass in your target object or structure, an optional list of fields or properties to validate only (by default it does all of them), and an optional constraints argument which can be the shared name or an actual constraints structure a-la-carte. If no constraints are passed, then we will look for the constraints in the target object as a public property called `constraints`. The `validate()` method returns a `cbvalidation.models.results.IValidationResult` type object, which you can then use for evaluating the validation.

{% hint style="info" %}
Please note that you can validate using a procedural approach or a functional approach by using our `onError() and onSuccess()` callback methods.
{% endhint %}

```javascript
// Validation using the results object procedurally
function saveUser( event, rc, prc ){
    // create and populate a user object from an incoming form
    var user = populateModel( entityNew("User") );
    // validate model and get validation results object
    prc.validationResults = validate( user );
    // check for errors
    if( prc.validationResults.hasErrors() ){
        messagebox.error( prc.validationResults.getAllErrors() );
        relocate( "users/editor" );
    }
    else{
        userService.save( user );
    }
}

// Validation using the results object functionally
function saveUser( event, rc, prc ){
    // create and populate a user object from an incoming form
    var user = populateModel( entityNew("User") );
    
    validate( user )
        .onError( function( results ){
            messagebox.error( results.getAllErrors() );
            relocate( "users/editor" );
        })
        .onSuccess( function( results ){
            userService.save( user );
        });
    
}

// Validation using Active Entity and validate or fail
function save( event, rc, prc ){
    userService
        .getOrFail( rc.id )
        .populate()
        .validateOrFail()
        .save();
}
```

## Validation Results

The return of the `validate()` method is our results object  `cbvalidation.models.result.ValidationResult` which has several methods that you can use to interact with the validation results.  Usually you woul use the `onError() and onSuccess()` callbacks to finalize the validation.

```javascript
/**
* Add errors into the result object
* @error The validation error to add into the results object
* @error_generic IValidationError
*
* @return IValidationResult
*/
any function addError(required error);

/**
* Set the validation target object name
* @return IValidationResult
*/
any function setTargetName(required string name);

/**
* Get the name of the target object that got validated
*/
string function getTargetName();

/**
* Get the validation locale
*/
string function getValidationLocale();

/**
* has locale information
*/
boolean function hasLocale();

/**
* Set the validation locale
*
* @return IValidationResult
*/
any function setLocale(required string locale);


/**
* Determine if the results had error or not
* @fieldThe field to count on (optional)
*/
boolean function hasErrors(string field);

/**
* Clear All errors
* @return IValidationResult
*/
any function clearErrors();


/**
* Get how many errors you have
* @fieldThe field to count on (optional)
*/
numeric function getErrorCount(string field);

/**
* Get the Errors Array, which is an array of error messages (strings)
* @fieldThe field to use to filter the error messages on (optional)
*/
array function getAllErrors(string field);

/**
* Get an error object for a specific field that failed. Throws exception if the field does not exist
* @fieldThe field to return error objects on
*
* @return IValidationError[]
*/
array function getFieldErrors(required string field);

/**
* Get a collection of metadata about the validation results
*/
struct function getResultMetadata();

/**
* Set a collection of metadata into the results object
*
* @return IValidationResult
*/
any function setResultMetadata(required struct data);

/**
* Call back that will be executed if the validation results had errors in them.
* The consumer receives the results instance: `(results) => {}, function( results ){}`
*
* @consumer Block to be executed if the result of the validation had errors.
*
* @return Same instance
*/
function onError( required consumer )

/**
* Call back that will be executed if the validation results had NO errors in them.
* The consumer receives the results instance: `(results) => {}, function( results ){}`
*
* @consumer Block to be executed if the result of the validation had NO errors.
*
* @return Same instance
*/
function onSuccess( required consumer )
```

## Validation Error Object

Some of these methods return error objects which adhere to our Error Interface: `cbvalidation.models.result.IValidationError`, which can quickly tell you what field had the exception, what was the rejected value and the validation message:

```javascript
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * The ColdBox validation error interface, all inspired by awesome Hyrule Validation Framework by Dan Vega
 */
import cbvalidation.models.result.*;
interface {

    /**
     * Set the error message
     * @messageThe error message
     */
    IValidationError function setMessage( required string message );

    /**
     * Set the field
     * @messageThe error message
     */
    IValidationError function setField( required string field );

    /**
     * Set the rejected value
     * @valueThe rejected value
     */
    IValidationError function setRejectedValue( required any value );

    /**
     * Set the validator type name that rejected
     * @validationTypeThe name of the rejected validator
     */
    IValidationError function setValidationType( required any validationType );

    /**
     * Get the error validation type
     */
    string function getValidationType();

    /**
     * Set the validator data
     * @dataThe data of the validator
     */
    IValidationError function setValidationData( required any data );

    /**
     * Get the error validation data
     */
    string function getValidationData();

    /**
     * Get the error message
     */
    string function getMessage();

    /**
     * Get the error field
     */
    string function getField();

    /**
     * Get the rejected value
     */
    any function getRejectedValue();

}
```


# Validating With Failures

In **cbValidation** 1.5 we introduced the `validateOrFail()` function.  This function works in similar manner to the `validate()` method, but instead of giving you the results object, it throws an exception of type `ValidationException`.

| Incoming Target | Validation Fails | Result                                                                              |
| --------------- | ---------------- | ----------------------------------------------------------------------------------- |
| Object          | false            | Returns the same object                                                             |
| Object          | true             | Throws `ValidationException`                                                        |
| Struct          | false            | Returns the structure with ONLY the fields that were validated from the constraints |
| Struct          | true             | Throws `ValidationException`                                                        |

## Exception Extended Info

So your validation fails, where are the results? In the exception structure under the `extendedInfo` key.  We store the validation results as JSON in the extended info and then you can use them for display purposes:

```javascript
try{
    validateOrFail( target );
    service.save( target );
} catch( ValidationException e  ){
    return {
        "error" : true,
        "validationErrors" : deserializeJSON( e.extendedInfo )
    };
}
```

&#x20;


# Validating with shared constraints

We also have the ability to validate a target object or form with shared constraints from our configuration file. Just use the name of the key in the configuration form as the name of the `constraints` argument.

```javascript
    // validate user object
    prc.results = validateModel( target=user, constraints="sharedUser" );

    // validate incoming form elements in the RC or request collection
    prc.results = validateModel( target=rc, constraints="sharedUser" );
```

This will validate the object and `rc` using the `sharedUser` constraints defined in the [configuration file:](/v3.x-1/overview/declaring-constraints/configuration-file#declaration) `config/Coldbox.cfc`


# Validating with a-la-carte constraints

&#x20;We also have the ability to validate a target object with custom a-la-carte constraints by passing the constraints inline as an struct of structs. This way you can store these constraint rules anywhere you like.

```javascript
var myConstraints = {
	login = { required=true, size=6..10 }, 
	password = { required=true, size=6..10 }
};
prc.results = validateModel( target=user, constraints=myConstraints );
```

&#x20;This will validate the object using the inline constraints that you built.


# Validating Custom Fields

You can also tell the validation manager to **ONLY** validate on certain fields and not all the fields declared in the validation constraints.

```javascript
prc.results = validateModel( target=user, fields="login,password" );
```

This will only validate the `login` and `password` fields.

## Custom Includes/Excludes

You can also use the following arguments:

* `includeFields` : The fields to include in the validation ONLY
* `excludeFields` : The fields to exclude in the validation

```javascript
prc.results = validateModel( 
    target=user, 
    includeFields="username,password", 
    excludeFields="id" 
);
```


# Validating With Profiles

cbValidation 2.x series introduced the ability to validate using field `profiles`.  This will allow you to define all your constraints but also define field profiles where you can define only certain fields to be validated if the profile name is used. &#x20;

## Defining Profiles

This is using the `this.constraintProfiles` struct literal:

```javascript
this.constraintProfiles = {
	"new" = "fname,lname,email,password",
	"update" = "fname,lname,email",
	"passUpdate" = "password,confirmpassword"
}
```

The **key** is the **name** of the profile and the **value** is a list of the fields to validate if the profile is targeted for validation.

## Validating Profiles

Every validation method: `validate(), validateOrFail()` has a `profiles` argument. You can then pass one or more to the argument so you can validate 1 or more profiles:

```javascript
var results = validateModel( target=model, profiles="update" )
var results = validateModel( target=model, profiles="update,passUpdate" )
```


# Displaying Errors

After validation you can use the same results object and use it to display the validation errors in your client side:

## Handlers:

```javascript
// store the validation results in the request collection
prc.validationResults = validate( obj );
```

## Views:

```markup
<-- Display all errors as a message box --->
#getInstance( "MessageBox@cbMessagebox" )
    .renderMessage( type="error", messageArray=prc.validationResults.getAllErrors() )#
```

If you want more control you can use the `hasErrors()` and iterate over the errors to display:

```javascript
<cfif prc.validationResults.hasErrors()>
    <ul>
    <cfloop array="#prc.validationResults.getErrors()#" index="thisError">
        <li>#thisError.getMessage()#</li>
    </cfloop>
    </ul>
</cfif>
```

You can even use the results object in your views to get specific field errors, message, etc.

## Functional Approach

You can also use the callbacks `onError() and onSuccess` to finalize the validation.  These are very common when using non only html apps but api apps.

```javascript
any function saveShared( event, rc, prc ){
		// validation
		validate(
			target      = rc,
			constraints = "sharedUser"
		).onError( function( results ){
			flash.put(
				"notice",
				results.getAllErrors().tostring()
			);
			return index( event, rc, prc );
		})
		.onSuccess( function( results ){
			flash.put( "User info validated!" );
			relocate( "main" );
		} );
	}
```

## Common Methods

The following are some common methods from the validation result object for dealing with errors:

* `getResultMetadata()`
* `getFieldErrors( [field] )`
* `getAllErrors( [field] )`
* `getAllErrorsAsJSON( [field] )`
* `getAllErrorsAsStruct( [field] )`
* `getErrorCount( [field] )`
* `hasErrors( [field] )`
* `getErrors()`
* `onError( consumer )`
* `onSuccess( consumer )`

The API Docs in the module (once installed) will give you the latest information about these methods and arguments.


# WireBox Integration

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`, which is the one you can inject and use anywhere you like.

```javascript
// get reference
property name="validationManager" inject="ValidationManager@cbvalidation";
```

{% hint style="info" %}
Remember you have the mixins available to you in your handlers/interceptors/layouts and views
{% endhint %}


# Custom Validators

If the core validators are not sufficient for you, then you can create your own custom validators. You can either leverage the `udf` validator and create your own closure/lambda to validate inline or create a reusable validator CFC

## Closure/Lambda Validator

If you use the `udf` validator, then you can declare your validation inline. Just create a closure/lambda that will be called for you at the time of validation. This closure/lambda will receive all the following arguments and MUST return a boolean indicator: **true** => passed, **false** => invalid

* `value` : The value to validate, can be null
* `target` : The object that is the target of validation

```javascript
slug : { 
    required : true, 
    udf : ( value, target ) => {
        if( isNull( arguments.value ) ) return false;
        return qb.from( "content" )
            .where( "slug", arguments.value )
            .when( this.isLoaded(), ( q ) => {
                arguments.q.whereNotIn( "id", this.getId() );
            } )
            .count() == 0;
    }
},
```

## Custom CFC Validator

You can also create a reusable CFC that can be shared in any ColdBox app as a validator. Create the CFC and it should implement our interface which can be found here: `cbvalidation.models.validators.IValidator` and it specifies just two functions your own validator must implement: `getName(), validate():`

{% code title="cbvalidation.models.validators.IValidator" %}

```java
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * The ColdBox validator interface, all inspired by awesome Hyrule Validation Framework by Dan Vega
 */
interface {

    /**
     * Will check if an incoming value validates
     * @validationResultThe result object of the validation
     * @targetThe target object to validate on
     * @fieldThe field on the target object to validate on
     * @targetValueThe target value to validate
     * @rules The rules imposed on the currently validating field
     */
    boolean function validate(
        required any validationResult,
        required any target,
        required string field,
        any targetValue,
        any validationData,
        struct rules
    );

    /**
     * Get the name of the validator
     */
    string function getName();

}
```

{% endcode %}

Here is a sample validator:

```javascript
/**
 * Copyright since 2020 by Ortus Solutions, Corp
 * www.ortussolutions.com
 * ---
 * This validator validates if a value is is less than a maximum number
 */
component accessors="true" singleton {

    property name="name";

    /**
     * Constructor
     */
    MaxValidator function init(){
        variables.name = "Max";
        return this;
    }

    /**
     * Will check if an incoming value validates
     * @validationResultThe result object of the validation
     * @targetThe target object to validate on
     * @fieldThe field on the target object to validate on
     * @targetValueThe target value to validate
     * @validationDataThe validation data the validator was created with
     */
    boolean function validate(
        required any validationResult,
        required any target,
        required string field,
        any targetValue,
        any validationData,
        struct rules
    ){
        // return true if no data to check, type needs a data element to be checked.
        if ( isNull( arguments.targetValue ) || ( isSimpleValue( arguments.targetValue ) && !len( arguments.targetValue ) ) ) {
            return true;
        }

        // Max Tests
        if ( arguments.targetValue <= arguments.validationData ) {
            return true;
        }

        var args = {
            message        : "The '#arguments.field#' value is not less than or equal to #arguments.validationData#",
            field          : arguments.field,
            validationType : getName(),
            rejectedValue  : ( isSimpleValue( arguments.targetValue ) ? arguments.targetValue : "" ),
            validationData : arguments.validationData
        };
        var error = validationResult.newError( argumentCollection = args ).setErrorMetadata( { max : arguments.validationData } );
        validationResult.addError( error );
        return false;
    }

    /**
     * Get the name of the validator
     */
    string function getName(){
        return variables.name;
    }

}
```

## Defining Custom Validators

You can use them in two approaches when defining them in your constraints:

1. Use the `validator` constraints which points to the Wirebox ID of your own custom validator object. Please note that if you use this approach you will not be able to pass validation data into the validator.
2. Use the WireBox ID as they key of your validator. Then you can pass your own validation data into the validator.

{% hint style="success" %}
Approach number 2 is much more flexible as it will allow you to declare multiple custom validators and each of those validators can receive validation data as well.
{% endhint %}

```javascript
//sample custom validator constraints
    this.constraints = {
        // Approach #1
        myField = {
            required : true, 
            validator : "MyCustomID" 
        },

        // Approach #2
        myField2 = {
            required : true, 
            UniqueInMyDatabase : {
                column : "column_name",
                table : "table_name",
                dsn : "myDatasource"
            },
            MyTimezoneValidator : true
        }
     };
```

{% hint style="success" %}
If you don't have any validation data to pass to a validator, just pass an empty struct (`{}`) or an empty string
{% endhint %}


# Unique ORM Validator

## Usage

The `unique` validator is part of the [cborm](https://github.com/coldbox/cbox-cborm) module. So make sure that the `cborm` module is installed first.

```bash
box install cborm
```

## Declaring the Constraint

The validator is mapped into WireBox as `UniqueValidator@cborm` so you can use in your constraints like so:

```javascript
{ 
    fieldName : { validator: "UniqueValidator@cborm" },
    // or
    fieldName : { "UniqueValidator@cborm" : {}  }
}
```

## Case Sensitivity

If you will be using this validator, then the name of the property has to be **EXACTLY** the same case as the constraint name. To do this, use single or double quotes to declare the constraint name. Please see example below.

```javascript
this.constraints = {
  "username" = { required=true, validator: "UniqueValidator@cborm" },
  "email" = { required=true, validator: "UniqueValidator@cborm" }
};
```

{% hint style="info" %}
This is done because we build the appropriate SQL to make sure the property name and the field name match.
{% endhint %}


# i18n Integration

## Internationalization

If you are using i18n (Internationalization and Localization) in your ColdBox applications you can also localize your validation error messages from the ColdBox validators.

{% hint style="info" %}
&#x20;**Info** You do not need to install the `cbi18n` module. This module is already a dependency of the `cbvalidation` module.
{% endhint %}

&#x20;You will do this by our lovely conventions for you resource bundle keys:

### &#x20;Objects:

```
{ObjectName}.{Field}.{ConstraintType}}=Message
```

### &#x20;Forms with Shared Constraints Name

```
{SharedConstraintName}.{Field}.{ConstraintType}=Message
```

### &#x20;Forms with No Shared Constraints

```
GenericForm.{Field}.{ConstraintType}=Message
```

### Key Replacements

We also setup lots of global `{Key}` replacements for your messages and also several that the core constraint validators offer as well:

#### Global Replacements

* `{rejectedValue}` - The rejected value
* `{field}` or property - The property or field that was validated
* `{validationType}` - The name of the constraint validator
* `{validationData}` - The value of the constraint definition, e.g size=5..10, then this value is 5..10
* `{targetName}` - The name of the user, shared constraint or form

#### i18n Validator Replacements

* `{DiscreteValidator}` - operation, operationValue
* `{InListValidator}` - inList
* `{MaxValidator}` - max
* `{MinValidator}` - min
* `{RangeValidator}` - range, min, max
* `{RegexValidator}` - regex
* `{SameAsValidator}`, `{SameAsNoCaseValidator}` - SameAs
* `{SizeValidator}` - size, min, max
* `{TypeValidator}` - type

#### **Examples**

```
blank=The field {property} must contain a value.
email=The field {property} is not a valid email address.
unique=The field {property} is not a unique value.
size=The field {property} was not in the size range of {size}.
inlist=The field {property} was not in the list of possible values.
validator=There was a problem with {property}.
min=The minimum value {min} was not met for the field {property}.
max=The maximum value {max} was exceeded for the field {property}.
range=The range was not met for the field {property}.
matches=The field {property} does not match {regex}.
numeric=The field {property} is not a valid number.
```

{% hint style="info" %}
Please note that since version 3.x of cbvalidation you can use json resource bundles thanks to cbi18n v2.x
{% endhint %}


# Custom Validation Managers

If you would like to adapt your own validation engines to work with ANY ColdBox application you can do this by implementing the following interfaces:

* Validation Manager : Implement the `cbvalidation.models.IValidationManager`. Then use the class path in your configuration file so it uses your validation manager instead of ours.
* Validation Results : Implement the `cbvalidation.models.result.IValidationResult`, which makes it possible for any ColdBox application to use your validation results.
* Validation Error : Implement the `cbvalidation.models.result.IValidationError`, which makes it possible for any ColdBox application to use your validation error representations.

Then map it in your configuration file:

{% code title="config/Coldbox.cfc" %}

```javascript
validation = {
    // The third-party validation manager to use, by default it uses CBValidation.
    manager = "my.class.path"
}
```

{% endcode %}

|   |
| - |


# Introduction

cbValidation is the server-side validation engine for ColdBox applications

CBValidation is the server-side validation engine that provides a unified approach to object, struct, and form validation for ColdBox applications. Built with flexibility and performance in mind, it allows you to construct declarative validation constraint rules and validate them with ease. Whether you're validating API requests, form submissions, or domain objects, CBValidation gives you the tools to ensure data integrity across your entire application.

The validation engine is based on **constraint-driven validation** where you declaratively specify validation rules for properties or fields. These constraints can live directly in your domain objects, be defined as shared constraints in your ColdBox configuration, or created dynamically on-the-fly for maximum flexibility.

### Quick Example 🚀

Here's a taste of CBValidation's power with a simple user registration example:

```js
property name="firstName";
property name="lastName";
property name="email";
property name="password";
property name="age" type="numeric";

// Define validation constraints directly in your model
this.constraints = {
    firstName: {
        required: true,
        size: "2..50",
        requiredMessage: "Please enter your first name"
    },
    lastName: {
        required: true,
        size: "2..50",
        requiredMessage: "Please enter your last name"
    },
    email: {
        required: true,
        type: "email",
        typeMessage: "Please enter a valid email address"
    },
    password: {
        required: true,
        size: "8..128",
        sizeMessage: "Password must be at least 8 characters long"
    },
    age: {
        required: true,
        type: "numeric",
        range: "13..120",
        rangeMessage: "Age must be between 13 and 120"
    }
}
```

Now the validation:

```java
function register( event, rc, prc ) {
    validate( populate( "User" ) )
        .onError( results => {
            flash.put( "errors", results.getAllErrors() );
            relocate( "users/editor" );
        })
        .onSuccess( results => {
            userService.save( user );
            flash.put( "success", "Registration successful!" );
            relocate( "users/welcome" );
        });
}
```

With just two simple validation methods - `validate()` and `validateOrFail()` - you get comprehensive validation with detailed error reporting, custom messages, and seamless integration with your ColdBox application.

### Features ✨

#### 🎯 **Flexible Constraint Definition**

* **Domain Object Constraints** - Define validation rules directly in your models for encapsulated validation logic
* **Shared Constraints** - Reusable validation rules stored in your ColdBox configuration
* **A-la-carte Constraints** - Dynamic validation rules created on-the-fly for specific scenarios
* **External Constraints** - Load validation rules from databases, JSON files, or services

#### 🔧 **Powerful Validation Rules**

* **30+ Built-in Validators** - Required, email, size, range, regex, date comparisons, and more
* **Custom Validators** - Create your own validation rules with full framework integration
* **Nested Object Support** - Validate complex data structures with dot notation (`user.address.street`)
* **Array Validation** - Validate arrays and array items with wildcard notation (`items.*.price`)
* **Conditional Validation** - Rules like `requiredIf`, `requiredUnless` for dynamic requirements

#### 🎨 **User Experience Features**

* **Custom Error Messages** - Personalized, user-friendly validation messages
* **Message Replacement Variables** - Dynamic messages with context like `{min}`, `{max}`, `{rejectedValue}`
* **Internationalization (i18n)** - Multi-language validation messages through cbi18n integration
* **Constraint Profiles** - Validate specific field groups for different scenarios (registration, update, etc.)

#### 🚀 **Developer Experience**

* **Two Simple Methods** - `validate()` for result objects, `validateOrFail()` for exception-based validation
* **Rich Error Information** - Detailed validation results with field names, messages, and metadata
* **Exception Integration** - Automatic ValidationException throwing with JSON error details
* **Mixin Integration** - Validation methods available globally in handlers, views, layouts, and interceptors

#### 🔄 **Advanced Features**

* **Method/UDF Validation** - Call custom validation methods with error metadata support
* **Database Unique Constraints** - Built-in unique field validation against database tables
* **Null Value Handling** - Intelligent handling of null, empty, and undefined values
* **WireBox Integration** - Full dependency injection support for custom validators
* **Performance Optimized** - Efficient constraint processing and validator caching

#### 🛡️ **Enterprise Ready**

* **Production Tested** - Battle-tested in countless ColdBox applications
* **Comprehensive Documentation** - Detailed guides, examples, and best practices
* **Professional Support** - Backed by Ortus Solutions with commercial support options
* **BoxLang Compatible** - Full support for both CFML and BoxLang platforms

### Professional Open Source

![Ortus Solutions, Corp](/files/-LWbz0FwX9mtBeSrsDFI)

CBValidation is professional open-source software backed by [Ortus Solutions, Corp](https://www.ortussolutions.com/) offering services like:

* Custom Development
* Professional Support & Mentoring
* Training
* Server Tuning
* Security Hardening
* Code Reviews
* [Much More](https://www.ortussolutions.com/)

### Resources & Community

* Source: <https://github.com/coldbox-modules/cbvalidation>
* Issues: <https://github.com/coldbox-modules/cbvalidation/issues>
* Official Site: <https://www.coldbox.org>
* BoxLang Site: <https://boxlang.io>
* Video Training:
  * <https://www.cfcasts.com>
  * <https://learn.boxlang.io>
  * <https://youtube.com/c/OrtusSolutions>
* Comunity: <https://community.ortussolutions.com/>
* Slack: <https://boxteam.ortussolutions.com>

### HONOR GOES TO GOD ABOVE ALL

Because of His grace, this project exists. If you don't like this, then don't read it, it's not for you.

> "Therefore being justified by **faith**, we have peace with God through our Lord Jesus Christ: By whom also we have access by **faith** into this **grace** wherein we stand, and rejoice in hope of the glory of God." Romans 5:5


# Release History

This section contains the release history for CBValidation module.

In this section you will find the release notes for each version we release under this major version. If you are looking for the release notes of previous major versions use the version switcher at the top left of this documentation book. Here is a breakdown of our major version releases.

## 4.x

A major version leaving behind old engine support and including several new validators and new ColdBox 7 integrations.

## 3.x

Upgraded to leverage the new cbi18n v2.x module. New CFML engine compatibilities and moving to modern land!

## 2.x

Complete rewrite to script and include tons of new validations, rules, and conventions. It also ended the era of ACF11 and Lucee 4.5 support.

## 1.x

Initial awesome release!


# What's New With 4.8.0

Unreleased

This is the next development release focusing on improved null value handling in validation filtering.

## Fixed

* Null values are now properly filtered out when `validateOrFail` returns validated struct/array results
* Handle null values correctly when filtering constraints in nested structures and arrays

## Added

* Copilot instructions for better IDE integration
* GitHub Actions workflow improvements

## Coming Soon

Additional enhancements and bug fixes are in development. Check back soon for updates!

See Development Branch: <https://github.com/coldbox-modules/cbvalidation>


# What's New With 4.7.0

October 13, 2025

This release enhances the `validateOrFail()` method to provide better filtering of nested structures and arrays, ensuring that only validated fields are returned in the result.

## Changed

* `validateOrFail` now filters nested structs and arrays to only return keys matching constraints, not just top-level keys ([PR #85](https://github.com/coldbox-modules/cbvalidation/pull/85))

See Release Notes on Github: <https://github.com/coldbox-modules/cbvalidation/releases/tag/v4.7.0>


# What's New With 4.6.0

September 18, 2025

This release includes important bug fixes and adds support for the latest CFML engine versions.

## Fixed

* Fix for cases where a non-empty value wasn't passing an `empty: false` validation check

## Added

* GitHub Actions update
* BoxLang PRIME support
* Adobe 2025 support

See Release Notes on Github: <https://github.com/coldbox-modules/cbvalidation/releases/tag/v4.6.0>


# What's New With 4.5.0

February 19, 2025

This release adds new features for applying default values to validated objects and expands platform support.

## Removed

* `eurodate` validator has been removed. It doesn't work consistently across ACF/Lucee as they use different standards. Users can now validate dates as they see fit for their specific use case.

## Added

* **BoxLang certification** - cbValidation is now certified to work with BoxLang
* **Lucee 6 support** - Testing and support for Lucee 6.x
* **Adobe 2023 support** - Testing and support for Adobe ColdFusion 2023
* **`defaultValue` constraint** - Apply default values to fields before constraints are checked, useful for initializing optional fields with sensible defaults

See Release Notes on Github: <https://github.com/coldbox-modules/cbvalidation/releases/tag/v4.5.0>


# What's New With 4.4.0

October 16, 2023

### Added

* requiredIf accepts a UDF and closure now

### Breaking

* UDF validator now treats null and empty values as valid


# What's New With 4.3.1

June 15, 2023

### Fixed

* Only perform type evaluation if target value is not null or empty string #75


# What's New With 4.3.0

May 5, 2023

This release focused on validator enhancements and improved error handling for UDF and Method validators.

## Added

* Allow UDF and Method Validators to Utilize Error Metadata by @homestar9 ([#48](https://github.com/coldbox-modules/cbvalidation/pull/48))

## Fixed

* Date Comparisons Fail if Compare field is empty ([#58](https://github.com/coldbox-modules/cbvalidation/pull/58)) thanks to @nockhigan

See Release Notes on Github: <https://github.com/coldbox-modules/cbvalidation/releases/tag/v4.3.0>


# What's New With 4.2.0

April 14, 2023

### Added

* New github action versions and consolidation of actions
* New [Contributing](https://github.com/coldbox-modules/cbvalidation/blob/v4.2.0/CONTRIBUTING.md) guidelines
* New github support templates

### Changed

* The way custom validators are retrieved so they are ColdBox 7+ compatible
* `pr` github action now just does format checks to avoid issues with other repos.
* Consolidated Adobe 2021 scripts into the server scripts

### Fixed

* Fix for `tasks.json` file to include no recursion
* [#71](https://github.com/coldbox-modules/cbvalidation/issues/71) - ValidationManager errors when returning `validatedKeys` due to `sharedconstraint` name
* [#45](https://github.com/coldbox-modules/cbvalidation/issues/45) - `Type` validator needs to be able to validate against `any` type even if that is an empty string


# What's New With 4.1.0

November 15, 2022

This is a minor release that includes new validators and also integration with ColdBox 7 delegates.  This will now allow objects to have validatable traits:

```javascript
component name="User" delegates="Validatable@cbValidation"{

}
```

This will give the target object the delegates methods available to it.

### Added

* New ColdBox 7 delegate: `Validatable@cbValidation` which can be used to make objects validatable
* New validators: `notSameAs, notSameAsNoCase`

### Changed

* All date comparison validators now validate as `false` when the comparison target dates values are NOT dates instead of throwing an exception.


# What's New With 4.0.0

October 10, 2022

This is a major release as we have updated all the internal libraries and have dropped off Adobe 2016 support.  Here are the release notes:

### Added

* Major bump of all dependencies
* New `InstanceOf` validator thanks to @homestar9 : <https://github.com/coldbox-modules/cbvalidation/pull/65>
* New virtual app testing and tuning

### Fixed

* Fix process result metadata replacements <https://github.com/coldbox-modules/cbvalidation/pull/64/files> thanks to @alessio-de-padova, when using full null support

### Changed

* Dropped ACF2016


# About This Book

Information about the cbValidation documentation book, contribution guidelines, and copyright.

The source code for this book is hosted in GitHub: <https://github.com/ortus-docs/cbvalidation-docs>. You can freely contribute to it and submit pull requests. The contents of this book is copyrighted by [Ortus Solutions, Corp](http://www.ortussolutions.com) and cannot be altered or reproduced without the author's consent. All content is provided *"As-Is"* and can be freely distributed.

* The majority of code examples in this book are done in `cfscript`.
* The majority of code generation and running of examples are done via **CommandBox**: The ColdFusion (CFML) CLI, Package Manager, REPL - <https://www.ortussolutions.com/products/commandbox>

## External Trademarks & Copyrights

Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.

## Notice of Liability

The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software, and resources described in it.

## Contributing

We highly encourage contributions to this book and our open-source software. The source code for this book can be found in our [GitHub repository](https://github.com/ortus-docs/cbvalidation-docs) where you can submit pull requests.

## Charitable Proceeds

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - <https://www.harvesting.org/>. So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

### Shalom Children's Home

**Shalom Children’s Home** is one of the ministries that are dear to our hearts located in El Salvador. During the 12-year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education, and life skills training in a Christian environment. The home is supported by a child sponsorship program.

We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador who either have no families or have been abandoned. This is a good earth to seed and plant.


# Author

Information about the authors of the cbValidation module.

## Luis Fernando Majano Lainez

![](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-LA-UVvG0NM7NpDzssBL%2F-Lk6BFGIHo1oV7R83_YL%2F-Lk6D1zW4YSdITH86ZYX%2FLuis%20F%20Majano.jpg?alt=media\&token=3106d0c5-15df-4fbe-ae5c-1bedd9a9363c)

Luis Majano is a Computer Engineer that has been developing and designing software systems since the year 2000. He was born in [San Salvador, El Salvador](http://en.wikipedia.org/wiki/El_Salvador) in the late 70’s, during a period of economical instability and civil war. He lived in El Salvador until 1995 and then moved to Miami, Florida where he completed his Bachelors of Science in Computer Engineering at [Florida International University](http://fiu.edu). Luis resides in Houston, Texas with his beautiful wife Veronica, baby girl Alexia and baby boy Lucas!

He is the CEO of [Ortus Solutions](http://www.ortussolutions.com), a consulting firm specializing in web development, ColdFusion (CFML), Java development and all open source professional services under the ColdBox and ContentBox stack. He is the creator of ColdBox, ContentBox, WireBox, MockBox, LogBox and anything “BOX”, and contributes to many open source ColdFusion/Java projects. You can read his blog at [www.luismajano.com](http://www.luismajano.com)

Luis has a passion for Jesus, tennis, golf, volleyball and anything electronic. Random Author Facts:

* He played volleyball in the Salvadorean National Team at the tender age of 17
* The Lord of the Rings and The Hobbit is something he reads every 5 years. (Geek!)
* His first ever computer was a Texas Instrument TI-86 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)
* He has a geek love for circuits, microcontrollers and overall embedded systems.
* He has of late (during old age) become a fan of organic gardening.

> Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!
>
> “Trust in the LORD with all your heart, and do not lean on your own understanding.”\
> Proverbs 3:5

## Contributors

### Will de Bruin


# Installation

Get CBValidation installed in your ColdBox application and configure it for validation workflows.

## Instructions

Leverage [CommandBox](https://www.ortussolutions.com/products/commandbox) to install via your CLI

```bash
box install cbvalidation
```

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`. It will also register several helper methods that can be used throughout the ColdBox application.

## System Requirements

* BoxLang 1+ (Preferred)
* Lucee 5+
* ColdFusion 2023+

## Mixins - Helper Methods

The module will also register the following methods in your handlers/interceptors/layouts/views

* `validate()`
* `validateOrFail()`
* `getValidationManager()`
* `validatehasValue()`
* `validateIsNullOrEmpty()`
* `assert()`

```javascript
/**
 * Validate an object or structure according to the constraints rules.
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return cbvalidation.model.result.IValidationResult
 */
function validate()

/**
 * Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
 * The validation errors will be contained in the `extendedInfo` of the exception in JSON format
 *
 * @target An object or structure to validate
 * @fields The fields to validate on the target. By default, it validates on all fields
 * @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
 * @locale The i18n locale to use for validation messages
 * @excludeFields The fields to exclude from the validation
 * @includeFields The fields to include in the validation
 * @profiles If passed, a list of profile names to use for validation constraints
 *
 * @return The validated object or the structure fields that where validated
 * @throws ValidationException
 */
function validateOrFail()

/**
 * Retrieve the application's configured Validation Manager
 */
function getValidationManager()

/**
 * Verify if the target value has a value
 * Checks for nullness or for length if it's a simple value, array, query, struct or object.
 */
boolean function validateHasValue( any targetValue )

/**
 * Check if a value is null or is a simple value and it's empty
 *
 * @targetValue the value to check for nullness/emptyness
 */
boolean function validateIsNullOrEmpty( any targetValue )

/**
 * This method mimics the Java assert() function, where it evaluates the target to a boolean value and it must be true
 * to pass and return a true to you, or throw an `AssertException`
 *
 * @target The tareget to evaluate for being true
 * @message The message to send in the exception
 *
 * @throws AssertException if the target is a false or null value
 * @return True, if the target is a non-null value. If false, then it will throw the `AssertError` exception
 */
boolean function assert( target, message="" )
```

## Delegate Mode

If you are using ColdBox 7, then you can use the `Validatable@cbValidation` delegate. Which will allow you to add these validation traits to any object you desire.

```javascript
// BoxLang Syntax
@delegates( "Validatable@cbValidation" )
class{}

// CFML Syntax
component delegates="Validatable@cbValidation"{}
```

The methods delegated by default are the following:

* `assert()`
* `getValidationManager()`
* `getValidationResults()`
* `isValid()`
* `validate()`
* `validateHasValue()`
* `validateIsNullOrEmpty()`
* `validateOrFail()`

You can also use the delegation for only certain methods if needed:

```javascript
// BoxLang Short Syntax
@delegates( "Validatable@cbValidation=validate,validateOrFail" )
class{}

// BoxLang Long Syntax via delegate injection
class{

    @inject( "Validatable@cbValidation" )
    @delegate( "validate,validateOrFail" )
    property name="validatable";

}

// ----------------------------------------------------------------

// CFML Short Syntax
component delegates="Validatable@cbValidation=validate,validateOrFail"{}

// Long Syntax via delegate injection
component{

  property name="validatable"
        inject="Validatable@cbValidation"
        delegate="validate,validateOrFail"

}
```

## WireBox Integration

The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`, which is the one you can inject and use anywhere you like.

```javascript
// get reference
property name="validationManager" inject="ValidationManager@cbvalidation";
```

{% hint style="danger" %}
Remember, you have the mixins available to you in your handlers/interceptors/layouts and views and the `Validatable@cbValidation` delegate for any model object.
{% endhint %}


# Configuration

Configuration options for CBValidation module.

### Settings

You can configure the module by creating a `cbvalidation` key in the `config/Coldbox.cfc` `moduleSettings` structure

{% code title="config/Coldbox.bx|cfc" %}

```javascript
moduleSettings = {
    cbValidation = {
        // The third-party validation manager to use, by default it uses CBValidation.
        manager = "class path",
        // You can store global constraint rules here with unique names
        sharedConstraints = {
            name = {
                field = { constraints here }
            }
        }

    }
}
```

{% endcode %}

#### manager

The `manager` key by default points to `cbValidation.models.ValidationManager`. If you would like to override or decorate our manager, then you can set the classpath of the manager to use. This manager must adhere to our interface: `cbvalidation.interfaces.IValidationManager`

#### sharedConstraints

This structure will hold all of your shared constraints for forms or/and objects that you can easily reference by name. It's like declaring the constraints inline but storing them globally.

{% hint style="danger" %}
**Important:** The module will register several objects into WireBox using the `@cbvalidation` namespace. The validation manager is registered as `ValidationManager@cbvalidation`
{% endhint %}


# Available Constraints

Below are all the currently supported constraints. If you need more you can create your own [Custom validators](/advanced/advanced-custom-validators) as well.

```javascript
propertyName = {
        // The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
        accepted : any value

        // The field under validation must be a date after the set targetDate
        after : targetDate

        // The field under validation must be a date after or equal the set targetDate
        afterOrEqual : targetDate

        // The field must be alpha ONLY
        alpha : any value

        // The field under validation is an array and all items must pass this validation as well
        arrayItem : {
            // All the constraints to validate the items with
        }

        // The field under validation must be a date before the set targetDate
        before : targetDate

        // The field under validation must be a date before or equal the set targetDate
        beforeOrEqual : targetDate

        // The field under validation is a struct and all nested validation rules must pass
        constraints: {
           // All the constraints for the nested struct
        }

        // The field under validation must be a date that is equal the set targetDate
        dateEquals : targetDate

        // discrete math modifiers
        discrete : (gt,gte,lt,lte,eq,neq):value

        // the field must or must not be an empty value
        // needed because `required` counts empty strings as valid
        // and `type` ignores empty strings as "not required"
        empty : boolean [false]

        // value in list
        inList : list

        // Verify the instance of the target
        InstanceOf : "instance.path"

        // An alias for arrayItem
        items : {
            // All the constraints to validate the items with
        }

        // max value
        max : value

        // Validation method to use in the target object must return boolean accept the incoming value and target object
        method : methodName

        // min value
        min : value

        // An alias for constraints
        nestedConstraints: {
           // All the constraints for the nested struct
        }

        // not same as but with no case
        notSameAsNoCase : propertyName

        // not same as another property
        notSameAs : propertyName

        // range is a range of values the property value should exist in
        range : eg: 1..10 or 5..-5

        // regex validation
        regex : valid no case regex

        // required field or not, includes null values
        required : boolean [false]

        // The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`.
        requiredIf : {
            anotherfield:value, anotherfield:value
        }

        // The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed
        requiredUnless : {
            anotherfield:value, anotherfield:value
        }

        // same as but with no case
        sameAsNoCase : propertyName

        // same as another property
        sameAs : propertyName

        // size or length of the value which can be a (struct,string,array,query)
        size  : numeric or range, eg: 10 or 6..8

        // specific type constraint, one in the list.
        type  : (alpha,array,binary,boolean,component,creditcard,date,email,float,GUID,integer,ipaddress,json,numeric,query,ssn,string,struct,telephone,url,usdate,UUID,xml,zipcode),

        // UDF to use for validation, must return boolean accept the incoming value and target object, validate(value,target,metadata):boolean
        udf = variables.UDF or this.UDF or a closure.

        // Check if a column is unique in the database
        unique = {
            table : The table name,
            column : The column to check, defaults to the property field in check
        }

        // Custom validator, must implement coldbox.system.validation.validators.IValidator
        validator : path or wirebox id, example: 'mypath.MyValidator' or 'id:MyValidator'
}
```

## accepted

The field must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance. *Note: This validator will ignore values that are null or empty strings.*

```javascript
terms = { accepted : true }
```

**Common Use Cases:**

* Terms of service and privacy policy acceptance
* Newsletter subscription opt-ins
* Age verification checkboxes
* Legal disclaimer acknowledgments
* Cookie consent confirmations

## after

The field under validation must be a value after a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested. *Note: This validator will ignore values that are null or empty strings.*

```javascript
startDate : { required:true, type:"date", after: dateAdd( "d", 1, now() ) }
```

Instead of passing a date, you may specify another field to compare against the date as well:

```javascript
endDate : { required:true, type:"date", after: "startDate" }
```

**Common Use Cases:**

* Event end dates must be after start dates
* Subscription expiration dates after purchase dates
* Delivery dates after order dates
* Meeting end times after start times
* Contract termination dates after effective dates

## afterOrEqual

The field under validation must be a value after or equal a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested. *Note: This validator will ignore values that are null or empty strings.*

```javascript
startDate : { required:true, type:"date", afterOrEqual: dateAdd( "d", 1, now() ) }
```

## alpha

The field must be alphabetical ONLY. *Note: This validator will ignore values that are null or empty strings.*

```javascript
firstName = { alpha = true }
```

**Common Use Cases:**

* First and last names (no numbers or special characters)
* Department or division names
* Country and city names
* Product category names
* Language or locale identifiers

## arrayItem

This validator is used to validate an array's items. It will iterate through each of the array's items and validate each item against the `validationData` constraints you pass in. *Note: This validator will ignore values that are null or empty strings.*

```javascript
luckyNumbers = {
    required : true,
    type : "array",
    arrayItem : {
        required : true,
        type : "numeric"
    }
}
```

You may also specify `items` as an alias to `arrayItem`.

```javascript
luckyNumbers = {
    required : true,
    type : "array",
    items : {
        required : true,
        type : "numeric"
    }
}
```

Any validation errors found will be named using the parent field name and array index.

```javascript
var validationResult = validate(
    target = {
        "luckyNumbers": [ 7, 11, "not a number", 21 ]
    },
    constraints = {
        required : true,
        type : "array",
        items : {
            required : true,
            type : "numeric"
        }
    }
);
```

```json
// validationResult.getAllErrorsAsJson()
{
    "luckyNumbers[3]": ["The 'item' has an invalid type, expected type is numeric"]
}
```

You can validate nested structs by nesting a `constraints` validator.

```javascript
invoiceItems = {
    required : true,
    type : "array",
    arrayItem : {
        type : "struct",
        constraints : {
            logDate : { required : true, type : "date" },
            isBilled : { required: true, type : "boolean" },
            notes : { required: true }
        }
    }
}
```

There is a [shortcut notation available](/overview/valid-constraints/nested-struct-and-array-field-name-shortcuts#nested-array-shorthand) for `arrayItem` that uses a specialized field name to skip nesting the constraints.

**Common Use Cases:**

* Shopping cart items validation
* Form field arrays (multiple phone numbers, addresses)
* Tag lists and category arrays
* File upload collections
* Multi-select option validation
* Invoice line items
* Survey question responses

## before

The field under validation must be a value before a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested. *Note: This validator will ignore values that are null or empty strings.*

```javascript
endDate : { required:true, type:"date", before: "01/01/2022" }
```

Instead of passing a date, you may specify another field to compare against the date as well:

```javascript
startDate : { required:true, type:"date", before: "endDate" }
```

## beforeOrEqual

The field under validation must be a value before or equal a given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested. *Note: This validator will ignore values that are null or empty strings.*

```javascript
endDate : { required:true, type:"date", beforeOrEqual: "01/01/2022" }
```

## constraints

This validator is used to validate a nested struct. The value of this validator are the constraints for the nested struct. *Note: This validator will ignore values that are null.*

```javascript
address = {
    "required": true,
    "type": "struct",
    "constraints": {
        "streetOne": { "required": true, "type": "string" },
        "streetTwo": { "required": false, "type": "string" },
        "city": { "required": true, "type": "string" },
        "state": { "required": true, "type": "string", "size": 2 },
        "zip": { "required": true, "type": "numeric", "size": 5 }
    }
}
```

Any validation errors found will be named using the parent field name and the child field name.

```javascript
var validationResult = validate(
    target = {
        "address": {
            "streetOne" : "123 Elm Street",
            "streetTwo" : "",
            "city"      : "Anytown",
            "zip"       : "60606"
        }
    },
    constraints = {
        "address": {
            "required": true,
            "type": "struct",
            "constraints": {
                "streetOne": { "required": true, "type": "string" },
                "streetTwo": { "required": false, "type": "string" },
                "city": { "required": true, "type": "string" },
                "state": { "required": true, "type": "string", "size": 2 },
                "zip": { "required": true, "type": "numeric", "size": 5 }
            }
        }
    }
);
```

```json
// validationResult.getAllErrorsAsJson()
{
    "address.state": ["The 'state' field is required"]
}
```

`constraints` can be used as many levels deep as you need to go.

```javascript
owner = {
    "firstName": { "required": true, "type": "string" },
    "lastName": { "required": true, "type": "string" },
    "address": {
        "required": true,
        "type": "struct",
        "constraints": {
            "streetOne": { "required": true, "type": "string" },
            "streetTwo": { "required": false, "type": "string" },
            "city": { "required": true, "type": "string" },
            "state": { "required": true, "type": "string", "size": 2 },
            "zip": { "required": true, "type": "numeric", "size": 5 }
        }
    }
}
```

`constraints` can also be combined with `items` to validate an array of structs.

```javascript
invoiceItems = {
    required : true,
    type : "array",
    arrayItem : {
        type : "struct",
        constraints : {
            logDate : { required : true, type : "date" },
            isBilled : { required: true, type : "boolean" },
            notes : { required: true }
        }
    }
}
```

There is a [shortcut notation available](/overview/valid-constraints/nested-struct-and-array-field-name-shortcuts#nested-struct-shorthand) for `constraints` that uses a specialized field name to skip nesting the constraints.

## dateEquals

The field under validation must be a value that is the same as the given date. The dates will be passed into the `dateCompare()` function in order to be converted and tested. *Note: This validator will ignore values that are null or empty strings.*

```javascript
endDate : { required:true, type:"date", dateEquals: "01/01/2022" }
```

Instead of passing a date, you may specify another field to compare against the date as well:

```javascript
startDate : { required:true, type:"date", dateEquals: "createdDate" }
```

## discrete

The field must pass certain discrete math operations using the format: `operator:value` *Note: This validator will ignore values that are null or empty strings.*

* `gt` - Greater than the value
* `gte` - Greater than or equal to the value
* `lt` - Less than the value
* `lte` - Less than or equal to the value
* `eq` - Equal to the value
* `neq` - Not equal to the value

```javascript
myField = { discrete = "gt:4" }
myField = { discrete = "eq:luis" }
myField = { discrete = "lte:1" }
```

## empty

The field is not required but if it exists it cannot be empty. *Note: This validator will ignore values that are null.*

```javascript
myField = { empty = false }
```

This is needed since [required](#required) validators allow empty strings when `false` while [type](#type) validators ignore empty values as valid. This means we can have a situation as follows:

```javascript
{
    "startDate": {
        "required": false,
        "type": "date"
    }
}
```

With these validation rules passing in `startDate = ""` would pass the validation! The empty validator helps us ensure that the value passed in is not empty (and, in this case, a date).

```javascript
{
    "startDate": {
        "required": false,
        "empty": false,
        "type": "date"
    }
}
```

The field still isn't required, but if it is passed the value must be a non-empty value and it must be parseable as a date.

## inList

The field must be in the included list. *Note: This validator will ignore values that are null or empty strings.*

```javascript
status = { inList = "active,inactive,pending" },
priority = { inList = "low,medium,high,critical" },
color = { inList = "red,green,blue,yellow" }
```

**Common Use Cases:**

* Status fields (active/inactive, published/draft)
* Priority levels (low/medium/high/critical)
* User roles (admin/user/guest/moderator)
* Product categories or types
* Geographic regions or time zones
* Payment methods (credit/debit/paypal/stripe)
* File formats or MIME types

## instanceOf

The value passed must be an instance of a particular type. This validator checks that an object is an instance of a specific class or component, useful for validating that dependency injection worked correctly or that factory methods returned the expected type. *Note: This validator will ignore values that are null or empty strings.*

```javascript
// Basic dependency injection validation
userService: {
    required: true,
    instanceOf: "UserService"  // Must be UserService instance
},
emailService: {
    instanceOf: "models.services.EmailService"  // Full path validation
},
configBean: {
    instanceOf: "ConfigurationBean"  // Validate configuration objects
}
```

**Advanced Usage Examples:**

```javascript
// Factory pattern validation
gateway: {
    required: true,
    instanceOf: "PaymentGateway"  // Ensure factory returned correct type
},
validator: {
    instanceOf: "CreditCardValidator"  // Type-safe validator injection
},

// API Response validation
data: { instanceOf: "models.ResultCollection" },
pagination: { instanceOf: "models.PaginationInfo" }
```

**Common Use Cases:**

* **Dependency Injection Validation**: Ensure WireBox injected the correct service types
* **Factory Pattern Validation**: Verify factory methods return expected object types
* **API Response Validation**: Validate that API responses contain properly typed objects
* **Plugin/Module Validation**: Ensure loaded plugins implement required interfaces
* **Configuration Validation**: Verify configuration objects are the expected type

**Path Specification:**

* Use simple names for objects in the same package: `"UserService"`
* Use dot notation for full paths: `"models.services.UserService"`
* Works with interfaces and abstract classes
* Supports CFC inheritance checking

## items

See [arrayItem](#arrayitem).

## max

The field must be less than or equal to the defined value. *Note: This validator will ignore values that are null or empty strings.*

```javascript
age = { max = 120 },
price = { max = 9999.99 },
quantity = { max = 100 }
```

**Common Use Cases:**

* Age limits and maximum age restrictions
* Price caps and budget limits
* Quantity restrictions in shopping carts
* File size limits (in MB/KB)
* Rating scales (1-5, 1-10)
* Percentage values (0-100)
* Inventory limits

## method

The `methodName` will be called on the target object and it will pass in validationData, targetValue, and metadata. It must return a boolean response: **true** = pass, **false** = fail.

Any data you place in the `metadata` structure will be set in the validation result object for later retrieval. *Note: This validator will ignore values that are null or empty strings.*

```javascript
myField = { method = "methodName" }

function methodName( validationData, targetValue, metadata ){
    metadata[ "customMessage" ] = "I am a custom message set via metadata.";
    return false;
}
```

## min

The field must be greater than or equal to the defined value. *Note: This validator will ignore values that are null or empty strings.*

```javascript
age = { min = 18 },
password = { min = 8 },
price = { min = 0.01 }
```

**Common Use Cases:**

* Minimum age requirements (18+, 21+)
* Password length requirements
* Minimum order values
* Required experience years
* Minimum bid amounts
* Rating thresholds
* Stock quantity minimums

## nestedConstraints

See [constraints](#constraints).

## notSameAsNoCase

The field must NOT be the same as another field with no case sensitivity. This validator is useful for scenarios where you need to ensure two fields are different, regardless of letter casing. *Note: This validator will ignore values that are null or empty strings.*

```javascript
// Password cannot be the same as username (case insensitive)
username: { required: true, size: "3..20" },
password: {
    required: true,
    size: "8..50",
    notSameAsNoCase: "username"  // Password can't match username
}
```

**Common Use Cases:**

* Preventing passwords from matching usernames
* Ensuring alternate contact fields are different
* Validating that backup values don't duplicate primary values

## notSameAs

The field must NOT be the same as another field with case sensitivity. This validator ensures exact case-sensitive comparison between fields. *Note: This validator will ignore values that are null or empty strings.*

```javascript
// New password must be different from current password
currentPassword: { required: true },
newPassword: {
    required: true,
    size: "8..50",
    notSameAs: "currentPassword"  // Case-sensitive comparison
},
alternateEmail: {
    type: "email",
    notSameAs: "primaryEmail"  // Must be different emails
}
```

**Common Use Cases:**

* Password change validation (new password ≠ old password)
* Ensuring backup contact information is different
* Validating that case-sensitive codes or identifiers are unique

**When to Use Each:**

* Use `notSameAs` when case matters (passwords, case-sensitive codes)
* Use `notSameAsNoCase` when case doesn't matter (usernames, display names)

## range

The field must be within the range values and the validation data must follow the range pattern: `min..max`. *Note: This validator will ignore values that are null or empty strings.*

```javascript
rating = { range = "1..5" },
temperature = { range = "-20..50" },
percentage = { range = "0..100" }
```

**Common Use Cases:**

* Rating systems (1-5 stars, 1-10 scale)
* Temperature ranges for equipment
* Percentage values (0-100%)
* Age ranges for demographics
* Price ranges for budgets
* Quantity ranges for bulk orders
* Time ranges (hours: 0-23, minutes: 0-59)

## regex

The field must pass the regular expression match with no case sensitivity. *Note: This validator will ignore values that are null or empty strings.*

```javascript
leaveType = { regex = "^(sick|vacation|disability)$" },
productCode = { regex = "^[A-Z]{2}\d{4}$" },
phoneFormat = { regex = "^\(\d{3}\) \d{3}-\d{4}$" }
```

**Common Use Cases:**

* Product codes and SKU patterns
* Phone number formatting
* License plate formats
* Social security number patterns
* Custom ID formats (employee IDs, customer codes)
* URL slug patterns
* Version number formats

## required

The field must have some type of value and not null or an empty string.

```javascript
firstName = { required = true },
email = { required = true },
newsletter = { required = false }
```

**Common Use Cases:**

* Essential user information (name, email, password)
* Legal requirements (terms acceptance, age verification)
* Contact information for orders
* Mandatory form fields
* Required configuration settings
* Critical system parameters

## requiredIf

The field under validation must be present and not empty if the `anotherfield` field is equal to the passed `value`. The validation data can be a `struct` or a `string` representing the field to check, or it can be a UDF/closure/lambda to use for validation. The UDF must return **boolean**, `validate( value, target, metadata ):boolean`

Any data you place in the `metadata` structure will be set in the validation result object for later retrieval.

```javascript
// Struct based
myField = {
 // myField is required if field2 = test and field3 = hello
 requiredIf = {
  field2 = "test",
  field3 = "hello"
 }
}

// String Based
myField = {
 // myField is required if field3 exists and has a value.
 requiredIf = "field3"
}

// UDF Based
myField = {
 // myField is required if today is monday.
 requiredIf = function( value, target, errorMetadata ) {
        return dayOfWeekAsString( dayOfWeek( now() ) ) == "Monday";
 }
}
```

## requiredUnless

The field under validation must be present and not empty unless the `anotherfield` field is equal to the passed `value`. The validation data can be a `struct` or a `string` representing the field to check.

```javascript
myField = {
 // myField is required unless field2 = test and field3 = hello
 requiredUnless = {
  field2 = "test",
  field3 = "hello"
 }
}

// String Based
myField = {
 // myField is required unless field3 exists and has a value.
 requiredUnless = "field3"
}
```

## sameAsNoCase

The field must be the same as another field with no case sensitivity. *Note: This validator will ignore values that are null or empty strings.*

```javascript
confirmEmail = { sameAsNoCase = "email" },
displayName = { sameAsNoCase = "username" }
```

**Common Use Cases:**

* Email confirmation (case-insensitive matching)
* Username verification fields
* Display name matching
* Case-insensitive code confirmation

## sameAs

The field must be the same as another field with case sensitivity. *Note: This validator will ignore values that are null or empty strings.*

```javascript
confirmPassword = { sameAs = "password" },
verifyApiKey = { sameAs = "apiKey" }
```

**Common Use Cases:**

* Password confirmation fields
* API key verification
* Security code confirmation
* Case-sensitive token matching
* Exact duplicate field validation

## size

The field value size must be within the range values and the validation data must follow the range pattern: `min..max.` Value can be a (struct,string,array,query). *Note: This validator will ignore values that are null or empty strings.*

```javascript
username = { size = "3..20" },
description = { size = "10..500" },
tags = { size = "1..10" }  // Array size
```

**Common Use Cases:**

* Username length requirements (3-20 characters)
* Password complexity (8-128 characters)
* Description fields (min/max word counts)
* Tag or category limits (max 10 items)
* Comment length restrictions
* File name length limits
* Array size validation (shopping cart items)

## type

One of the most versatile validators. It can test if the value is of the following specific types:

* alpha
* array
* binary
* boolean
* component
* creditcard
* date
* email
* float
* GUID
* integer
* ipaddress
* json
* numeric
* query
* ssn
* string
* struct
* telephone
* url
* usdate
* UUID
* xml
* zipcode

*Note: This validator will ignore values that are null or empty strings.*

```javascript
email = { type = "email" },
price = { type = "numeric" },
birthDate = { type = "date" },
isActive = { type = "boolean" },
config = { type = "json" }
```

**Common Use Cases:**

* **email**: User registration, contact forms
* **numeric/float**: Prices, quantities, measurements
* **date/usdate**: Birth dates, appointment scheduling
* **boolean**: Feature toggles, yes/no questions
* **creditcard**: Payment processing
* **telephone**: Contact information
* **url**: Website links, API endpoints
* **json/xml**: Configuration data, API payloads
* **array/struct**: Complex data validation
* **guid/uuid**: Unique identifiers

## udf

The field value, the target object, and an empty metadata structure will be passed to the declared closure/lambda to use for validation. The UDF must return **boolean**, `validate( value, target, metadata ):boolean`

Any data you place in the `metadata` structure will be set in the validation result object for later retrieval. *Note: This validator will ignore values that are null or empty strings.*

```javascript
myField = { udf = function( value, target, metadata ) { return true; } }
myField = { udf = (value ,target, metadata ) => true }
myField = { udf = function( value, target, metadata ) {
    metadata[ "customMessage" ] = "This is a custom error message from within the udf";
    return false;
}
```

## unique

The field must be a unique value in a specific database table. The validation data is a struct with the following keys:

* `table` : The name of the table to check
* `column` : The column to check, defaults to the property field in check

*Note: This validator will ignore values that are null or empty strings.*

```javascript
username = { unique = { table = "users", column = "username" } },
email = { unique = { table = "users", column = "email_address" } },
productSku = { unique = { table = "products" } }  // Uses field name as column
```

**Common Use Cases:**

* User registration (unique usernames, emails)
* Product catalogs (unique SKUs, product codes)
* Employee records (unique employee IDs, SSNs)
* Customer accounts (unique account numbers)
* Inventory management (unique serial numbers)
* Content management (unique slugs, URLs)
* Organization data (unique department codes)

## validator

The field value will be passed to the validator CFC to be used for validation. Please see [Custom Validators](/advanced/advanced-custom-validators)

```javascript
myField = { validator = "UniqueValidator@cborm" }
```


# Custom Message Replacements

CBValidation provides powerful message replacement functionality that allows you to create dynamic, context-aware error messages. You can use these replacements in both custom constraint messages and i18n resource bundles.

## Global Replacements

These replacements are available for **all validators**:

* `{rejectedValue}` - The actual value that failed validation
* `{field}` or `{property}` - The name of the field being validated
* `{validationType}` - The name of the constraint validator (e.g., "Required", "Size", "Type")
* `{validationData}` - The constraint's configuration value (e.g., for `size="5..10"`, this would be "5..10")

## Validator-Specific Replacements

Each validator provides additional context-specific replacement variables accessible via the error metadata:

### Numeric Validators

* **`{MaxValidator}`** - `{max}` - The maximum allowed value
* **`{MinValidator}`** - `{min}` - The minimum required value
* **`{RangeValidator}`** - `{range}`, `{min}`, `{max}` - Range boundaries
* **`{DiscreteValidator}`** - `{operation}`, `{operationValue}` - Math operation details

### String & Collection Validators

* **`{SizeValidator}`** - `{size}`, `{min}`, `{max}` - Size constraints for strings, arrays, structs
* **`{TypeValidator}`** - `{type}` - Expected data type
* **`{RegexValidator}`** - `{regex}` - Regular expression pattern
* **`{InListValidator}`** - `{inList}` - Comma-separated list of valid values

### Comparison Validators

* **`{SameAsValidator}`** - `{sameas}` - Field name for comparison
* **`{SameAsNoCaseValidator}`** - `{sameas}` - Field name for case-insensitive comparison
* **`{NotSameAsValidator}`** - `{notsameas}` - Field name that should be different
* **`{NotSameAsNoCaseValidator}`** - `{notsameas}` - Field name for case-insensitive difference check

### Date Validators

* **`{AfterValidator}`** - `{after}` - Reference date or field name
* **`{BeforeValidator}`** - `{before}` - Reference date or field name
* **`{AfterOrEqualValidator}`** - `{afterOrEqual}` - Reference date or field name
* **`{BeforeOrEqualValidator}`** - `{beforeOrEqual}` - Reference date or field name
* **`{DateEqualsValidator}`** - `{dateEquals}` - Reference date or field name

### Database & Uniqueness

* **`{UniqueValidator}`** - `{table}`, `{column}` - Database table and column being checked

## Usage Examples

### Basic Custom Messages

```javascript
username = {
    required = true,
    requiredMessage = "Please enter your {field}",
    size = "3..20",
    sizeMessage = "The {field} must be between {min} and {max} characters"
}
```

### Advanced Examples with Metadata

```javascript
password = {
    required = true,
    size = "8..128",
    sizeMessage = "Password must be at least {min} characters (you entered {rejectedValue} characters)",
    regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)",
    regexMessage = "Password must contain uppercase, lowercase, and numbers (Pattern: {regex})"
},

age = {
    required = true,
    range = "18..65",
    rangeMessage = "Age must be between {min} and {max} years old (you entered: {rejectedValue})"
},

confirmPassword = {
    required = true,
    sameAs = "password",
    sameAsMessage = "Password confirmation must match your {sameas} field"
}
```

### i18n Integration

You can use these replacements in your resource bundle files:

```properties
# resources/validation_en.properties
user.username.required=Please provide a {field} for your account
user.username.size={field} must be {min}-{max} characters (current: {rejectedValue})
user.age.range=Age must be {min} to {max} years (you entered {rejectedValue})
user.email.type=Please enter a valid {type} address in the {field} field
```

## Error Metadata Access

Starting in CBValidation 4.3.0+, you can access all error metadata programmatically:

```javascript
var result = validate(target=user, constraints="userValidation");
if (result.hasErrors()) {
    for (var error in result.getAllErrors()) {
        var metadata = error.getErrorMetadata();
        // metadata contains all the replacement variables
        // e.g., metadata.min, metadata.max, metadata.type, etc.
    }
}
```

This allows for dynamic error handling and custom error message generation based on the specific validation context.


# Constraint Custom Messages

CBValidation provides default English error messages for all constraints, but you can customize these messages to match your application's tone, language, or specific requirements. Custom messages give you complete control over validation error presentation.

## Message Convention

To create a custom message for any constraint, follow this simple pattern:

```javascript
{constraintName}Message = "Your custom error message"
```

The constraint name should match exactly (case-sensitive) with the word "Message" appended.

## Basic Examples

### Single Constraint Messages

```javascript
username = {
    required = true,
    requiredMessage = "Please enter a username"
}
```

### Multiple Constraint Messages

```javascript
username = {
    required = true,
    requiredMessage = "Username is required for your account",
    size = "3..20",
    sizeMessage = "Username must be 3-20 characters long",
    regex = "^[a-zA-Z0-9_]+$",
    regexMessage = "Username can only contain letters, numbers, and underscores"
}
```

## All Constraint Message Options

Here are the message options for all available constraints:

### Core Constraints

```javascript
requiredMessage = "This field is required"
typeMessage = "Please enter a valid value"
sizeMessage = "Value must be the correct size"
emptyMessage = "This field must be empty"
```

### Numeric Constraints

```javascript
minMessage = "Value must be at least the minimum"
maxMessage = "Value cannot exceed the maximum"
rangeMessage = "Value must be within the specified range"
discreteMessage = "Value must meet the numeric criteria"
```

### String Constraints

```javascript
regexMessage = "Value must match the required pattern"
alphaMessage = "Value must contain only letters"
inListMessage = "Please select a valid option"
```

### Comparison Constraints

```javascript
sameAsMessage = "Values must match"
sameAsNoCaseMessage = "Values must match (case-insensitive)"
notSameAsMessage = "Values must be different"
notSameAsNoCaseMessage = "Values must be different (case-insensitive)"
```

### Date Constraints

```javascript
afterMessage = "Date must be after the specified date"
beforeMessage = "Date must be before the specified date"
afterOrEqualMessage = "Date must be on or after the specified date"
beforeOrEqualMessage = "Date must be on or before the specified date"
dateEqualsMessage = "Date must match the specified date"
```

### Advanced Constraints

```javascript
acceptedMessage = "You must accept the terms"
instanceOfMessage = "Value must be of the correct type"
uniqueMessage = "This value already exists"
methodMessage = "Custom validation failed"
udfMessage = "Custom validation failed"
```

## Dynamic Message Replacements

Custom messages support dynamic replacement variables that make your messages more informative:

```javascript
email = {
    required = true,
    requiredMessage = "The {field} field is required",
    type = "email",
    typeMessage = "Please enter a valid {type} in the {field} field"
},

password = {
    size = "8..128",
    sizeMessage = "Password must be {min}-{max} characters (you entered {rejectedValue})"
},

age = {
    range = "18..65",
    rangeMessage = "Age must be between {min} and {max} years (current: {rejectedValue})"
}
```

## User-Friendly Message Examples

### Registration Form

```javascript
this.constraints = {
    firstName = {
        required = true,
        requiredMessage = "Please enter your first name",
        size = "2..50",
        sizeMessage = "First name must be 2-50 characters long"
    },

    email = {
        required = true,
        requiredMessage = "Email address is required",
        type = "email",
        typeMessage = "Please enter a valid email address"
    },

    password = {
        required = true,
        requiredMessage = "Password is required",
        size = "8..128",
        sizeMessage = "Password must be at least 8 characters long"
    },

    confirmPassword = {
        required = true,
        requiredMessage = "Please confirm your password",
        sameAs = "password",
        sameAsMessage = "Password confirmation doesn't match"
    },

    termsAccepted = {
        accepted = true,
        acceptedMessage = "You must accept the terms and conditions"
    }
};
```

### Profile Update Form

```javascript
this.constraints = {
    currentPassword = {
        required = true,
        requiredMessage = "Current password is required to make changes"
    },

    newEmail = {
        type = "email",
        typeMessage = "Please enter a valid email address",
        unique = { table: "users", column: "email" },
        uniqueMessage = "This email address is already registered"
    },

    age = {
        range = "13..120",
        rangeMessage = "Please enter a valid age between 13 and 120"
    }
};
```

## Best Practices

### 1. Be Specific and Helpful

```javascript
// ❌ Vague
requiredMessage = "Required field"

// ✅ Specific and helpful
requiredMessage = "Please enter your phone number so we can contact you"
```

### 2. Use Natural Language

```javascript
// ❌ Technical
sizeMessage = "Length validation failed: min=8, max=20"

// ✅ Natural language
sizeMessage = "Please enter 8-20 characters"
```

### 3. Provide Guidance

```javascript
// ❌ Just states the problem
regexMessage = "Invalid format"

// ✅ Provides guidance
regexMessage = "Phone number should be in format: (555) 123-4567"
```

### 4. Use Replacement Variables

```javascript
// ❌ Static message
rangeMessage = "Value must be between 1 and 100"

// ✅ Dynamic with replacements
rangeMessage = "Please enter a value between {min} and {max}"
```

## i18n Integration

Custom messages work seamlessly with i18n. You can define messages in resource bundles and still use the same constraint message pattern:

```javascript
// In your constraints
email = {
    required = true,
    requiredMessage = "#user.email.required#",
    type = "email",
    typeMessage = "#user.email.invalid#"
}
```

```properties
# In resources/validation_en.properties
user.email.required=Please provide your email address
user.email.invalid=Please enter a valid email address

# In resources/validation_es.properties
user.email.required=Por favor proporciona tu dirección de correo
user.email.invalid=Por favor ingresa una dirección de correo válida
```

This approach allows you to maintain consistent, localized error messages across your entire application while leveraging CBValidation's powerful constraint system.




---

[Next Page](/llms-full.txt/1)

