NAME
Validation::Class - Centralized Input Validation For Any Application
VERSION
version 1.112870
SYNOPSIS
use MyApp::Validation;
my $input = MyApp::Validation->new(params => $params);
unless ($input->validate){
return $input->errors->to_string;
}
DESCRIPTION
Important Note! Validation::Class just got alot more flexible which came
at the cost of losing the grouped parameters functionality. AGAIN,
grouped parameters are no longer supported using the old way of doing
things. Validation::Class now supports hash
serialization/deserialization which means that you can now set the
parameters using a hashref of nested hashrefs and validate against them,
or set the parameters using a hashref of (serialized)key/(non-ref)value
pairs and validate against that. This function is provided in
Validation::Class via Hash::Flatten.
DESCRIPTION
Validation::Class is a different approach to data validation, it
attempts to simplify and centralize data validation rules to ensure DRY
(don't repeat yourself) code. The primary intent of this module is to
provide a simplistic validation work-flow and promote code (validation)
reuse.
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
# a validation rule
field 'login' => {
label => 'user login',
error => 'login invalid',
validation => sub {
my ($self, $this, $fields) = @_;
return $this->{value} eq 'admin' ? 1 : 0;
}
};
# a validation rule
field 'password' => {
label => 'user password',
error => 'password invalid',
validation => sub {
my ($self, $this, $fields) = @_;
return $this->{value} eq 'pass' ? 1 : 0;
}
};
1;
BUILDING A VALIDATION CLASS
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
# a validation rule template
mixin 'basic' => {
required => 1,
min_length => 1,
max_length => 255,
filters => ['lowercase', 'alphanumeric']
};
# a validation rule
field 'user.login' => {
mixin => 'basic',
label => 'user login',
error => 'login invalid',
validation => sub {
my ($self, $this, $fields) = @_;
return $this->{value} eq 'admin' ? 1 : 0;
}
};
# a validation rule
field 'user.password' => {
mixin => 'basic',
label => 'user login',
error => 'login invalid',
validation => sub {
my ($self, $this, $fields) = @_;
return $this->{value} eq 'pass' ? 1 : 0;
}
};
1;
THE MIXIN KEYWORD
The mixin keyword creates a validation rules template that can be
applied to any field using the mixin directive.
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
mixin 'constrain' => {
required => 1,
min_length => 1,
max_length => 255,
...
};
field 'login' => {
mixin => 'constrain',
...
};
THE FILTER KEYWORD
The filter keyword creates custom filters to be used in your field
definitions.
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
filter 'telephone' => sub {
...
};
field 'telephone' => {
filter => ['trim', 'telephone'],
...
};
THE DIRECTIVE KEYWORD
The directive keyword creates custom validator directives to be used in
your field definitions. The routine is passed two parameters, the value
of directive and the value of the field the validator is being processed
against. The validator should return true or false.
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
directive 'between' => sub {
my ($directive, $value, $field, $class) = @_;
my ($min, $max) = split /\-/, $directive;
unless ($value > $min && $value < $max) {
my $handle = $field->{label} || $field->{name};
$class->error($field, "$handle must be between $directive");
return 0;
}
return 1;
};
field 'hours' => {
between => '00-24',
...
};
THE FIELD KEYWORD
The field keyword create a validation block and defines validation rules
for reuse in code. The field keyword should correspond with the
parameter name expected to be passed to your validation class.
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
field 'login' => {
required => 1,
min_length => 1,
max_length => 255,
...
};
The field keword takes two arguments, the field name and a hashref of
key/values pairs. The keys are referred to as directives, those
directives are as follows:
FIELD/MIXIN DEFAULT DIRECTIVES
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
# a validation template
mixin '...' => {
...
};
# a validation rule
field '...' => {
mixin => '...',
...
};
1;
When building a validation class, the first encountered and arguably two
most important keyword functions are field() and mixin() which are used
to declare their respective properties. A mixin() declares a validation
template where its properties are intended to be copied within field()
declarations which declares validation rules and properties.
Both the field() and mixin() declarations/functions require two
parameters, the first being a name, used to identify the declaration,
and the second being a hashref of key/value pairs. The key(s) within a
declaration are commonly referred to as directives.
The following is a list of default directives which can be used in
field/mixin declarations:
label
# the label directive
field 'foobar' => {
label => 'Foo Bar',
...
};
alias
# the alias directive
field 'foobar' => {
alias => 'foo_bar',
...
};
mixin
mixin 'abcxyz' => {
...
};
# the mixin directive
field 'foobar' => {
mixin => 'abcxyz',
...
};
mixin_field
# the mixin_field directive
field 'foobar' => {
mixin_field => '...',
...
};
validation
# the validation directive
field 'foobar' => {
validation => '...',
...
};
error/errors
# the error(s) directive
field 'foobar' => {
errors => '...',
...
};
value
# the value directive
field 'foobar' => {
value => '...',
...
};
name
# the name directive
field 'foobar' => {
name => '...',
...
};
filter/filters
# the filter(s) directive
field 'foobar' => {
filter => '...',
...
};
The following is a list of default filters that may be used with the
filter directive:
trim
field 'foobar' => {
filter => 'trim',
};
alpha
field 'foobar' => {
filter => 'alpha',
};
currency
field 'foobar' => {
filter => 'currency',
};
strip
field 'foobar' => {
filter => 'strip',
};
numeric
field 'foobar' => {
filter => 'numeric',
};
uppercase
field 'foobar' => {
filter => 'uppercase',
};
titlecase
field 'foobar' => {
filter => 'titlecase',
};
capitalize
field 'foobar' => {
filter => 'capitalize',
};
lowercase
field 'foobar' => {
filter => 'lowercase',
};
alphanumeric
field 'foobar' => {
filter => 'alphanumeric',
};
required
# the required directive
field 'foobar' => {
required => '...',
...
};
FIELD/MIXIN DEFAULT VALIDATOR DIRECTIVES
package MyApp::Validation;
use Validation::Class;
use base 'Validation::Class';
# a validation rule with validator directives
field '...' => {
min_length => '...',
max_length => '...',
pattern => '+# (###) ###-####',
...
};
1;
Validator directives are special directives with associated validation
code that is used to validate common use-cases such as "checking the
length of a parameter", etc.
The following is a list of the default validators which can be used in
field/mixin declarations:
min_length
# the min_length directive
field 'foobar' => {
min_length => '...',
...
};
max_length
# the max_length directive
field 'foobar' => {
max_length => '...',
...
};
between
# the between directive
field 'foobar' => {
between => '1-5',
...
};
length
# the length directive
field 'foobar' => {
length => 20,
...
};
pattern
# the pattern directive
field 'telephone' => {
pattern => '### ###-####',
...
};
field 'country_code' => {
pattern => 'XX',
filter => 'uppercase'
...
};
matches
# the matches directive
field 'password' => {
matches => 'password_confirmation',
...
};
options
# the options directive
field 'status' => {
options => 'Active, Inactive',
...
};
EXECUTING A VALIDATION CLASS
The following is an example of how to use you constructed validation
class in other code, .e.g. Web App Controller, etc.
use MyApp::Validation;
my $input = MyApp::Validation->new(params => $params);
unless ($input->validate('field1','field2')){
return $input->errors->to_string;
}
Feeling lazy, have your validation class automatically find the
appropriate fields to validate against (params must match field names).
use MyApp::Validation;
my $input = MyApp::Validation->new(params => $params);
unless ($input->validate){
return $input->errors->to_string;
}
You can define an alias to automatically map a parameter to a validation
field whereby a field definition will have an alias attribute containing
an arrayref of alternate parameters that can be matched against
passed-in parameters. The whole mapping technique can get cumbersome in
larger projects.
package MyApp::Validation;
field 'foo.bar' => {
...,
alias => [
'foo',
'bar',
'baz',
'bax'
]
};
use MyApp::Validation;
my $input = MyApp::Validation->new(params => { foo => 1 });
unless ($input->validate(){
return $input->errors->to_string;
}
new
The new method instantiates and returns an instance of your validation
class.
use MyApp::Validation;
my $input = MyApp::Validation->new;
$input->params($params);
...
or
my $input = MyApp::Validation->new(params => $params);
...
fields
The fields attribute returns a hashref of defined fields, filtered and
merged with thier parameter counterparts.
my $self = MyApp::Validation->new(fields => $fields);
my $fields = $self->fields();
...
filters
The filters attribute returns a hashref of pre-defined filter
definitions.
my $filters = $self->filters();
...
ignore_unknown
The ignore_unknown boolean determines whether your application will live
or die upon encountering unregistered field directives during
validation.
my $self = MyApp::Validation->new(params => $params, ignore_unknown => 1);
$self->ignore_unknown(1);
...
report_unknown
The report_unknown boolean determines whether your application will
report unregistered fields as class-level errors upon encountering
unregistered field directives during validation.
my $self = MyApp::Validation->new(params => $params,
ignore_unknown => 1, report_unknown => 1);
$self->report_unknown(1);
...
hash_inflator
The hash_inflator value determines how the hash serializer
(inflation/deflation) behaves. The value must be a hashref of "OPTIONS"
in Hash::Flatten options. Pure for the sake of consistency, you can use
lowercase keys (with underscores) which will be converted to camelcased
keys before passed to the serializer.
my $self = MyApp::Validation->new(
hash_inflator => {
hash_delimiter => '/',
array_delimiter => '//'
}
);
...
params
The params attribute gets/sets the parameters to be validated.
my $input = {
...
};
my $self = MyApp::Validation->new(params => $input);
$self->params($input);
my $params = $self->params();
...
mixins
The mixins attribute returns a hashref of defined validation templates.
my $mixins = $self->mixins();
...
validate
The validate method returns true/false depending on whether all
specified fields passed validation checks.
use MyApp::Validation;
my $input = MyApp::Validation->new(params => $params);
# validate specific fields
unless ($input->validate('field1','field2')){
return $input->errors->to_string;
}
# validate all fields, regardless of parameter existence
unless ($input->validate()){
return $input->errors->to_string;
}
# validate all existing parameters
unless ($input->validate(keys %{$input->params})){
return $input->errors->to_string;
}
# validate specific parameters (by name) after mapping them to other fields
my $map = {
param1 => 'field_abc',
param2 => 'field_def'
};
unless ($input->validate($map)){
return $input->errors->to_string;
}
reset_fields
The reset_fields effectively resets any altered field objects at the
class level. This method is called automatically everytime the new()
method is triggered.
$self->reset_fields();
PARAMETER HANDLING
The following are convenience functions for handling your input data
after processing and data validation.
get_params
The get_params method returns the values (in list form) of the
parameters specified.
if ($self->validate) {
my $name_a = $self->get_params('name');
my ($name_b, $email, $login, $password) =
$self->get_params(qw/name email login password/);
# you should note that if the params dont exist they will return undef
# ... meaning you should check that it exists before checking its value
# e.g.
if (defined $name) {
if ($name eq '') {
print 'name parameter was passed but was empty';
}
}
else {
print 'name parameter was never submitted';
}
}
get_params_hash
If your fields and parameters are designed with complex hash structures,
The get_params_hash method returns the deserialized hashref of specified
parameters based on the the default or custom configuration of the hash
serializer Hash::Flatten.
my $params = {
'user.login' => 'member',
'user.password' => 'abc123456'
};
if ($self->validate(keys %$params)) {
my $params = $self->get_params_hash;
print $params->{user}->{login};
}
set_params_hash
Depending on how parameters are being input into your application, if
your input parameters are already complex hash structures, The
set_params_hash method will set and return the serialized version of
your hashref based on the the default or custom configuration of the
hash serializer Hash::Flatten.
my $params = {
user => {
login => 'member',
password => 'abc123456'
}
};
my $serialized_params = $self->set_params_hash($params);
ERROR HANDLING
The most important part of any input validation framework is its
ease-of-use and its error handling. Validation::Class gives you the
ability to bypass, override and/or clear errors at-will without a
hassle. The following methods assist you in doing just that.
error_fields
The error_fields method returns a hashref of fields whose value is an
arrayref of error messages.
unless ($self->validate) {
my $fields = $self->error_fields();
}
reset_errors
The reset_errors method clears all errors, both at the class and
individual field levels. This method is called automatically everytime
the validate() method is triggered.
$self->reset_errors();
error
The error function is used to set and/or retrieve errors encountered
during validation. The error function with no parameters returns the
error message object which is an arrayref of error messages stored at
class-level.
# return all errors encountered/set as an arrayref
return $self->error();
# return all errors specific to the specified field (at the field-level)
# as an arrayref
return $self->error('some_param');
# set an error specific to the specified field (at the field-level)
# using the field object (hashref not field name)
$self->error($field_object, "i am your error message");
unless ($self->validate) {
my $fields = $self->error();
}
errors
The errors function returns a special class (Validation::Class::Errors)
used to add convenience methods to the error objects. This class can be
utilized as follows.
# by default uses errors specified at the class-level
return $self->errors;
# count() method returns the number of errors encoutered
return $self->errors->count();
# to_string($delimiter) method strigifies the error arrayref object using
# the specified delimiter or ', ' by default
return $self->errors->to_string();
return $self->errors->to_string("
\n");
# use errors at the field-level in the errors class
return $self->errors($self->fields->{some_field})->count();
unless ($self->validate) {
return $self->errors->to_string;
}
AUTHOR
Al Newkirk
COPYRIGHT AND LICENSE
This software is copyright (c) 2011 by awncorp.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.