NAME Validation::Class - Centralized Input Validation For Any Application VERSION version 0.111912 SYNOPSIS use MyApp::Validation; my $input = MyApp::Validation->new(params => $params); unless ($input->validate){ return $input->errors->to_string; } 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; } If you are using groups in your validation class you might validate your data like so ... use MyApp::Validation; my $input = MyApp::Validation->new(params => $params); unless ($input->validate('user:login', 'user:password')){ return $input->errors->to_string; } Although this means that the incoming parameters need to specify its parameter names using the same group naming convention. If this is not to your liking, the validate() method can assist you in mapping your incoming parameters to your grouped validation fields as shown here: use MyApp::Validation; my $input = MyApp::Validation->new(params => $params); unless ($input->validate({ user => 'user:login', pass => 'user:password')){ return $input->errors->to_string; } You can also map automatically by using field aliases whereby a field definition will have an alias attribute containing an arrayref of alternate parameters that can be matched against passed-in parameters as an alternative to the parameter mapping technique. 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 fields 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 fields during validation. my $self = MyApp::Validation->new(params => $params, ignore_unknown => 1, report_unknown => 1); $self->report_unknown(1); ... 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 = $self->get_params('name'); my ($name, $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'; } } 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) 2010 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.