arrow-left

Only this pageAll pages
gitbookPowered by GitBook
1 of 30

v2.x

Loading...

Intro

Loading...

Loading...

Loading...

Loading...

Loading...

Overview

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Advanced

Loading...

Loading...

Loading...

Loading...

Installation

hashtag
Instructions

Just drop into your modules folder or use CommandBoxarrow-up-right 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.

hashtag
Mixins - Helper Methods

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

  • validate()

  • validateOrFail()

  • getValidationManager()

/**
 * 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()

Author

hashtag
Luis Fernando Majano Lainez

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 Salvadorarrow-up-right 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 Universityarrow-up-right. 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

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!)

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

hashtag
Contributors

hashtag
Will de Bruin

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.

  • Ortus Solutionsarrow-up-right
    www.luismajano.comarrow-up-right

    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):

    hashtag
    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

    hashtag
    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

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

    What's New With 2.0.0

    hashtag
    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

    hashtag
    Improvements

    • Consistency on all validators to ignore null or empty values except the Required validator

    • Formatting consistencies

    • Improve error messages to describe better validation

    hashtag
    Compat & Bugs

    • Bugs : Fixed lots of wrong type exceptions

    • Compat : Remove ACF11 support

    Get away from evaluate() instead use invoke()

    Available Constraints

    Below are all the currently supported constraints. If you need more you can create your own Custom validators as well.

    hashtag
    accepted

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

    hashtag
    alpha

    The field must be alphabetical ONLY

    hashtag
    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

    hashtag
    inList

    The field must be in the included list

    hashtag
    max

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

    hashtag
    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.

    hashtag
    min

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

    hashtag
    range

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

    hashtag
    regex

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

    hashtag
    required

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

    hashtag
    requiredIf

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

    hashtag
    requiredUnless

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

    hashtag
    sameAsNoCase

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

    hashtag
    sameAs

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

    hashtag
    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)

    hashtag
    type

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

    • alpha

    • array

    • binary

    hashtag
    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

    hashtag
    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

    hashtag
    validator

    The field value will be passed to the validator CFC to be used for validation. Please see

    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'
    }
    terms = { accepted = true }
    - Less than the value
  • lte - Less than or equal to the value

  • eq - Equal to the value

  • neq - Not equal to the value

  • boolean
  • component

  • creditcard

  • date

  • email

  • eurodate

  • float

  • GUID

  • integer

  • ipaddress

  • json

  • numeric

  • query

  • ssn

  • string

  • struct

  • telephone

  • url

  • usdate

  • UUID

  • xml

  • zipcode

  • Custom Validators
    terms = { alpha = true }
    myField = { discrete = "gt:4" }
    myField = { discrete = "eq:luis" }
    myField = { discrete = "lte:1" }
    myField = { inList = "red,green,blue" }
    myField = { max = 25 }
    myField = { method = "methodName" }
    
    function methodName( validationData, targetValue ){
        return true;
    }
    myField = { min = 8 }
    myField = { range = "1..5" }
    myField = { range = "5..-5" }
    myField = { regex = "^(sick|vacation|disability)$" }
    myField = { required=true }
    myField = { required=false }
    myField = { 
     requiredIf = {
      field2 = "test",
      field3 = "hello"
     }
    }
    myField = { 
     requiredUnless = {
      field2 = "test",
      field3 = "hello"
     }
    }
    myField = { sameAs = "otherField" }
    myField = { sameAs = "otherField" }
    myField = { size : 10 }
    myFiedl = { size : "8..20" }
    myField = { type : "float" }
    myField = { udf = function( value, target ) { return true; } }
    myField = { udf = (value,target) => true }
    myField = { unique = { table : "users", column : "username" } }
    myField = { validator = "UniqueValidator@cborm" }

    Validating Constraints

    hashtag
    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.

    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.

    hashtag
    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

    hashtag
    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:

    /**
     * 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()
    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();
    }
    /**
     * 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);
    
    }
    /**
     * 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();
    
    }

    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.

    About This Book

    The source code for this book is hosted in GitHub: https://github.com/ortus-docs/cbvalidation-docsarrow-up-right. You can freely contribute to it and submit pull requests. The contents of this book is copyright by Ortus Solutions, Corparrow-up-right 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 -

    hashtag
    External Trademarks & Copyrights

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

    hashtag
    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.

    hashtag
    Contributing

    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.

    hashtag
    Charitable Proceeds

    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.

    hashtag
    Shalom Children's Home

    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.

    https://www.ortussolutions.com/products/commandboxarrow-up-right
    GitHub repositoryarrow-up-right
    https://www.harvesting.org/arrow-up-right
    Shalom Children's Home

    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.

    hashtag
    System Requirements

    • Lucee 5+

    • ColdFusion 2016+

    hashtag
    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 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()

    hashtag
    Professional Open Source

    The ColdBox ORM Module is a professional open source software backed by offering services like:

    • Custom Development

    • Professional Support & Mentoring

    • Training

    hashtag
    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

    Server Tuning
  • Security Hardening

  • Code Reviews

  • configuration file
    Ortus Solutions, Corparrow-up-right
    Ortus Solutions, Corp
    Much Morearrow-up-right

    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.

        // 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: config/Coldbox.cfc

    Configuration File

    Shared Constraints

    You can optionally register constraints in your ColdBox configurationarrow-up-right 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:

    hashtag
    Declaration

    config/ColdBox.cfc
    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 by unique key name.

    hashtag
    Usage

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

    validate( target, "sharedUser" );
    
    validate( rc, "loginForm" );
    
    validate( rc, "changePasswordForm" );

    Validating with a-la-carte constraints

    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.

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

    This will validate the object using the inline constraints that you built.

    Declaring Constraints

    hashtag
    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 ({})

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

    hashtag
    Defining Constraints

    You can define constraints in several locations:

    circle-info

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

    hashtag
    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
    Inside a domain object
    A-la-carte
    // Define the field by name
    // The contents are the constraints
    fieldName1 = {
        validator1 = validationData,
        validator2 = validationData
    },
    
    fieldName2 = {
        validator1 = validationData,
        validator2 = validationData
    }

    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

    hashtag
    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:

    Object

    true

    Throws ValidationException

    Struct

    false

    Returns the structure with ONLY the fields that were validated from the constraints

    Struct

    true

    Throws ValidationException

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

    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.

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

    This will only validate the login and password fields.

    hashtag
    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

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

    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.

    // 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" );
            }
        }

    Configuration

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

    Key

    Type

    Required

    Default

    Description

    manager

    instantiation path or WireBox ID

    false

    triangle-exclamation

    Important: The module will register several objects into WireBox using the @cbvalidation namespace. The validation manager is registered as ValidationManager@cbvalidation

    config/Coldbox.cfc
    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 }
            }
        }
    
    }

    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.

    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.

    hashtag
    Declaration

    models/User.cfc
    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
        }
    }

    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.

    circle-info

    By default all properties are of type string and not required

    hashtag
    Usage

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

    config/User.cfc
    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}
        };
    }
    validate( myUser );
    validateOrFail( myUser );

    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/37arrow-up-right

    • 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

    Unique ORM Validator

    hashtag
    Usage

    The unique validator is part of the module. So make sure that the cborm module is installed first.

    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.

    hashtag
    Defining Profiles

    This is using the this.constraintProfiles struct literal:

    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.

    // get reference
    property name="validationManager" inject="ValidationManager@cbvalidation";
    circle-info

    Remember you have the mixins available to you in your handlers/interceptors/layouts and views

    hashtag
    Declaring the Constraint

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

    hashtag
    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.

    circle-info

    This is done because we build the appropriate SQL to make sure the property name and the field name match.

    box install cborm
    cbormarrow-up-right
    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.

    hashtag
    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:

    this.constraintProfiles = {
    	"new" = "fname,lname,email,password",
    	"update" = "fname,lname,email",
    	"passUpdate" = "password,confirmpassword"
    }
    var results = validateModel( target=model, profiles="update" )
    var results = validateModel( target=model, profiles="update,passUpdate" )
    { 
        fieldName : { validator: "UniqueValidator@cborm" },
        // or
        fieldName : { "UniqueValidator@cborm" : {}  }
    }
    this.constraints = {
      "username" = { required=true, validator: "UniqueValidator@cborm" },
      "email" = { required=true, validator: "UniqueValidator@cborm" }
    };

    Displaying Errors

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

    hashtag
    Handlers:

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

    hashtag
    Views:

    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, messagesbox, etc.

    hashtag
    Common Methods

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

    • getResultMetadata()

    • getFieldErrors( [field] )

    • getAllErrors( [field] )

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

    getAllErrorsAsJSON( [field] )

  • getAllErrorsAsStruct( [field] )

  • getErrorCount( [field] )

  • hasErrors( [field] )

  • getErrors()

  • <-- Display all errors as a message box --->
    #getInstance( "MessageBox@cbMessagebox" )
        .renderMessage( type="error", messageArray=prc.validationResults.getAllErrors() )#
    <cfif prc.validationResults.hasErrors()>
        <ul>
        <cfloop array="#prc.validationResults.getErrors()#" index="thisError">
            <li>#thisError.getMessage()#</li>
        </cfloop>
        </ul>
    </cfif>

    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:

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

    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:

    {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:

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

    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

    hashtag
    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

    hashtag
    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():

    Here is a sample validator:

    hashtag
    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.

    circle-check

    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.

    circle-check

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

    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;
        }
    },
    cbvalidation.models.validators.IValidator
    /**
     * 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();
    
    }
    /**
     * 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;
        }
    
    }
    //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
            }
         };

    i18n Integration

    hashtag
    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.

    circle-info

    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:

    hashtag
    Objects:

    hashtag
    Forms with Shared Constraints Name

    hashtag
    Forms with No Shared Constraints

    hashtag
    Key Replacements

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

    hashtag
    Global Replacements

    • {rejectedValue} - The rejected value

    • {field} or property - The property or field that was validated

    • {validationType}

    hashtag
    i18n Validator Replacements

    • {DiscreteValidator} - operation, operationValue

    • {InListValidator} - inList

    • {MaxValidator}

    hashtag
    Examples

    - 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

  • - max
  • {MinValidator} - min

  • {RangeValidator} - range, min, max

  • {RegexValidator} - regex

  • {SameAsValidator}, {SameAsNoCaseValidator} - SameAs

  • {SizeValidator} - size, min, max

  • {TypeValidator} - type

  • {ObjectName}.{Field}.{ConstraintType}}=Message
    {SharedConstraintName}.{Field}.{ConstraintType}=Message
    GenericForm.{Field}.{ConstraintType}=Message
    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.