I am so excited to bring you the release of cbValidation to version 3.1.0. This has been a great collaboration between Wil De Bruin and Eric Peterson. Thanks so much guys for all that you do for open source. You can see all of the release notes below with some of the major improvements of this release. To get this release make sure you are already on version 3.x and use CommandBox: box update cbvalidation. You can find the release notes here: https://coldbox-validation.ortusbooks.com/intro/release-history/whats-new-with-3.1.0 and you can view all the new documentation here: https://coldbox-validation.ortusbooks.com. Enjoy!

New Functional Callbacks: onError(), onSuccess()

We have introduced two functional callbacks so you can deal with validation in a more functional approach than a procedural approach. Let's see how we used to do validation proceduraly:

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

We use the validate() method and it returns a ValidationResult object which we can then use to check for errors, get errors and much more. Now let's use the new modern onError() and onSuccess() functional constructs:

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

As you can see, we can chain our call of execution from the vaidate() method into either an error or a success closure/lambda. We can then continue to decide what happens if it validates. Cleaner and much more readable. Enjoy!

New Validators

We have introduced several new validators in this release, check them out:

  • arrayItem : { constraints } - The target field must be an array and all the items in the array must validate against the constraints given.
  • after : date - The target field must be a date that is after the given date.
  • after : otherField - The target field must be a date that is after another field (otherField)
  • afterOrEqual : date - The target field must be a date that is after or equal the given date.
  • afterOrEqual : otherField - The target field must be a date that is after or equal another field (otherField)
  • before : date - The target field must be a date that is before the given date.
  • before : otherField - The target field must be a date that is before another field (otherField)
  • beforeOrEqual : date - The target field must be a date that is before or equal the given date.
  • beforeOrEqual : otherField - The target field must be a date that is before or equal another field (otherField)
  • dateEquals : date - The target field must be the same date as the given date
  • dateEquals : otherField - The target field must be the same date as the otherField date
startDate : { required:true, type:"date", after: dateAdd( "d", 1, now() ) }

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

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

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

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

users : { required: true, type: "array", arrayItem : {
							"name" : { required : true },
							"age"  : { required : true, range : "18..50" }
						}
			}
			
invoiceItems = {
    required : true,
    type : "array",
    arrayItem : {
        logDate : { required : true, type : "date" },
        isBilled : { required: true, type : "boolean" },
        notes : { required: true }
    }
}

Updated Validators

  • requiredIf : otherField - The target field must be required if the otherField exists and has value
  • requiredUnless : otherField - The target field must be required unless the otherField exists and has value

New Mixins

We have created several new mixins for this release in order to assist you with validating, well, anything. Here are the three new methods available to your handlers, interceptors, layouts and views.

  • validateHasValue( targetValue ) - Checks for nullness or for length if it's a simple value, array, query, struct or object.
  • validateIsNullOrEmpty( targetValue ) - Check if a value is null or is a simple value and it's empty
  • assert( expression, [message] ) - This method mimics the Java assert() function, where it evaluates a expression to a boolean value and it must be true, else we throw an AssertException exception and you can pass an optional message to the exception.

/**
 * 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="" )

Release Notes

Added

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

Changed

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

Fixed

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