Validatable Delegate
Using the Validatable delegate for object validation
The Validatable@cbValidation
delegate (ColdBox 7+) allows you to add validation capabilities directly to any object using ColdBox's delegation pattern. This provides a cleaner, more object-oriented approach to validation.
Overview
Instead of injecting the ValidationManager
into every class, you can delegate validation methods directly to your objects. This is available in ColdBox 7 and later.
Basic Setup
Shorthand Syntax
The simplest way to make an object validatable:
class delegates="Validatable@cbValidation" {
property name="id" type="numeric";
property name="name" type="string";
property name="email" type="string";
this.constraints = {
name: { required: true, size: "2..100" },
email: { required: true, type: "email" }
};
}
Selective Method Delegation
Delegate only specific validation methods:
class delegates="Validatable@cbValidation=validate,validateOrFail" {
property name="sku" type="string";
property name="price" type="numeric";
}
// Only add validate and validateOrFail methods
component delegates="Validatable@cbValidation=validate,validateOrFail" {
property name="sku" type="string";
property name="price" type="numeric";
}
Long Syntax with Property Injection
For more control, use explicit property delegation:
class {
property name="validatable"
inject="Validatable@cbValidation"
delegate="validate,validateOrFail";
property name="orderNumber" type="string";
property name="items" type="array";
this.constraints = {
orderNumber: { required: true },
items: { required: true, arrayItem: {...} }
};
}
Available Delegated Methods
When using the Validatable delegate, the following methods are available:
validate()
- Validate and return result objectvalidateOrFail()
- Validate or throw exceptionisValid()
- Quick boolean check (stores results)getValidationResults()
- Get stored validation resultsvalidateHasValue()
- Check if a value existsvalidateIsNullOrEmpty()
- Check if value is null/emptyassert()
- Assert a condition is truegetValidationManager()
- Access the ValidationManager
Using Delegated Validation Methods
Validate Method
function saveUser(event, rc, prc) {
var user = entityNew("User");
populateModel(user);
// Call validate() directly on the object
var results = user.validate();
if (results.hasErrors()) {
prc.errors = results.getAllErrors();
return event.setView("user/form");
}
entitySave(user);
return event.setNextRoute("user.view");
}
ValidateOrFail Method
For API endpoints with exception handling:
function apiCreateUser(event, rc, prc) {
var user = entityNew("User");
populateModel(user);
try {
// validateOrFail throws exception if validation fails
user.validateOrFail();
entitySave(user);
return event.renderData(data: user);
} catch(ValidationException e) {
return event.renderData(
statusCode: 422,
data: { errors: deserializeJSON(e.extendedInfo) }
);
}
}
IsValid Method
Quick validation with stored results:
function processUser(event, rc, prc) {
var user = entityNew("User");
populateModel(user);
// isValid() stores results and returns boolean
if (user.isValid()) {
// User is valid, proceed
userService.create(user);
} else {
// Access stored results
var results = user.getValidationResults();
prc.errors = results.getAllErrors();
}
}
Advanced Usage
Validation with Profiles
Pass profiles for targeted validation:
component delegates="Validatable@cbValidation" {
property name="name" type="string";
property name="email" type="string";
property name="password" type="string";
this.constraints = {
name: { required: true },
email: { required: true, type: "email" },
password: { required: true, size: "8..50" }
};
this.constraintProfiles = {
registration: "name,email,password",
update: "name,email",
passwordChange: "password"
};
}
// In handler:
function updateUser(event, rc, prc) {
var user = userService.getById(rc.userId);
populateModel(user);
// Validate only update profile fields
if (user.isValid(profiles: "update")) {
userService.update(user);
}
}
Custom Validation with Callbacks
Combine validation with business logic:
component delegates="Validatable@cbValidation" {
property name="sku" type="string";
property name="price" type="numeric";
this.constraints = {
sku: { required: true, regex: "^[A-Z0-9]+$" },
price: { required: true, min: 0.01 }
};
// Custom validation method
public void function validateUniqueSku() {
if (productService.skuExists(this.sku)) {
throw("ValidationException", "SKU '#sku#' already exists");
}
}
}
// In handler:
function createProduct(event, rc, prc) {
var product = entityNew("Product");
populateModel(product);
try {
product.validateOrFail();
product.validateUniqueSku(); // Custom validation
productService.create(product);
return event.setNextRoute("product.view");
} catch(ValidationException e) {
prc.errors = [e.message];
}
}
Best Practices
1. Use Shorthand for Full Delegation
For simple validation needs, use the shorthand syntax:
component delegates="Validatable@cbValidation" {
// All validation methods available
}
2. Use Selective Delegation for Lightweight Objects
For objects that only need specific methods:
component delegates="Validatable@cbValidation=validate,isValid" {
// Only these methods available
}
3. Always Define Constraints
Ensure your object has constraints defined:
component delegates="Validatable@cbValidation" {
this.constraints = {
// Define all constraints here
};
}
4. Use isValid() for Simple Checks
For quick validation without error details:
if (user.isValid()) {
processUser(user);
}
5. Use validateOrFail() for APIs
For REST endpoints where you need exception handling:
try {
user.validateOrFail();
// Process user
} catch(ValidationException e) {
return errorResponse(e);
}
6. Combine with Custom Methods
Add custom validation logic to your objects:
public boolean function isEligible() {
return this.age >= 18 && this.isValid(profiles="eligibility");
}
Supported ColdBox Versions
The Validatable delegate requires:
ColdBox 7.0+
cbValidation 4.1.0+
For earlier ColdBox versions, use the mixin methods via validate()
and validateOrFail()
.
See Also
Installation & Mixins - Mixin methods for handlers, views, interceptors
Validation Results - Understanding validation result objects
Custom Validators - Creating custom validation logic
Last updated
Was this helpful?