BoxLang 🚀 A New JVM Dynamic Language Learn More...
Copyright Since 2005 ColdBox Platform by Luis Majano
and Ortus Solutions, Corp
www.coldbox.org | www.ortussolutions.com
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 validate objects or structures and even use profiles to target specific fields for validation. The validation engine is highly extensible and can be used in any kind of application.
The module leverages the power of the cbi18n module for internationalization support, providing localized validation messages, and integrates seamlessly with ColdBox's WireBox dependency injection container for maximum flexibility and testability.
Apache License, Version 2.0.
Leverage 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: validate(), validateOrFail(), getValidationManager()
This module is fully documented at: https://coldbox-validation.ortusbooks.com/. It also has an MCP server with live docs and examples.
ValidationManager@cbvalidation - The core validation enginevalidationManager@cbvalidation - Alias for convenienceThe module will also register several methods in your handlers/interceptors/layouts/views
/**
* 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="" )
Here are the module settings you can place in your
ColdBox.cfc by using the cbvalidation
settings structure in the modulesettings
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 = {
userRegistration = {
email = { required=true, type="email" },
password = { required=true, size="8..50" },
firstName = { required=true, size="1..50" },
lastName = { required=true, size="1..50" }
},
userUpdate = {
email = { required=true, type="email" },
firstName = { required=true, size="1..50" },
lastName = { required=true, size="1..50" }
}
}
}
}
You can read more about ColdBox Validation here: - https://coldbox-validation.ortusbooks.com/
Please check out the docs for the latest on constraints: https://coldbox-validation.ortusbooks.com/overview/valid-constraints. Constraints rely on rules you apply to incoming fields of data. They can be created on objects or stored wherever you like, as long as you pass them to the validation methods.
Each property can have one or more constraints attached to it. In an
object you can create a this.constraints and declare them
by the fields you like:
this.constraints = {
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 alphanumeric 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 must be a date that is equal the set targetDate
dateEquals : targetDate
// 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,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'
}
}
function saveUser( event, rc, prc ){
var results = validate( target=rc, constraints="userRegistration" );
if( results.hasErrors() ){
prc.errors = results.getAllErrors();
return event.setView( "users/registration" );
}
// Process valid data
var user = userService.create( rc );
}
function apiCreateUser( event, rc, prc ){
try{
var validData = validateOrFail( target=rc, profiles="registration" );
var user = userService.create( validData );
return event.renderData( data=user );
} catch( ValidationException e ){
return event.renderData(
statusCode=422,
data={ errors: deserializeJSON( e.extendedInfo ) }
);
}
}
class {
this.constraints = {
email = { required=true, type="email" },
age = { required=true, min=18, max=65 },
password = { required=true, size="8..50" },
confirmPassword = { required=true, sameAs="password" },
"address.street" = { required=true, size="5..100" },
"preferences.*" = { type="string" }
};
this.constraintProfiles = {
registration = "email,password,confirmPassword",
update = "email,firstName,lastName",
passwordChange = "password,confirmPassword"
};
}
Run your validation tests with the BoxLang CLI:
# Run all tests
boxlang-cli test run
# Run with specific runner
boxlang-cli test run --runner="http://localhost:60299/tests/runner.cfm"
# Run specific test bundle
boxlang-cli test run --bundles="test-harness/tests"
# Run with verbose output
boxlang-cli test run --verbose
You can also create profiles or selections of fields that will be
targeted for validation if you are defining the constraints in
objects. All you do is create a key called:
this.constraintProfiles which contains a struct of
defined fields:
this.constraintProfiles = {
new = "fname,lname,email,password",
update = "fname,lname,email",
passUpdate = "password,confirmpassword"
}
Each key is the name of the profile like new, update
passUpdate. The value of the profile is a list of fields to
validate within that selected profile. In order to use it, just pass
in one or more profile names into the validate() or
validateOrFail() methods.
var results = validateModel( target=model, profiles="update" )
var results = validateModel( target=model, profiles="update,passUpdate" )
********************************************************************************
Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp
www.coldbox.org | www.luismajano.com | www.ortussolutions.com
********************************************************************************
Because of His grace, this project exists. If you don't like this, then don't read it, its 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. And not only so, but we glory in tribulations also: knowing that tribulation worketh patience; And patience, experience; and experience, hope: And hope maketh not ashamed; because the love of God is shed abroad in our hearts by the Holy Ghost which is given unto us. ." Romans 5:5
"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
validateOrFail returns validated struct/array resultsvalidateOrFail now filters nested structs and arrays to only return keys matching constraints, not just top-level keys (PR #85)empty: false validation checkeurodate doesn't event work in ACF/Lucee as it uses just a single standard. Remove it so the user can validate as they see fit.defaultValue to apply default values before constraints are checkedpr github action now just does format checks to avoid issues with other repos.tasks.json file to include no recursionvalidatedKeys due to sharedconstraint nameType validator needs to be able to validate against any type even if that is an empty stringValidatable@cbValidation which can be used to make objects validatablenotSameAs, notSameAsNoCasefalse when the comparison target dates values are NOT dates instead of throwing an exception.InstanceOf validator thanks to @homestar9 : https://github.com/coldbox-modules/cbvalidation/pull/65EmptyValidator by @elpete. This validator is useful when a field is not required but if it exists it cannot be empty: https://github.com/coldbox-modules/cbvalidation/pull/61validationData. It was changed to a !isStruct() but in reality, it has to be simple ONLY for replacements.DateEquals which can help you validate that a target value is a date and is the same date as the validation date or other fieldAfter which can help you validate that a target value is a date and is after the validation dateAfterOrEqual which can help you validate that a target value is a date and is after or equal the validation dateBefore which can help you validate that a target value is a date and is before the validation dateBeforeOrEqual which can help you validate that a target value is a date and is before or equal the validation dateonError( closure ), onSuccess( closure ) callbacks that can be used to validate results using the validate() method and concatenate the callbacks.assert() helper that can assit you in validating truthful expressions or throwing exceptionsvalidateIsNullorEmpty() 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.BaseValidator for usage by all validators to bring uniformity, global di, and helpers.IValidator removes the getName() since that comes from the BaseValidator now.UniqueValidator now supports both creationg and update checks with new constraints.interfaces folder so we can continue to document them and use them without direct compilation.rules struct argument to several validators that missed it.validators pathvalidationData cannot be converted to a string for UDF,RequiredUnless,RequiredIf,Unique so they are excluded from this message replacementfeature : Added constraintProfiles to allow you to define which fields to validate according to defined profiles: https://github.com/coldbox-modules/cbvalidation/issues/37feature : Updated RequiredUnless and RequiredIf to use struct literal notation instead of the weird parsing we did.feature : Added the Unique validator thanks to @elpete!feature : All validators now accept a rules argument, which is the struct of constraints for the specific field it's validating onimprovement : Added null support for the RequiredIf,RequiredUnless validator valuesAccepted - The field under validation must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.Alpha - Only allows alphabetic charactersRequiredUnless 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.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.Required validatorevaluate() instead use invoke()Bugs : Fixed lots of wrong type exceptionsCompat : Remove ACF11 supportbug : Added float to the type validator which was missingbug : This version's mixin is causing errors because its looking for this.validate() and its looking in the handler, not in the mixin file itself.features : validateOrFail() new method to validate and if it fails it will throw a ValidationException. Also if the target is an object, the object is returned. If the target is a struct, the struct is returned ONLY with the validated fields.feature : validateModel() is now deprecated in favor of validate(). validateModel() is now marked for deprecation.improvement : Direct scoping for performance an avoidance of lookup bugsimprovement : HTTPS protocol for everythingimprovement : Updated to testbox 3bug : Fix mapping declaration for apidocs`bug : Missing return on addSharedConstraint() functioninvoke for security and performancenewError() on the validation result objectMaxValidator The Max validator needs to better reflect that it can be less than or equal to the number to compare to <=MinValidator The explanation needs to better reflect the min validator which is >=GenericObject Should return null on non-existent keys instead of an exception if not we cannot validate nullnessvalidate() methods using the includeFields argument.
$
box install cbvalidation