Git Product home page Git Product logo

cbvalidation's Introduction


Copyright Since 2005 ColdBox Platform by Luis Majano and Ortus Solutions, Corp
www.coldbox.org | www.ortussolutions.com


WELCOME TO THE COLDBOX VALIDATION MODULE

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.

LICENSE

Apache License, Version 2.0.

IMPORTANT LINKS

SYSTEM REQUIREMENTS

  • Lucee 5.x+
  • Adobe ColdFusion 2018+

Installation

Leverage CommandBox to install:

box install cbvalidation

The module will register several objects into WireBox using the @cbvalidation namespace. The validation manager is registered as ValidationManager@cbvalidation. It will also register several helper methods that can be used throughout the ColdBox application: validate(), validateOrFail(), getValidationManager()

Mixins

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

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

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

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

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

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

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

Settings

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

modulesettings = {
	cbValidation = {
		// The third-party validation manager to use, by default it uses CBValidation.
		manager = "class path",

		// You can store global constraint rules here with unique names
		sharedConstraints = {
			name = {
				field = { constraints here }
			}
		}
	}
}

You can read more about ColdBox Validation here: - https://coldbox-validation.ortusbooks.com/

Constraints

Please check out the docs for the latest on constraints: https://coldbox-validation.ortusbooks.com/overview/valid-constraints. Constraints rely on rules you apply to incoming fields of data. They can be created on objects or stored wherever you like, as long as you pass them to the validation methods.

Each property can have one or more constraints attached to it. In an object you can create a this.constraints and declare them by the fields you like:

this.constraints = {

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

        // The field under validation must be a date after the set targetDate
        after : targetDate

        // The field under validation must be a date after or equal the set targetDate
        afterOrEqual : targetDate

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

        // The field under validation is an array and all items must pass this validation as well
        arrayItem : {
            // All the constraints to validate the items with
        }

        // The field under validation must be a date before the set targetDate
        before : targetDate

        // The field under validation must be a date before or equal the set targetDate
        beforeOrEqual : targetDate

        // The field under validation must be a date that is equal the set targetDate
        dateEquals : targetDate

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

        // value in list
        inList : list

        // max value
        max : value

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

        // min value
        min : value

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

        // regex validation
        regex : valid no case regex

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

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

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

        // same as but with no case
        sameAsNoCase : propertyName

        // same as another property
        sameAs : propertyName

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

        // specific type constraint, one in the list.
        type  : (alpha,array,binary,boolean,component,creditcard,date,email,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'
	}

}

Constraint Profiles

You can also create profiles or selections of fields that will be targeted for validation if you are defining the constraints in objects. All you do is create a key called: this.constraintProfiles which contains a struct of defined fields:

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

Each key is the name of the profile like new, update passUpdate. The value of the profile is a list of fields to validate within that selected profile. In order to use it, just pass in one or more profile names into the validate() or validateOrFail() methods.

var results = validateModel( target=model, profiles="update" )
var results = validateModel( target=model, profiles="update,passUpdate" )
********************************************************************************
Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp
www.coldbox.org | www.luismajano.com | www.ortussolutions.com
********************************************************************************

HONOR GOES TO GOD ABOVE ALL

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

"Therefore being justified by faith, we have peace with God through our Lord Jesus Christ: By whom also we have access by faith into this grace wherein we stand, and rejoice in hope of the glory of God. And not only so, but we glory in tribulations also: knowing that tribulation worketh patience; And patience, experience; and experience, hope: And hope maketh not ashamed; because the love of God is shed abroad in our hearts by the Holy Ghost which is given unto us. ." Romans 5:5

THE DAILY BREAD

"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12

cbvalidation's People

Contributors

angel-chrystian avatar bdw429s avatar elpete avatar eppinger avatar evagoras avatar gpickin avatar homestar9 avatar jclausen avatar lmajano avatar michaelborn avatar mordantwastrel avatar nockhigan avatar ryanalbrecht avatar sanaullah avatar srikanthm79 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cbvalidation's Issues

ValidationManager errors when returning validatedKeys due to sharedconstraint name

https://github.com/coldbox-modules/cbvalidation/blob/development/models/ValidationManager.cfc#L283

If you pass in a shared constraint name to validateOrFail(target=rc, constraints="loginForm");
The validate function handles the shared constraint name... and validates correctly.

On 283, it uses constraints.keyExists( key ) but key in still the shared constraint name "loginForm" - it hasn't been exploded into the full struct of Constraints.

