Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
2021-MAY-15
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.
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.
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.
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.
Lucee 5+
ColdFusion 2016+
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 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()
The ColdBox ORM Module is a professional open source software backed by Ortus Solutions, Corp offering services like:
Custom Development
Professional Support & Mentoring
Training
Server Tuning
Security Hardening
Code Reviews
The Box Products discussion group and community can be found here:
https://community.ortussolutions.com/c/communities
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
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.
Upgraded to leverage the new cbi18n v2.x module. New CFML engine compatiblities and moving to modernland!
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.
Initial awesome release!
2022-JAN-12
Nested structs can be validated using the constraints
or nestedConstraints
validator.
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.
The field name change also applies to items
or arrayItem
validators.
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.
To make defining array item and nested constraint validators easier, you can use a shorthand on the field name, like so:
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.
A few of the built-in validators now have an alias in addition to the long form validator name:
Co-authored by @garciadev
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
Date Comparisons Fail if Compare field is empty #58 thanks to @nockhigan: https://github.com/coldbox-modules/cbvalidation/pull/58
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
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()
Bugs
: Fixed lots of wrong type exceptions
Compat
: Remove ACF11 support
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)
If you are not using localization, then this is a seamless upgrade to you.
feature
: Added constraintProfiles
to allow you to define which fields to validate according to defined profiles:
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
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
The source code for this book is hosted in GitHub: . You can freely contribute to it and submit pull requests. The contents of this book is copyright by 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 -
Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.
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.
We highly encourage contribution to this book and our open source software. The source code for this book can be found in our where you can submit pull requests.
10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - . 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 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.
Luis Majano is a Computer Engineer that has been developing and designing software systems since the year 2000. He was born in 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 . Luis resides in Houston, Texas with his beautiful wife Veronica, baby girl Alexia and baby boy Lucas!
He is the CEO of , 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
You can configure the module by creating a cbvalidation
key in the config/Coldbox.cfc
moduleSettings
structure
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.
Important: The module will register several objects into WireBox using the @cbvalidation
namespace. The validation manager is registered as ValidationManager@cbvalidation
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 ({}
)
These constraints can then be defined in many locations where cbValidation can read them.
You can define constraints in several locations:
When validating using validate(), validateOrFail()
you have to specify a target, but specifying a constraint in your call is optional.
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
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.
Shared Constraints
You can optionally register constraints in your 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:
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.
You can then use the keys for those constraints in the validation calls:
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.
We can then create the validation rules for the properties it will apply to it:
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.
By default all properties are of type string and not required
You can then use them implicitly when calling our validation methods:
Just drop into your modules folder or use 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.
The module will also register the following methods in your handlers/interceptors/layouts/views
validate()
validateOrFail()
getValidationManager()
validatehasValue()
validateIsNullOrEmpty()
assert()
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:
Just add the name of the constraint you like and append to it the word Message and you are ready to roll:
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):
{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
{DiscreteValidator}
- operation, operationValue
{InListValidator}
- inList
{MaxValidator}
- max
{MinValidator}
- min
{RangeValidator}
- range, min, max
{RegexValidator}
- regex
{SameAsValidator}
, {SameAsNoCaseValidator}
- sameas
{SizeValidator}
- size, min, max
{TypeValidator}
- type
Below are all the currently supported constraints. If you need more you can create your own Custom validators as well.
The field must be yes, on, 1, or true. This is useful for validating "Terms of Service" acceptance.
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.
Instead of passing a date, you may specify another field to compare against the date as well:
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.
The field must be alphabetical ONLY
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.
You may also specify items
as an alias to arrayItem
.
Any validation errors found will be named using the parent field name and array index.
You can validate nested structs by nesting a constraints
validator.
There is a shortcut notation available for arrayItem
that uses a specialized field name to skip nesting the constraints.
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.
Instead of passing a date, you may specify another field to compare against the date as well:
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.
This validator is used to validate a nested struct. The value of this validator are the constraints for the nested struct.
Any validation errors found will be named using the parent field name and the child field name.
constraints
can be used as many levels deep as you need to go.
constraints
can also be combined with items
to validate an array of structs.
There is a shortcut notation available for constraints
that uses a specialized field name to skip nesting the constraints.
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.
Instead of passing a date, you may specify another field to compare against the date as well:
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
The field is not required but if it exists it cannot be empty.
This is needed since required validators allow empty strings when false
while type validators ignore empty values as valid. This means we can have a situation as follows:
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).
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.
The field must be in the included list
See arrayItem.
The field must be less than or equal to the defined value
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.
The field must be greater than or equal to the defined value
See constraints.
The field must be within the range values and the validation data must follow the range pattern: min..max
The field must pass the regular expression match with no case sensitivity
The field must have some type of value and not null.
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.
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.
The field must be the same as another field with no case sensitivity
The field must be the same as another field with case sensitivity
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)
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
eurodate
float
GUID
integer
ipaddress
json
numeric
query
ssn
string
struct
telephone
url
usdate
UUID
xml
zipcode
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.
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
The field value will be passed to the validator CFC to be used for validation. Please see Custom Validators
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
.
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:
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.
For a nested struct, this is done by defining the field as a dot-delimited field name following the nested structure.
This can be continued as many levels deep as necessary.
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.
The struct and array shorthand can be combined, as well.
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.
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.
Please note that you can validate using a procedural approach or a functional approach by using our onError() and onSuccess()
callback methods.
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.
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:
Incoming Target | Validation Fails | Result |
Object | false | Returns the same object |
Object | true | Throws |
Struct | false | Returns the structure with ONLY the fields that were validated from the constraints |
Struct | true | Throws |
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.
This will validate the object using the inline constraints that you built.
You can also tell the validation manager to ONLY validate on certain fields and not all the fields declared in the validation constraints.
This will only validate the login
and password
fields.
You can also use the following arguments:
includeFields
: The fields to include in the validation ONLY
excludeFields
: The fields to exclude in the validation
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.
This will validate the object and rc
using the sharedUser
constraints defined in the configuration file: config/Coldbox.cfc
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.
Remember you have the mixins available to you in your handlers/interceptors/layouts and views
After validation you can use the same results object and use it to display the validation errors in your client side:
If you want more control you can use the hasErrors()
and iterate over the errors to display:
You can even use the results object in your views to get specific field errors, message, etc.
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.
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.
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.
This is using the this.constraintProfiles
struct literal:
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.
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:
The unique
validator is part of the module. So make sure that the cborm
module is installed first.
The validator is mapped into WireBox as UniqueValidator@cborm
so you can use in your constraints like so:
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.
This is done because we build the appropriate SQL to make sure the property name and the field name match.
If you are using i18n (Internationalization and Localization) in your ColdBox applications you can also localize your validation error messages from the ColdBox validators.
Info You do not need to install the cbi18n
module. This module is already a dependency of the cbvalidation
module.
You will do this by our lovely conventions for you resource bundle keys:
We also setup lots of global {Key}
replacements for your messages and also several that the core constraint validators offer as well:
{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
{DiscreteValidator}
- operation, operationValue
{InListValidator}
- inList
{MaxValidator}
- max
{MinValidator}
- min
{RangeValidator}
- range, min, max
{RegexValidator}
- regex
{SameAsValidator}
, {SameAsNoCaseValidator}
- SameAs
{SizeValidator}
- size, min, max
{TypeValidator}
- type
Please note that since version 3.x of cbvalidation you can use json resource bundles thanks to cbi18n v2.x
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
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
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():
Here is a sample validator:
You can use them in two approaches when defining them in your constraints:
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.
Use the WireBox ID as they key of your validator. Then you can pass your own validation data into the validator.
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.
If you don't have any validation data to pass to a validator, just pass an empty struct ({}
) or an empty string
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: