Skip to content

Commit 615d912

Browse files
committed
Merge branch 'development'
2 parents 93ce81e + 391495f commit 615d912

21 files changed

+566
-66
lines changed

box.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name":"ColdBox Validation",
33
"author":"Ortus Solutions <[email protected]>",
4-
"version":"4.0.0",
4+
"version":"4.1.0",
55
"location":"https://downloads.ortussolutions.com/ortussolutions/coldbox-modules/cbvalidation/@build.version@/[email protected]@.zip",
66
"slug":"cbvalidation",
77
"type":"modules",

build/Build.cfc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,7 @@ component {
130130
)
131131
.toConsole();
132132

133-
// Prepare exports directory
134-
variables.exportsDir = variables.artifactsDir & "/#projectName#/#arguments.version#";
135-
directoryCreate( variables.exportsDir, true, true );
133+
ensureExportDir( argumentCollection = arguments );
136134

137135
// Project Build Dir
138136
variables.projectBuildDir = variables.buildDir & "/#projectName#";
@@ -200,11 +198,12 @@ component {
200198
version = "1.0.0",
201199
outputDir = ".tmp/apidocs"
202200
){
201+
ensureExportDir( argumentCollection = arguments );
202+
203203
// Create project mapping
204204
fileSystemUtil.createMapping( arguments.projectName, variables.cwd );
205205
// Generate Docs
206206
print.greenLine( "Generating API Docs, please wait..." ).toConsole();
207-
directoryCreate( arguments.outputDir, true, true );
208207

209208
command( "docbox generate" )
210209
.params(
@@ -315,4 +314,18 @@ component {
315314
return ( createObject( "java", "java.lang.System" ).getProperty( "cfml.cli.exitCode" ) ?: 0 );
316315
}
317316

317+
/**
318+
* Ensure the export directory exists at artifacts/NAME/VERSION/
319+
*/
320+
private function ensureExportDir(
321+
required projectName,
322+
version = "1.0.0"
323+
){
324+
if ( structKeyExists( variables, "exportsDir" ) && directoryExists( variables.exportsDir ) ){
325+
return;
326+
}
327+
// Prepare exports directory
328+
variables.exportsDir = variables.artifactsDir & "/#projectName#/#arguments.version#";
329+
directoryCreate( variables.exportsDir, true, true );
330+
}
318331
}

changelog.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
----
99

10+
## [4.1.0] => 2022-NOV-14
11+
12+
### Added
13+
14+
* New ColdBox 7 delegate: `Validatable@cbValidation` which can be used to make objects validatable
15+
* New validators: `notSameAs, notSameAsNoCase`
16+
17+
### Changed
18+
19+
* All date comparison validators now validate as `false` when the comparison target dates values are NOT dates instead of throwing an exception.
20+
21+
----
22+
1023
## [4.0.0] => 2022-OCT-10
1124

1225
### Added
@@ -64,7 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6477

6578
----
6679

67-
## [3.1.0] => 2021-MAY-17
80+
## [3.1.1] => 2021-MAY-17
6881

6982
### Fixed
7083

helpers/Mixins.cfm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ boolean function validateHasValue( any targetValue ){
7373
* @targetValue the value to check for nullness/emptyness
7474
*/
7575
boolean function validateIsNullOrEmpty( any targetValue ){
76-
return getValidationManager().getValidator( "Required", {} ).hasValue( argumentCollection = arguments );
76+
return !getValidationManager().getValidator( "Required", {} ).hasValue( argumentCollection = arguments );
7777
}
7878
7979
/**

models/delegates/Validatable.cfc

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* Copyright since 2016 by Ortus Solutions, Corp
3+
* www.ortussolutions.com
4+
* ---
5+
* This delegate helps models validate themselves
6+
*/
7+
component accessors="true" {
8+
9+
// DI
10+
property name="validationManager" inject="ValidationManager@cbvalidation";
11+
12+
// Properties
13+
property name="validationResults";
14+
15+
/**
16+
* Validate the $parent and stores a validation result in the delegate
17+
*
18+
* @fields One or more fields to validate on, by default it validates all fields in the constraints. This can be a simple list or an array.
19+
* @constraints An optional shared constraints name or an actual structure of constraints to validate on.
20+
* @locale An optional locale to use for i18n messages
21+
* @excludeFields An optional list of fields to exclude from the validation.
22+
* @IncludeFields An optional list of fields to include in the validation.
23+
* @profiles If passed, a list of profile names to use for validation constraints
24+
*/
25+
boolean function isValid(
26+
string fields = "*",
27+
any constraints = "",
28+
string locale = "",
29+
string excludeFields = "",
30+
string includeFields = "",
31+
string profiles = ""
32+
){
33+
// validate and save results in private scope
34+
variables.validationResults = validate( argumentCollection = arguments );
35+
36+
// return it
37+
return ( !variables.validationResults.hasErrors() );
38+
}
39+
40+
/**
41+
* Get the validation results object. This will be an empty validation object if isValid() has not being called yet.
42+
*
43+
* @return cbvalidation.models.result.IValidationResult
44+
*/
45+
any function getValidationResults(){
46+
if ( !isNull( variables.validationResults ) && isObject( variables.validationResults ) ) {
47+
return variables.validationResults;
48+
}
49+
return new cbvalidation.models.result.ValidationResult();
50+
}
51+
52+
/**
53+
* Validate the parent delegate
54+
*
55+
* @fields The fields to validate on the target. By default, it validates on all fields
56+
* @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
57+
* @locale The i18n locale to use for validation messages
58+
* @excludeFields The fields to exclude from the validation
59+
* @includeFields The fields to include in the validation
60+
* @profiles If passed, a list of profile names to use for validation constraints
61+
*
62+
* @return cbvalidation.model.result.IValidationResult
63+
*/
64+
function validate(){
65+
arguments.target = $parent;
66+
return variables.validationManager.validate( argumentCollection = arguments );
67+
}
68+
69+
/**
70+
* Validate an object or structure according to the constraints rules and throw an exception if the validation fails.
71+
* The validation errors will be contained in the `extendedInfo` of the exception in JSON format
72+
*
73+
* @fields The fields to validate on the target. By default, it validates on all fields
74+
* @constraints A structure of constraint rules or the name of the shared constraint rules to use for validation
75+
* @locale The i18n locale to use for validation messages
76+
* @excludeFields The fields to exclude from the validation
77+
* @includeFields The fields to include in the validation
78+
* @profiles If passed, a list of profile names to use for validation constraints
79+
*
80+
* @return The validated object or the structure fields that where validated
81+
*
82+
* @throws ValidationException
83+
*/
84+
function validateOrFail(){
85+
arguments.target = $parent;
86+
return variables.validationManager.validateOrFail( argumentCollection = arguments );
87+
}
88+
89+
/**
90+
* Verify if the target value has a value
91+
* Checks for nullness or for length if it's a simple value, array, query, struct or object.
92+
*/
93+
boolean function validateHasValue( any targetValue ){
94+
return variables.validationManager
95+
.getValidator( "Required", {} )
96+
.hasValue( argumentCollection = arguments );
97+
}
98+
99+
/**
100+
* Check if a value is null or is a simple value and it's empty
101+
*
102+
* @targetValue the value to check for nullness/emptyness
103+
*/
104+
boolean function validateIsNullOrEmpty( any targetValue ){
105+
return !variables.validationManager
106+
.getValidator( "Required", {} )
107+
.hasValue( argumentCollection = arguments );
108+
}
109+
110+
/**
111+
* This method mimics the Java assert() function, where it evaluates the target to a boolean value and it must be true
112+
* to pass and return a true to you, or throw an `AssertException`
113+
*
114+
* @target The tareget to evaluate for being true
115+
* @message The message to send in the exception
116+
*
117+
* @return True, if the target is a non-null value. If false, then it will throw the `AssertError` exception
118+
*
119+
* @throws AssertException if the target is a false or null value
120+
*/
121+
boolean function assert( target, message = "" ){
122+
if ( !isNull( arguments.target ) && arguments.target ) {
123+
return true;
124+
}
125+
throw(
126+
type : "AssertException",
127+
message: len( arguments.message ) ? arguments.message : "Assertion failed from #callStackGet()[ 2 ].toString()#"
128+
);
129+
}
130+
131+
}

models/validators/AfterOrEqualValidator.cfc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,22 @@ component extends="BaseValidator" accessors="true" singleton {
3838
if ( isNull( arguments.targetValue ) || isNullOrEmpty( arguments.targetValue ) ) {
3939
return true;
4040
}
41-
// If not a date, throw it
41+
42+
// If not a date, invalide it
4243
if ( !isDate( arguments.targetValue ) ) {
43-
throw(
44-
message = "The date you sent is an invalid date [#arguments.targetValue#]",
45-
type = "InvalidValidationData"
44+
validationResult.addError(
45+
validationResult.newError(
46+
argumentCollection = {
47+
message : "The '#arguments.targetValue#' is not a valid date, so we cannot compare them.",
48+
field : arguments.field,
49+
validationType : getName(),
50+
rejectedValue : ( arguments.targetValue ),
51+
validationData : arguments.validationData,
52+
errorMetadata : { "afterOrEqual" : arguments.targetValue }
53+
}
54+
)
4655
);
56+
return false;
4757
}
4858

4959
// The compare value is set or it can be another field

models/validators/AfterValidator.cfc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,22 @@ component extends="BaseValidator" accessors="true" singleton {
3838
if ( isNull( arguments.targetValue ) || isNullOrEmpty( arguments.targetValue ) ) {
3939
return true;
4040
}
41-
// If target is not a date, throw it
41+
42+
// If target is not a date, invalidate it
4243
if ( !isDate( arguments.targetValue ) ) {
43-
throw(
44-
message = "The date you sent is an invalid date [#arguments.targetValue#]",
45-
type = "InvalidValidationData"
44+
validationResult.addError(
45+
validationResult.newError(
46+
argumentCollection = {
47+
message : "The '#arguments.targetValue#' is not a valid date, so we cannot compare them.",
48+
field : arguments.field,
49+
validationType : getName(),
50+
rejectedValue : ( arguments.targetValue ),
51+
validationData : arguments.validationData,
52+
errorMetadata : { "afterOrEqual" : arguments.targetValue }
53+
}
54+
)
4655
);
56+
return false;
4757
}
4858

4959
// The compare value is set or it can be another field

models/validators/BeforeOrEqualValidator.cfc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,19 @@ component extends="BaseValidator" accessors="true" singleton {
4040
}
4141
// If not a date, throw it
4242
if ( !isDate( arguments.targetValue ) ) {
43-
throw(
44-
message = "The date you sent is an invalid date [#arguments.targetValue#]",
45-
type = "InvalidValidationData"
43+
validationResult.addError(
44+
validationResult.newError(
45+
argumentCollection = {
46+
message : "The '#arguments.targetValue#' is not a valid date, so we cannot compare them.",
47+
field : arguments.field,
48+
validationType : getName(),
49+
rejectedValue : ( arguments.targetValue ),
50+
validationData : arguments.validationData,
51+
errorMetadata : { "afterOrEqual" : arguments.targetValue }
52+
}
53+
)
4654
);
55+
return false;
4756
}
4857

4958
// The compare value is set or it can be another field

models/validators/BeforeValidator.cfc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,19 @@ component extends="BaseValidator" accessors="true" singleton {
4040
}
4141
// If not a date, throw it
4242
if ( !isDate( arguments.targetValue ) ) {
43-
throw(
44-
message = "The date you sent is an invalid date [#arguments.targetValue#]",
45-
type = "InvalidValidationData"
43+
validationResult.addError(
44+
validationResult.newError(
45+
argumentCollection = {
46+
message : "The '#arguments.targetValue#' is not a valid date, so we cannot compare them.",
47+
field : arguments.field,
48+
validationType : getName(),
49+
rejectedValue : ( arguments.targetValue ),
50+
validationData : arguments.validationData,
51+
errorMetadata : { "afterOrEqual" : arguments.targetValue }
52+
}
53+
)
4654
);
55+
return false;
4756
}
4857

4958
// The compare value is set or it can be another field

models/validators/DateEqualsValidator.cfc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,22 @@ component extends="BaseValidator" accessors="true" singleton {
3838
if ( isNull( arguments.targetValue ) || isNullOrEmpty( arguments.targetValue ) ) {
3939
return true;
4040
}
41+
4142
// If not a date, throw it
4243
if ( !isDate( arguments.targetValue ) ) {
43-
throw(
44-
message = "The date you sent is an invalid date [#arguments.targetValue#]",
45-
type = "InvalidValidationData"
44+
validationResult.addError(
45+
validationResult.newError(
46+
argumentCollection = {
47+
message : "The '#arguments.targetValue#' is not a valid date, so we cannot compare them.",
48+
field : arguments.field,
49+
validationType : getName(),
50+
rejectedValue : ( arguments.targetValue ),
51+
validationData : arguments.validationData,
52+
errorMetadata : { "afterOrEqual" : arguments.targetValue }
53+
}
54+
)
4655
);
56+
return false;
4757
}
4858

4959
// The compare value is set or it can be another field

0 commit comments

Comments
 (0)