This needs to be resolved.

Found by PowerToaster in the ortus community forum.
https://community.ortussolutions.com/t/the-function-keyexists-does-not-exist-in-the-string/9601

Ability to define constraint profiles

INtroduce a new key called this.constraintProfiles which is a struct of arrays/lists. Each key is the name of the profile and it's value can be an array or list of fields. This is useful to define all global constraints but actually validate using a profile only.

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

Then when calling validation you use the profiles argument

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

Or you can pass multiple profiles

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

Provide an easier way for the user to add custom errors to an existing validationResult object

Summary

Provide an easier way for the user to add custom errors to an existing validationResult object

Detailed Description

Currently, the developer can create a new validationError object two ways:

Use newError(ARGUMENTS)

Or use getInstance('cbvalidation.models.result.ValidationError') and then populate that error object

Then the developer has to use addError() to add it to the ValidationResult.

Propose a new feature - something like addNewError() (not a terribly good name) that would accept all the arguments for a validationError (like newError) and add it to the list of errors (like addError).

Possible Implementation Ideas

    /**
     * Create a new error, then add it to the current error array
     * 
     * @arguments all fields that would be part of a validationError object
     */
    any function addNewError() {
        addError(duplicate(errorTemplate).configure(argumentCollection = arguments));
        return this;
    }

UDF Validator will Fail if TargetValue is Undefined (ACF)

Here's how you can replicate the issue on Adobe ColdFusion. I tested with ACF 2016 (latest).

Create a new model object with a property with no default:
property name="userType";

Add a UDF validator to the constraints struct:

this.constraints = {
    "userType": { 
        required: true,
        udf: function( value, target ) {
             return true;  // just for sake of example
        }
    }
}

Now try validating the object. You'll get the following error in cbvalidation\models\validators\UDFValidator.cfc
Element TARGETVALUE is undefined in ARGUMENTS.

I suspect the issue has to do with how ACF handles null/undefined values. I'm just guessing, but a possible fix might be to check if arguments.targetValue is null, and then assign it to an empty string or JavaCast it as a null via javaCast( "null", "" ).

Another idea would be to stop attempting to validate a constraint if required: true exists and the value fails that check. In other words, if the value doesn't exist and the value is required, don't attempt any other validators including UDF or method validators

Hope this helps!

Feature Suggestion: InstanceOf Validator

CBValidation already has "type" validation, but having an "InstanceOf" validator would be pretty slick for ensuring that composed object properties are of the correct class type.

I would need to write tests, but perhaps something like this would work

