diff --git a/models/Component.cfc b/models/Component.cfc
index 606bf24..9912825 100644
--- a/models/Component.cfc
+++ b/models/Component.cfc
@@ -360,7 +360,7 @@ component output="true" accessors="true" {
// Determine if component should be lazy loaded
// If lazy parameter is explicitly provided, use that value
// Otherwise, use the component's lazy preference
- local.shouldLazyLoad = isNull( arguments.lazy ) ?
+ local.shouldLazyLoad = isNull( arguments.lazy ) ?
local.instance._getLazyLoad() : // Use component's preference if no explicit parameter
arguments.lazy; // Use explicit parameter value
@@ -1115,7 +1115,9 @@ component output="true" accessors="true" {
function _getConstraints(){
if ( variables.keyExists( "constraints" ) ) {
return variables.constraints;
- }
+ }else if ( structKeyExists( this, "constraints" ) ) {
+ return this.constraints;
+ }
return [:];
}
diff --git a/models/services/ValidationService.cfc b/models/services/ValidationService.cfc
index 81b2dc2..0894415 100644
--- a/models/services/ValidationService.cfc
+++ b/models/services/ValidationService.cfc
@@ -45,8 +45,12 @@ component accessors="true" singleton {
* @return ValidationResult The result of the validation operation.
*/
function validate( wire, target, fields, constraints, locale, excludeFields, includeFields, profiles ){
- arguments.target = isNull( arguments.target ) ? arguments.wire._getDataProperties() : arguments.target;
- arguments.constraints = isNull( arguments.constraints ) ? arguments.wire._getConstraints() : arguments.constraints;
+ if( isNull( arguments.target ) ){
+ // if no target is provided, default to the wire's data properties
+ arguments.target = arguments.wire._getDataProperties();
+ // use the wire's constraints if explicit constraints are not provided
+ arguments.constraints = isNull( arguments.constraints ) ? arguments.wire._getConstraints() : arguments.constraints
+ }
return getManager().validate( argumentCollection = arguments );
}
diff --git a/test-harness/models/validationTest.cfc b/test-harness/models/validationTest.cfc
new file mode 100644
index 0000000..d172f17
--- /dev/null
+++ b/test-harness/models/validationTest.cfc
@@ -0,0 +1,21 @@
+component accessors="true" {
+
+ property name="FirstName";
+ property name="LastName";
+
+ this.constraints = {
+ FirstName : {
+ required : true,
+ requiredMessage : "First name is required",
+ size : "2..50",
+ sizeMessage : "First name must be 2-50 characters"
+ },
+ LastName : {
+ required : true,
+ requiredMessage : "Last name is required",
+ size : "2..50",
+ sizeMessage : "Last name must be 2-50 characters"
+ }
+ };
+
+}
\ No newline at end of file
diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc
index 5c5aafe..a90b7ea 100644
--- a/test-harness/tests/specs/CBWIRESpec.cfc
+++ b/test-harness/tests/specs/CBWIRESpec.cfc
@@ -575,9 +575,26 @@ component extends="coldbox.system.testing.BaseTestCase" {
);
expect( renderedHtml ).toInclude( 'Some#x20;text#x20;with#x20;#x5c;"quotes' );
- });
+ } );
+
+ it( "should get constraints when set using this.constraints=", function() {
+ var testValidationComponent = getInstance("wires.test.validation.validateConstraints1");
+ var constraints = testValidationComponent._getConstraints();
+ expect( constraints ).toBeTypeOf( "struct" );
+ expect( constraints ).toHaveLength( 1 );
+ expect( constraints ).toHaveKey( "firstname" );
+ } );
+
+ it( "should get constraints when set using constraints=", function() {
+ var testValidationComponent = getInstance("wires.test.validation.validateConstraints2");
+ var constraints = testValidationComponent._getConstraints();
+ expect( constraints ).toBeTypeOf( "struct" );
+ expect( constraints ).toHaveLength( 1 );
+ expect( constraints ).toHaveKey( "firstname" );
+ } );
- });
+
+ } );
describe("Incoming Requests", function() {
@@ -727,7 +744,7 @@ component extends="coldbox.system.testing.BaseTestCase" {
var settings = getInstance( "coldbox:modulesettings:cbwire" );
var originalSetting = settings.csrfEnabled;
settings.csrfEnabled = false;
-
+
var payload = incomingRequest(
memo = {
"name": "TestComponent",
@@ -747,12 +764,12 @@ component extends="coldbox.system.testing.BaseTestCase" {
updates = {},
csrfToken = "badToken"
);
-
+
// Should not throw an error even with bad token when CSRF is disabled
var response = cbwireController.handleRequest( payload, event );
expect( isStruct( response ) ).toBeTrue();
expect( response.components[1].effects.html ).toInclude( "CBWIRE Slays!" );
-
+
// Restore original setting
settings.csrfEnabled = originalSetting;
} );
@@ -761,10 +778,10 @@ component extends="coldbox.system.testing.BaseTestCase" {
var settings = getInstance( "coldbox:modulesettings:cbwire" );
var originalSetting = settings.csrfEnabled;
settings.csrfEnabled = false;
-
+
var token = cbwireController.generateCSRFToken();
expect( token ).toBe( "" );
-
+
// Restore original setting
settings.csrfEnabled = originalSetting;
} );
diff --git a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc
index 559acf2..83f9b5b 100644
--- a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc
+++ b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc
@@ -40,7 +40,8 @@ component extends="coldbox.system.testing.BaseTestCase" {
});
describe( "validate()", function() {
- it( "should validate with given target and constraints", function() {
+
+ it( "should validate with given target and constraints", function() {
var wire = {};
var target = { "foo": "bar" };
var constraints = { "foo": { "required": true } };
@@ -61,6 +62,83 @@ component extends="coldbox.system.testing.BaseTestCase" {
var result = validationService.validate( wire );
expect( result ).toHaveKey( "ok" );
});
+
+ it( "should validate an object other than the wire itself", function() {
+ var oValidationTest = getInstance( "validationTest" );
+ var wire = prepareMock( createStub() );
+ wire.$( "_getDataProperties", { "bar": "baz" } );
+ wire.$( "_getConstraints", { "bar": { "required": true } } );
+ // mock the validate method to return the arguments passed to it so that
+ // we can validate that the correct mutation of the arguments is occurring
+ // in the validate() method of the service
+ mockValidationManager.$(
+ method = "validate",
+ callback = function() {
+ return arguments;
+ }
+ );
+ var result = validationService.validate( wire=wire, target=oValidationTest );
+ // validate that we do not have the wires constraints and that there
+ // are no constraints passed to validate() method so that the constraints
+ // from the object will be used
+ expect( result ).notToHaveKey( "constraints" );
+ // validate that we have a target passed into the validate method
+ expect( result ).toHaveKey( "target" );
+ // validate that the target contains the constraints from the object
+ expect( result.target ).toHaveKey( "constraints" );
+ expect( result.target.constraints ).toBeTypeOf( "struct" );
+ expect( result.target.constraints ).toHaveLength( 2 );
+ expect( result.target.constraints ).toHaveKey( "firstname" );
+ expect( result.target.constraints ).toHaveKey( "lastname" );
+ expect( result.target.constraints ).notToHaveKey( "bar" );
+ // get the metadata of the target to validate that it is the correct object and not the wire
+ var resultTargetMetaData = getMetadata( result.target );
+ // validate that the target metadata contains the name of the component (validationTest)
+ expect( resultTargetMetaData ).toHaveKey( "name" );
+ expect( resultTargetMetaData.name ).toInclude( "validationTest" );
+ });
+
+ it( "shoud validate an object other than the wire itself with custom validation constraints", function() {
+ var oValidationTest = getInstance( "validationTest" );
+ var wire = prepareMock( createStub() );
+ wire.$( "_getDataProperties", { "bar": "baz" } );
+ wire.$( "_getConstraints", { "bar": { "required": true } } );
+ var customConstraints = {
+ password : {
+ required : true,
+ requiredMessage : "Password is required",
+ size : "8..50",
+ sizeMessage : "Password must be 8-50 characters"
+ }
+ };
+ // mock the validate method to return the arguments passed to it so that
+ // we can validate that the correct mutation of the arguments is occurring
+ // in the validate() method of the service
+ mockValidationManager.$(
+ method = "validate",
+ callback = function() {
+ return arguments;
+ }
+ );
+ var result = validationService.validate( wire=wire, target=oValidationTest, constraints=customConstraints );
+ // validate that we do not have the wires constraints and that the constraints
+ // passed to the validate() method are the custom constraints and not the objects
+ // or wires constraints
+ expect( result ).toHaveKey( "constraints" );
+ expect( result.constraints ).toBeTypeOf( "struct" );
+ expect( result.constraints ).toHaveLength( 1 );
+ expect( result.constraints ).toHaveKey( "password" );
+ expect( result.constraints ).notToHaveKey( "lastname" );
+ expect( result.constraints ).notToHaveKey( "bar" );
+ // validate that we have a target passed into the validate method
+ expect( result ).toHaveKey( "target" );
+ // get the metadata of the target to validate that it is the correct object and not the wire
+ var resultTargetMetaData = getMetadata( result.target );
+ // validate that the target metadata contains the name of the component (validationTest)
+ expect( resultTargetMetaData ).toHaveKey( "name" );
+ expect( resultTargetMetaData.name ).toInclude( "validationTest" );
+ });
+
});
describe( "validateOrFail()", function() {
diff --git a/test-harness/wires/test/validation/validateConstraints1.cfc b/test-harness/wires/test/validation/validateConstraints1.cfc
new file mode 100644
index 0000000..70d89dd
--- /dev/null
+++ b/test-harness/wires/test/validation/validateConstraints1.cfc
@@ -0,0 +1,20 @@
+component extends="cbwire.models.Component" {
+
+ data = {
+ "firstname": "sdfsad",
+ "lastname": ""
+ };
+ /*
+ This components DOES use this.constraints=
+
+ The cbwire documentation states that you can define constraints using constraints=
+ https://cbwire.ortusbooks.com/features/form-validation
+
+ CBValidation documentation states that you define constraints using this.constraints=
+ https://coldbox-validation.ortusbooks.com/overview/declaring-constraints/domain-object
+ */
+ this.constraints = {
+ "firstname": { required: true }
+ };
+
+}
\ No newline at end of file
diff --git a/test-harness/wires/test/validation/validateConstraints1.cfm b/test-harness/wires/test/validation/validateConstraints1.cfm
new file mode 100644
index 0000000..3534b82
--- /dev/null
+++ b/test-harness/wires/test/validation/validateConstraints1.cfm
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test-harness/wires/test/validation/validateConstraints2.cfc b/test-harness/wires/test/validation/validateConstraints2.cfc
new file mode 100644
index 0000000..2955ebe
--- /dev/null
+++ b/test-harness/wires/test/validation/validateConstraints2.cfc
@@ -0,0 +1,20 @@
+component extends="cbwire.models.Component" {
+
+ data = {
+ "firstname": "sdfsad",
+ "lastname": ""
+ };
+ /*
+ This components DOES use constraints=
+
+ The cbwire documentation states that you can define constraints using constraints=
+ https://cbwire.ortusbooks.com/features/form-validation
+
+ CBValidation documentation states that you define constraints using this.constraints=
+ https://coldbox-validation.ortusbooks.com/overview/declaring-constraints/domain-object
+ */
+ constraints = {
+ "firstname": { required: true }
+ };
+
+}
\ No newline at end of file
diff --git a/test-harness/wires/test/validation/validateConstraints2.cfm b/test-harness/wires/test/validation/validateConstraints2.cfm
new file mode 100644
index 0000000..3534b82
--- /dev/null
+++ b/test-harness/wires/test/validation/validateConstraints2.cfm
@@ -0,0 +1,6 @@
+
+