Validation Plugin

2 views
Skip to first unread message

Tony Nelson

unread,
Jun 19, 2011, 1:19:20 PM6/19/11
to ColdMVC
In case you care, I completely rewrote the ColdMVC Validation plugin
(https://github.com/tonynelson19/ColdMVC-Validation). Most notably, I
removed the client-side validation, since it didn't really work that
well (or at all). I'd like to re-add it in the future, but I need to
figure out the best approach first.

It's based on Hibernate Validator (http://www.hibernate.org/
subprojects/validator.html) and works pretty similar to Hyrule (btw
nice work Dan), but has pretty strong hooks into ColdMVC, which is why
it doesn't use Hyrule directly. As an aside, I plan on creating
ColdMVC plugins for both Hyrule and ValidateThis in the future, since
people have their own preferences and they should be able to use what
they want to use.

Anywho, here's the gist on the validation plugin:

Install the plugin inside your plugins.cfm: <cfset add("validation") /
>.

Add annotations to your models. Here's a User entity:

/**
* @extends coldmvc.Model
* @persistent true
*/
component {

property id;

/**
* @required
*/
property firstName;

/**
* @required
*/
property lastName;

/**
* @required { "message": "Please enter an email address." }
* @email
*/
property email;

/**
* @required
* @date
*/
property birthDate;

/**
* @range { "min": 18, "max": 25 }
*/
property age;

}

Validate your entities inside your actions using the validate model
helper added by the validation plugin. Here's a sample UserController
with an edit action that just posts a form back to itself:


/**
* @singleton
*/
component {

function pre() {

params.errors = [];

}

/**
* @validate { "User": "firstName, lastName, email" }
*/
function edit() {

var user = _User.new();

if (isPost()) {

user.populate(params.user);

var result = user.validate();

if (result.isValid()) {
user.save();
} else {
params.errors = result.getErrors();
}

}

params.user = user;

}

}

You'll notice the edit action has an @validate annotation. This is an
optional JSON string that allows for context-based validations for
entities. If an annotation isn't specified, the entire entity will be
validated. Another option is to pass in the properties that you'd like
to validate, such as user.validate("firstName,lastName,email"). The
annotation might become more useful if/when i figure out how to do
client-side validation.

The validation plugin comes with a handful of common constraints,
which are all located inside /validation/app/model/validation/
constraints/ (https://github.com/tonynelson19/ColdMVC-Validation/tree/
master/app/model/validation/constraints).

Most of the constraints currently just delegate to the valid helper
(https://github.com/tonynelson19/ColdMVC/blob/master/app/helpers/
valid.cfc).

If you want to create your own constraint, just create a CFC inside
your application's /app/model/validation/constraints/ directory and
the validation plugin will register it. The custom constraint just
needs to have a method named isValid that accepts a value, a rule, and
a model.

For an example of what a constraint looks like, here's the @required
constraint:

/**
* @constraint required
* @message The value for ${property} is required.
*/
component {

public boolean function isValid(required any value) {

if (!isSimpleValue(arguments.value)) {
return true;
}

if (arguments.value != "") {
return true;
}

return false;

}

}

The @constraint annotation is how the validator references your
constraint on properties. In this case, it will find any properties
annotated with @required. If you don't specify an @constraint
annotation, it will use name of the CFC. In this case, I could have
left off the @constraint and it would still be @required.

The @message annotation is the error message that gets returned if it
fails validation. It currently supports placeholders for ${Property}, $
{property}, and any dynamic rule values assigned using JSON syntax.
For example, the @range annotation displayed in the first example
above specifies a min and max value. These options are both available
inside the message as ${min} and ${max}. You can also use a custom
message on a per-property basis like is shown in the annotations for
the email property above. If you really want to get creative with
messages, just add a getMessage() method to your constraint and the
validator will call that whenever your validation fails.

All constrains are created as singletons within the validator and are
autowired by the bean factory. If you need access to outside services
or models inside your custom constraints, just add @accessors true to
the constraint and declare properties for them like you would on a
normal controller.

There's all custom tag for <c:errors /> that outputs params.errors
inside a <ul> tag. Might be convenient for most cases, use it if you
want to.

Also, the plugin will also display all registered constraints inside
the ColdMVC debug in case you want to verify that your custom
constraints are available or not.

Let me know if you have any questions or comments.

-Tony
Reply all
Reply to author
Forward
0 new messages