component extends="BaseValidator" accessors="true" singleton {

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

	/**
	 * Will check if an incoming instance type
	 *
	 * @validationResult The result object of the validation
	 * @target           The target object to validate on
	 * @field            The field on the target object to validate on
	 * @targetValue      The target value to validate
	 * @validationData   The validation data the validator was created with
	 * @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
	){

		// return true if no data to check, type needs a data element to be checked.
		if ( isNull( arguments.targetValue ) || isNullOrEmpty( arguments.targetValue ) ) {
			return true;
		}

		// value is valid if it is an object and of the correct type
		var r = ( 
			isObject( r ) && 
			isInstanceOf( arguments.targetValue, arguments.validationData ) 
		);

		if ( !r ) {
			var args = {
				message        : "The '#arguments.field#' has an invalid type, expected type is #arguments.validationData#",
				field          : arguments.field,
				validationType : getName(),
				rejectedValue  : ( isSimpleValue( arguments.targetValue ) ? arguments.targetValue : "" ),
				validationData : arguments.validationData
			};
			var error = validationResult
				.newError( argumentCollection = args )
				.setErrorMetadata( { "type" : arguments.validationData } );
			validationResult.addError( error );
		}

		return r;
	}

}

RequiredIf fails in nested struct if the comparison is not in the same nested Struct

submitted:
var valid = validateOrFail(
target = rc,
constraints = {
"accountTypeID" : { "required" : true, "type" : "numeric" },
"accountHolder" : { "requiredif" : { "accountTypeID" : 4 }, "type" : "struct"},
"accountHolder.firstName" : { "required" : { "accountTypeID" : 4 }, "type" : "string", "size" : "1..50", "empty" : false }
});

Results: Fails because the variable [comparePropertyValue] doesn't exist

image

Variable VALIDATEMODEL is undefined.

Hi,

I've dropped cbvalidation into the modules folder and when I try to use the validator in any handler i get the following message:

Variable VALIDATEMODEL is undefined.

I'm currently running Coldfusion version 9,0,2,282541

Here's the valdiation script:

 <!---  validation rules / constraints --->
  <cfset local.rules = {
                password = {required=true, requiredMessage="Please enter a value"},
                confirm_password = {
                                    required=true, requiredMessage="Please enter a value",
                                    SameAs= "password", SameAsMessage= "Please enter a matching password"
                                }
         }>

  <!--- Validate --->
  <cfset local.validator = validateModel(rc, local.rules )>

Here's the stack trace:

coldfusion.runtime.UndefinedVariableException: Variable VALIDATEMODEL is undefined.
    at coldfusion.runtime.CfJspPage._get(CfJspPage.java:303)
    at coldfusion.runtime.CfJspPage._get(CfJspPage.java:283)
    at coldfusion.runtime.CfJspPage._autoscalarize(CfJspPage.java:1494)
    at coldfusion.runtime.CfJspPage._autoscalarize(CfJspPage.java:1471)
    at cfAuthController2ecfc96573382$funcPASSWORDRESETCONFIRMACTION.runFunction(D:\webpages\cms\handlers\AuthController.cfc:77)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:517)
    at coldfusion.runtime.CfJspPage._invokeUDF(CfJspPage.java:2547)
    at cfEventHandler2ecfc2062222502$func_PRIVATEINVOKER.runFunction(D:\webpages\cms\coldbox\system\EventHandler.cfc:85)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:517)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:496)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:355)
    at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2301)
    at cfController2ecfc1432567149$funcINVOKER.runFunction(D:\webpages\cms\coldbox\system\web\Controller.cfc:795)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:517)
    at coldfusion.runtime.CfJspPage._invokeUDF(CfJspPage.java:2547)
    at cfController2ecfc1432567149$func_RUNEVENT.runFunction(D:\webpages\cms\coldbox\system\web\Controller.cfc:633)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:517)
    at coldfusion.runtime.CfJspPage._invokeUDF(CfJspPage.java:2547)
    at cfController2ecfc1432567149$funcRUNEVENT.runFunction(D:\webpages\cms\coldbox\system\web\Controller.cfc:425)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:517)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:496)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:355)
    at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2301)
    at cfBootstrap2ecfc1889428779$funcPROCESSCOLDBOXREQUEST.runFunction(D:\webpages\cms\coldbox\system\Bootstrap.cfc:200)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220)
    at coldfusion.runtime.CfJspPage._invokeUDF(CfJspPage.java:2582)
    at cfBootstrap2ecfc1889428779$funcONREQUESTSTART.runFunction(D:\webpages\cms\coldbox\system\Bootstrap.cfc:359)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:491)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:337)
    at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2360)
    at cfapplication2ecfc1226568062$funcONREQUESTSTART.runFunction(D:\webpages\cms\application.cfc:94)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472)
    at coldfusion.runtime.UDFMethod$ReturnTypeFilter.invoke(UDFMethod.java:405)
    at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368)
    at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55)
    at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:321)
    at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:220)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:491)
    at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:337)
    at coldfusion.runtime.AppEventInvoker.invoke(AppEventInvoker.java:88)
    at coldfusion.runtime.AppEventInvoker.onRequestStart(AppEventInvoker.java:258)
    at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:349)
    at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)
    at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
    at coldfusion.filter.PathFilter.invoke(PathFilter.java:94)
    at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70)
    at coldfusion.filter.BrowserDebugFilter.invoke(BrowserDebugFilter.java:79)
    at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
    at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
    at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
    at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
    at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
    at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
    at coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:126)
    at coldfusion.CfmServlet.service(CfmServlet.java:200)
    at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
    at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
    at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
    at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
    at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
    at jrun.servlet.FilterChain.service(FilterChain.java:101)
    at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
    at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
    at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
    at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
    at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
    at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
    at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)

Any help would be much appreciated

Discrete and inList validations throw error if data element value is not simple value

What are the steps to reproduce this issue?

Discrete validation:

var validationResult = validate(
target = {
// passing userid as an empty array
"userid": []
},
constraints = {
"userid": { "required": true, "type": "integer","discrete": "gte:1" }
}
);

InList validation:

var validationResult = validate(
    target = {
        "userid": []
    },
    constraints = {
        "userid": { "required": true, "type": "integer","inList": "1,2,3,4,5" }
    }
);

What happens?

DiscreteValidator :

modules\cbvalidation\models\validators\DiscreteValidator.cfc:93
91: }
92: case "gte": {
93: r = ( arguments.targetValue gte operationValue );
94: break;
95: }

Error : "can't compare Complex Object Type Array with a String"

inList validator:

modules\cbvalidation\models\validators\InListValidator.cfc:45
43: listFindNoCase(
44: arguments.validationData,
45: arguments.targetValue
46: )
47: ) {

Error : Can't cast Complex Object Type Array to String

What were you expecting to happen?

Check for data element to be Simplevalue and return error accordingly before Validating.

Any logs, error output, etc?

DiscreteValidator :

modules\cbvalidation\models\validators\DiscreteValidator.cfc:93
91: }
92: case "gte": {
93: r = ( arguments.targetValue gte operationValue );
94: break;
95: }

inList validator:

modules\cbvalidation\models\validators\InListValidator.cfc:45
43: listFindNoCase(
44: arguments.validationData,
45: arguments.targetValue
46: )
47: ) {

Any other comments?

What versions are you using?

Operating System: … Windows 10
Package Version: … "cbvalidation":"^2.1.0+126"

i18n validation for multiple modules with seperate bundles

When using multiple modules in a ColdBox application that have module specific i18n resourceBundle declarations in ModuleConfig.cfc as follows:

i18n = {
	resourceBundles = {
		"myBundle" = "#moduleMapping#/includes/i18n/myBundle"
	}
};

i18n validations will only work with default bundle for the entire application and not for a module that has its own declared bundle.

When considering the IValidationResult function addError( required IValidationError error ) function in ValidationResult.cfc component, there is no way to pass the 'bundle' parameter to var message = resourceService.getResource function so that i18n validation can be targeted to a specific bundle. Ideally, one should be able to validate an object and pass a 'bundle' alias so that the i18n type validation can be validated against the correct bundle. eg,

var validationResults = validateModel(target=rc.objEntity, locale=i18n.getFWLocale(), bundle="myBundle");

I'm happy to take a stab at correcting this and creating a pull request.

Default locale for Coldbox validation

When validating in ColdBox, pull the current locale by default so you don't have to change this:

validateModel( user );

to this:

validateModel( target = user, locale = getFWLocale() );

everywhere in your code just to use the i18n Integration.

Allow for generic validation message defaults to be configured

Allow all the built-in validation messages stored in /coldbox/system/validation/validators to be overridden on a global level.
For instance, the MinValidator has a default error message of:

message="The '#arguments.field#' value is not greater than #arguments.validationData#"

but what if I wanted the MinValidator to say

"I'm sorry, but you need to enter a {field} value that is not smaller than {validationData}"

everywhere in the site without specifying a custom message in every entity?

Abstract all the default messages out of the validators and store them in the default config using the {placeHolder} method for everything. Let users override the default messages for each validator in the ColdBox config. This will allow for system-wide validation message overrides per type in one place. Something like:

validation = {
    defaultMessages = {
        required = "The '{field}' value is required",
        type = "The '{field}' has an invalid type, expected type is {validationData}",
        size = "The '{field}' values is not in the required size range ({validationData})",
        range = "The '{field}' value is not the value field range ({validationData})"
    }
}

Additionally, create some new conventions to overriding default validator messages by constraint type with resource bundles. For instance, this would allow you to specify the default Spanish message for a required field once in your resource bundle for the entire site. I'm thinking something like this in your resource bundle:

cb_defaultValidationMessage.required = The 'field}' value is required
cb_defaultValidationMessage.type = The '{field}' has an invalid type, expected type is {validationData}
cb_defaultValidationMessage.size = The '{field}' values is not in the required size range ({validationData})
cb_defaultValidationMessage.range = The '{field}' value is not the value field range ({validationData})

So the order of validation message lookups would be like so ({placeHolder} replacements would be supported at all levels):

Custom message in the constraint

Custom message in resource bundle for that specific entity, property, type

Generic resource bundle for that validation type

Custom ColdBox app setting for global message for that validation type

Default message for that validation type

Add notSameAs and notSameAsNoCase validators

We are running into instances where you might want to validate two different fields to ensure they are not the same. Currently, you have to create a UDF for this. cbValidation already has sameAs and sameAsNoCase validators. We should add NOT validators to prevent the need for a UDF on these.

this.constraints = {
      "email": { required: true, type: "email" },
      "email2": { required: true, type: "email", notSameAsNoCase: "email" }
};

Type Validation fails on empty string even when not required

The following property declaration:

   property name="email"
                type="string"
                ormtype="string"
                default="";

with the following validation rule:

"email"         : {
            "required"      : false,
            "type"          : "email"
}

Will throw an error because the empty strings are validate-able and even an explicit null casting still returns an empty string on the getter.

Suggestion:

  • Igore empty strings for type validation when required is false
    or
  • Add an ignoreEmpty validation configuration option

suggestion: support dynamic `udfMessage`

Would like to do the following, where the udf message isn't baked at time of construction:

function getValidationConstraints() {
    var msg = "";
    return {
        foo: {
            udf: (v) => {
                if (v.x && v.y && !v.z) {
                    msg = "if x and y then z must be";
                    return false;
                }
                else if (v.x && !v.y && v.z) {
                    msg = "if x and not y, but z, then no";
                    return false;
                }
                // etc.
            }
            udfMessage: () => msg
        }
    }
}

Existing, but empty, values fail `required` checks

validateOrFail(constraints = {a: {required:true}}, target = {a: []}) // fails
validateOrFail(constraints = {a: {required:true}}, target = {a: [42]}) // passes
validateOrFail(constraints = {a: {required:true}}, target = {a: ""}) // fails
validateOrFail(constraints = {a: {required:true}}, target = {a: "42"}) // passes

I propose that all of the above should pass, because property a is present.

ValidationResult.newError() issue

I ran into what I think is a minor bug in ValidationResult.newError() recently. Before I made any changes I wanted to make sure that I wasn't just missing something.

The method currently looks like

IValidationError function newError( struct properties ){
    return duplicate( errorTemplate ).configure(argumentCollection=arguments);
}

This throws an error though because the the configure method expects individual paramaters and not a structure like properties. I think a fix would look something like

IValidationError function newError( struct properties ){
    return duplicate( errorTemplate ).configure(argumentCollection=properties);
}

Would this be worth pull requesting or am I doing something wrong?

Empty string is incorrectly validated as an integer

Summary

CBvalidation validates an empty string as a valid integer
Enviroment:
cfengine: [email protected]
coldbox: 6.0.0
cbvalidation: 2.2.0

Example

Page argument is optional, but if passed it should be valid integer gte 1.

Validation constraint:
page : {
type : "integer",
required : false,
discrete : "gte:1"
}

When calling an endpoint with an empty page argument:
https://localhost:8443/api/v1/relationship/blocks/page/

The expected behaviour/response:

Trigger invalid type validation error {"validation":[{"code":1,"field":"page"}]}
OR competely ignore page variable as having been passed.

Actual behaviour:

Page="" , an empty string is validated as an integer.

Reason:

webroot.modules.cbvalidation.models.validators.TypeValidator
should fail as the page variable should be an integer, but is passed a string.

Line 55: in the TypeValidator skips further processing if len==0:

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

This change appears to have been introduced in February:
f9e4b72#diff-9f977c8314a5c9fa133bad92cd8269d7

This appears to be a bug in CBValidator: Passing a string (even if empty) does not make it an integer

Version 1.5 errors if handler doesn't have Validate() method

This version's mixin is causing errors because its looking for this.validate() and its looking in the handler, not in the mixin file itself.

Had to revert code.

@lmajano

EXCEPTION(most recent call first)
expression Error
component [modules_app.api.modules.v1.handlers.Cabins] has no  function with name [validate] 
modules/cbvalidation/models/Mixins.cfm in validateModel at line 57
	string includeFields=""
){
	return this.validate( argumentCollection=arguments );
}
modules_app/api/modules/v1/handlers/Cabins.cfc in index at line 68
			tnsReqSeq      = { required : false }
		};
		var vResults = validateModel( target=rc, constraints=vConstraints );
		if( vResults.hasErrors() ){
			prc.response.setError( true )```

[Documentation] InList Validator Should Mention It Is Not Case Sensitive

Normally, I would submit the change request in GitBook, but for some reason I no longer have access.

Since the inList validator is not case sensitive, I think it would be a good idea to mention this in the Docs. Specifically, I would change this:

The field must be in the included list. Note: This validator will ignore values that are null or empty strings.

to this:

The field value must be in the included list. It is not case sensitive. Note: This validator will ignore values that are null or empty strings.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.