1265 lines
37 KiB
Plaintext
1265 lines
37 KiB
Plaintext
|
SYNOPSIS
|
||
|
|
||
|
use Validation::Class::Simple::Streamer;
|
||
|
|
||
|
my $params = {username => 'admin', password => 's3cret'};
|
||
|
my $input = Validation::Class::Simple::Streamer->new(params => $params);
|
||
|
|
||
|
# check username parameter
|
||
|
$input->check('username')->required->between('5-255');
|
||
|
$input->filters([qw/trim strip/]);
|
||
|
|
||
|
# check password parameter
|
||
|
$input->check('password')->required->between('5-255')->min_symbols(1);
|
||
|
$input->filters([qw/trim strip/]);
|
||
|
|
||
|
# run validate
|
||
|
$input->validate or die $input->errors_to_string;
|
||
|
|
||
|
DESCRIPTION
|
||
|
|
||
|
Validation::Class is a scalable data validation library with interfaces
|
||
|
for applications of all sizes. The most common usage of
|
||
|
Validation::Class is to transform class namespaces into data validation
|
||
|
domains where consistency and reuse are primary concerns.
|
||
|
Validation::Class provides an extensible framework for defining
|
||
|
reusable data validation rules. It ships with a complete set of
|
||
|
pre-defined validations and filters referred to as "directives".
|
||
|
|
||
|
The core feature-set consist of self-validating methods, validation
|
||
|
profiles, reusable validation rules and templates, pre and post input
|
||
|
filtering, class inheritance, automatic array handling, and
|
||
|
extensibility (e.g. overriding default error messages, creating custom
|
||
|
validators, creating custom input filters and much more).
|
||
|
Validation::Class promotes DRY (don't repeat yourself) code. The main
|
||
|
benefit in using Validation::Class is that the architecture is designed
|
||
|
to increase the consistency of data input handling. The following is a
|
||
|
more traditional usage of Validation::Class, using the DSL to construct
|
||
|
a validator class:
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
# data validation template
|
||
|
mixin basic => {
|
||
|
required => 1,
|
||
|
max_length => 255,
|
||
|
filters => [qw/trim strip/]
|
||
|
};
|
||
|
|
||
|
# data validation rules for the username parameter
|
||
|
field username => {
|
||
|
mixin => 'basic',
|
||
|
min_length => 5
|
||
|
};
|
||
|
|
||
|
# data validation rules for the password parameter
|
||
|
field password => {
|
||
|
mixin => 'basic',
|
||
|
min_length => 5,
|
||
|
min_symbols => 1
|
||
|
};
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $person = MyApp::Person->new(username => 'admin', password => 'secr3t');
|
||
|
|
||
|
# validate rules on the person object
|
||
|
unless ($person->validates) {
|
||
|
# handle the failures
|
||
|
warn $person->errors_to_string;
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
QUICKSTART
|
||
|
|
||
|
If you are looking for a simple in-line data validation module built
|
||
|
using the same tenets and principles as Validation::Class, please
|
||
|
review Validation::Class::Simple or
|
||
|
Validation::Class::Simple::Streamer. If you are new to
|
||
|
Validation::Class, or would like more information on the underpinnings
|
||
|
of this library and how it views and approaches data validation, please
|
||
|
review Validation::Class::Whitepaper. Please review the "GUIDED-TOUR"
|
||
|
in Validation::Class::Cookbook for a detailed step-by-step look into
|
||
|
how Validation::Class works.
|
||
|
|
||
|
UPGRADE
|
||
|
|
||
|
Validation::Class is stable, its feature-set is complete, and is
|
||
|
currently in maintenance-only mode, i.e. Validation::Class will only be
|
||
|
updated with minor enhancements and bug fixes. However, the lessons
|
||
|
learned will be incorporated into a compelete rewrite uploaded under
|
||
|
the namespace Validation::Interface. The Validation::Interface fork is
|
||
|
designed to have a much simpler API with less options and better
|
||
|
execution, focused on validating hierarchical data as its primarily
|
||
|
objective.
|
||
|
|
||
|
The adopt keyword (or adt) copies configuration and functionality from
|
||
|
other Validation::Class classes. The adopt keyword takes three
|
||
|
arguments, the name of the class to be introspected, and the
|
||
|
configuration type and name to be recreated. Basically, anything you
|
||
|
can configure using a Validation::Class keyword can be adopted into
|
||
|
other classes using this keyword with the exception of coderefs
|
||
|
registered using the build keyword. Please note! If you are adopting a
|
||
|
field declaration which has an associated mixin directive defined on
|
||
|
the target class, you must adopt the mixin explicitly if you wish it's
|
||
|
values to be interpolated.
|
||
|
|
||
|
package MyApp::Exployee;
|
||
|
|
||
|
use Validate::Class;
|
||
|
use MyApp::Person;
|
||
|
|
||
|
adopt MyApp::Person, mixin => 'basic';
|
||
|
adopt MyApp::Person, field => 'first_name';
|
||
|
adopt MyApp::Person, field => 'last_name';
|
||
|
adopt MyApp::Person, profile => 'has_fullname';
|
||
|
|
||
|
1;
|
||
|
|
||
|
The attribute keyword (or has) registers a class attribute, i.e. it
|
||
|
creates an accessor (getter and setter) on the class. Attribute
|
||
|
declaration is flexible and only requires an attribute name to be
|
||
|
configured. Additionally, the attribute keyword can takes two
|
||
|
arguments, the attribute's name and a scalar or coderef to be used as
|
||
|
it's default value.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validate::Class;
|
||
|
|
||
|
attribute 'first_name' => 'Peter';
|
||
|
attribute 'last_name' => 'Venkman';
|
||
|
attribute 'full_name' => sub {
|
||
|
join ', ', $_[0]->last_name, $_[0]->first_name
|
||
|
};
|
||
|
|
||
|
attribute 'email_address';
|
||
|
|
||
|
1;
|
||
|
|
||
|
The build keyword (or bld) registers a coderef to be run at
|
||
|
instantiation much in the same way the common BUILD routine is used in
|
||
|
modern OO frameworks.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
build sub {
|
||
|
|
||
|
my ($self, $args) = @_;
|
||
|
|
||
|
# run after instantiation in the order defined
|
||
|
|
||
|
};
|
||
|
|
||
|
1;
|
||
|
|
||
|
The build keyword takes one argument, a coderef which is passed the
|
||
|
instantiated class object.
|
||
|
|
||
|
The directive keyword (or dir) registers custom validator directives to
|
||
|
be used in your field definitions. Please note that custom directives
|
||
|
can only be used with field definitions. This is a means of extending
|
||
|
the list of directives per instance. See the list of core directives,
|
||
|
Validation::Class::Directives, or review Validation::Class::Directive
|
||
|
for insight into creating your own CPAN installable directives.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validate::Class;
|
||
|
|
||
|
# define a custom class-level directive
|
||
|
directive 'blacklisted' => sub {
|
||
|
|
||
|
my ($self, $field, $param) = @_;
|
||
|
|
||
|
if (defined $field->{blacklisted} && defined $param) {
|
||
|
if ($field->{required} || $param) {
|
||
|
if (exists_in_blacklist($field->{blacklisted}, $param)) {
|
||
|
my $handle = $field->label || $field->name;
|
||
|
$field->errors->add("$handle has been blacklisted");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
};
|
||
|
|
||
|
field 'email_address' => {
|
||
|
blacklisted => '/path/to/blacklist'
|
||
|
email => 1,
|
||
|
};
|
||
|
|
||
|
1;
|
||
|
|
||
|
The directive keyword takes two arguments, the name of the directive
|
||
|
and a coderef which will be used to validate the associated field. The
|
||
|
coderef is passed four ordered parameters; a directive object, the
|
||
|
class prototype object, the current field object, and the matching
|
||
|
parameter's value. The validator (coderef) is evaluated by its return
|
||
|
value as well as whether it altered any error containers.
|
||
|
|
||
|
The document keyword (or doc) registers a data matching profile which
|
||
|
can be used to validate heiarchal data. It will store a hashref with
|
||
|
pre-define path matching rules for the data structures you wish to
|
||
|
validate. The "path matching rules", which use a specialized object
|
||
|
notation, referred to as the document notation, can be thought of as a
|
||
|
kind-of simplified regular expression which is executed against the
|
||
|
flattened data structure. The following are a few general use-cases:
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
field 'string' => {
|
||
|
mixin => [':str']
|
||
|
};
|
||
|
|
||
|
# given this JSON data structure
|
||
|
{
|
||
|
"id": "1234-A",
|
||
|
"name": {
|
||
|
"first_name" : "Bob",
|
||
|
"last_name" : "Smith",
|
||
|
},
|
||
|
"title": "CIO",
|
||
|
"friends" : [],
|
||
|
}
|
||
|
|
||
|
# select id to validate against the string rule
|
||
|
document 'foobar' =>
|
||
|
{ 'id' => 'string' };
|
||
|
|
||
|
# select name -> first_name/last_name to validate against the string rule
|
||
|
document 'foobar' =>
|
||
|
{'name.first_name' => 'string', 'name.last_name' => 'string'};
|
||
|
|
||
|
# or
|
||
|
document 'foobar' =>
|
||
|
{'name.*_name' => 'string'};
|
||
|
|
||
|
# select each element in friends to validate against the string rule
|
||
|
document 'foobar' =>
|
||
|
{ 'friends.@' => 'string' };
|
||
|
|
||
|
# or select an element of a hashref in each element in friends to validate
|
||
|
# against the string rule
|
||
|
document 'foobar' =>
|
||
|
{ 'friends.@.name' => 'string' };
|
||
|
|
||
|
The document declaration's keys should follow the aforementioned
|
||
|
document notation schema and it's values should be strings which
|
||
|
correspond to the names of fields (or other document declarations) that
|
||
|
will be used to preform the data validation. It is possible to combine
|
||
|
document declarations to validate hierarchical data that contains data
|
||
|
structures matching one or more document patterns. The following is an
|
||
|
example of what that might look like.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
# data validation rule
|
||
|
field 'name' => {
|
||
|
mixin => [':str'],
|
||
|
pattern => qr/^[A-Za-z ]+$/,
|
||
|
max_length => 20,
|
||
|
};
|
||
|
|
||
|
# data validation map / document notation schema
|
||
|
document 'friend' => {
|
||
|
'name' => 'name'
|
||
|
};
|
||
|
|
||
|
# data validation map / document notation schema
|
||
|
document 'person' => {
|
||
|
'name' => 'name',
|
||
|
'friends.@' => 'friend'
|
||
|
};
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $data = {
|
||
|
"name" => "Anita Campbell-Green",
|
||
|
"friends" => [
|
||
|
{ "name" => "Horace" },
|
||
|
{ "name" => "Skinner" },
|
||
|
{ "name" => "Alonzo" },
|
||
|
{ "name" => "Frederick" },
|
||
|
],
|
||
|
};
|
||
|
|
||
|
my $person = MyApp::Person->new;
|
||
|
|
||
|
unless ($person->validate_document(person => $data)) {
|
||
|
warn $person->errors_to_string if $person->error_count;
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
Alternatively, the following is a more verbose data validation class
|
||
|
using traditional styling and configuration.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
field 'id' => {
|
||
|
mixin => [':str'],
|
||
|
filters => ['numeric'],
|
||
|
max_length => 2,
|
||
|
};
|
||
|
|
||
|
field 'name' => {
|
||
|
mixin => [':str'],
|
||
|
pattern => qr/^[A-Za-z ]+$/,
|
||
|
max_length => 20,
|
||
|
};
|
||
|
|
||
|
field 'rating' => {
|
||
|
mixin => [':str'],
|
||
|
pattern => qr/^\-?\d+$/,
|
||
|
};
|
||
|
|
||
|
field 'tag' => {
|
||
|
mixin => [':str'],
|
||
|
pattern => qr/^(?!evil)\w+/,
|
||
|
max_length => 20,
|
||
|
};
|
||
|
|
||
|
document 'person' => {
|
||
|
'id' => 'id',
|
||
|
'name' => 'name',
|
||
|
'company.name' => 'name',
|
||
|
'company.supervisor.name' => 'name',
|
||
|
'company.supervisor.rating.@.*' => 'rating',
|
||
|
'company.tags.@' => 'name'
|
||
|
};
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $data = {
|
||
|
"id" => "1234-ABC",
|
||
|
"name" => "Anita Campbell-Green",
|
||
|
"title" => "Designer",
|
||
|
"company" => {
|
||
|
"name" => "House of de Vil",
|
||
|
"supervisor" => {
|
||
|
"name" => "Cruella de Vil",
|
||
|
"rating" => [
|
||
|
{ "support" => -9,
|
||
|
"guidance" => -9
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"tags" => [
|
||
|
"evil",
|
||
|
"cruelty",
|
||
|
"dogs"
|
||
|
]
|
||
|
},
|
||
|
};
|
||
|
|
||
|
my $person = MyApp::Person->new;
|
||
|
|
||
|
unless ($person->validate_document(person => $data)) {
|
||
|
warn $person->errors_to_string if $person->error_count;
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
Additionally, the following is yet another way to validate a document
|
||
|
by passing the document specification directly instead of by name.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $data = {
|
||
|
"id" => "1234-ABC",
|
||
|
"name" => "Anita Campbell-Green",
|
||
|
"title" => "Designer",
|
||
|
"company" => {
|
||
|
"name" => "House of de Vil",
|
||
|
"supervisor" => {
|
||
|
"name" => "Cruella de Vil",
|
||
|
"rating" => [
|
||
|
{ "support" => -9,
|
||
|
"guidance" => -9
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"tags" => [
|
||
|
"evil",
|
||
|
"cruelty",
|
||
|
"dogs"
|
||
|
]
|
||
|
},
|
||
|
};
|
||
|
|
||
|
my $spec = {
|
||
|
'id' => { max_length => 2 },
|
||
|
'name' => { mixin => ':str' },
|
||
|
'company.name' => { mixin => ':str' },
|
||
|
'company.supervisor.name' => { mixin => ':str' },
|
||
|
'company.supervisor.rating.@.*' => { pattern => qr/^(?!evil)\w+/ },
|
||
|
'company.tags.@' => { max_length => 20 },
|
||
|
};
|
||
|
|
||
|
my $person = MyApp::Person->new;
|
||
|
|
||
|
unless ($person->validate_document($spec => $data)) {
|
||
|
warn $person->errors_to_string if $person->error_count;
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
The ensure keyword (or ens) is used to convert a pre-existing method
|
||
|
into an auto-validating method. The auto-validating method will be
|
||
|
registered and function as if it was created using the method keyword.
|
||
|
The original pre-existing method will be overridden with a modified
|
||
|
version which performs the pre and/or post validation routines.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
sub register {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
ensure register => {
|
||
|
input => ['name', '+email', 'username', '+password', '+password2'],
|
||
|
output => ['+id'], # optional output validation, dies on failure
|
||
|
};
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $person = MyApp::Person->new(params => $params);
|
||
|
|
||
|
if ($person->register) {
|
||
|
# handle the successful registration
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
The ensure keyword takes two arguments, the name of the method to be
|
||
|
overridden and a hashref of required key/value pairs. The hashref may
|
||
|
have an input key (e.g. input, input_document, input_profile, or
|
||
|
input_method). The `input` key (specifically) must have a value which
|
||
|
must be either an arrayref of fields to be validated, or a scalar value
|
||
|
which matches (a validation profile or auto-validating method name).
|
||
|
The hashref may also have an output key (e.g. output, output_document,
|
||
|
output_profile, or output_method). The `output` key (specifically) must
|
||
|
have a value which must be either an arrayref of fields to be
|
||
|
validated, or a scalar value which matches (a validation profile or
|
||
|
auto-validating method name). Whether and what the method returns is
|
||
|
yours to decide. The method will return undefined if validation fails.
|
||
|
The ensure keyword wraps and functions much in the same way as the
|
||
|
method keyword.
|
||
|
|
||
|
The field keyword (or fld) registers a data validation rule for reuse
|
||
|
and validation in code. The field name should correspond with the
|
||
|
parameter name expected to be passed to your validation class or
|
||
|
validated against.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
field 'username' => {
|
||
|
required => 1,
|
||
|
min_length => 1,
|
||
|
max_length => 255
|
||
|
};
|
||
|
|
||
|
The field keyword takes two arguments, the field name and a hashref of
|
||
|
key/values pairs known as directives. For more information on
|
||
|
pre-defined directives, please review the "list of core directives".
|
||
|
|
||
|
The field keyword also creates accessors which provide easy access to
|
||
|
the field's corresponding parameter value(s). Accessors will be created
|
||
|
using the field's name as a label having any special characters
|
||
|
replaced with an underscore.
|
||
|
|
||
|
# accessor will be created as send_reminders
|
||
|
field 'send-reminders' => {
|
||
|
length => 1
|
||
|
};
|
||
|
|
||
|
Please note that prefixing field names with a double plus-symbol
|
||
|
instructs the register to merge your declaration with any pre-existing
|
||
|
declarations within the same scope (e.g. fields imported via loading
|
||
|
roles), whereas prefixing field names with a single plus-symbol
|
||
|
instructs the register to overwrite any pre-existing declarations.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
set role => 'MyApp::User';
|
||
|
|
||
|
# append existing field and overwrite directives
|
||
|
field '++email_address' => {
|
||
|
required => 1
|
||
|
};
|
||
|
|
||
|
# redefine existing field
|
||
|
field '+login' => {
|
||
|
required => 1
|
||
|
};
|
||
|
|
||
|
1;
|
||
|
|
||
|
The filter keyword (or flt) registers custom filters to be used in your
|
||
|
field definitions. It is a means of extending the pre-existing filters
|
||
|
declared by the "filters directive" before instantiation.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validate::Class;
|
||
|
|
||
|
filter 'flatten' => sub {
|
||
|
$_[0] =~ s/[\t\r\n]+/ /g;
|
||
|
return $_[0];
|
||
|
};
|
||
|
|
||
|
field 'biography' => {
|
||
|
filters => ['trim', 'strip', 'flatten']
|
||
|
};
|
||
|
|
||
|
1;
|
||
|
|
||
|
The filter keyword takes two arguments, the name of the filter and a
|
||
|
coderef which will be used to filter the value the associated field.
|
||
|
The coderef is passed the value of the field and that value MUST be
|
||
|
operated on directly. The coderef should also return the transformed
|
||
|
value.
|
||
|
|
||
|
The load keyword (or set), which can also be used as a class method,
|
||
|
provides options for extending the current class by declaring roles,
|
||
|
requirements, etc.
|
||
|
|
||
|
The process of applying roles, requirement, and other settings to the
|
||
|
current class mainly involves introspecting the namespace's methods and
|
||
|
merging relevant parts of the prototype configuration.
|
||
|
|
||
|
The `classes` (or class) option uses Module::Find to load all child
|
||
|
classes (in-all-subdirectories) for convenient access through the
|
||
|
"class" in Validation::Class::Prototype method, and when introspecting
|
||
|
a larger application. This option accepts an arrayref or single
|
||
|
argument.
|
||
|
|
||
|
package MyApp;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
load classes => ['MyApp::Domain1', 'MyApp::Domain2'];
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $app = MyApp->new;
|
||
|
|
||
|
my $person = $app->class('person'); # return a new MyApp::Person object
|
||
|
|
||
|
1;
|
||
|
|
||
|
package MyApp::User;
|
||
|
|
||
|
use Validate::Class;
|
||
|
|
||
|
load requirements => 'activate';
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
load role => 'MyApp::User';
|
||
|
|
||
|
sub activate {}
|
||
|
|
||
|
1;
|
||
|
|
||
|
The `requirements` (or required) option is used to ensure that if/when
|
||
|
the class is used as a role the calling class has specific pre-existing
|
||
|
methods. This option accepts an arrayref or single argument.
|
||
|
|
||
|
package MyApp::User;
|
||
|
|
||
|
use Validate::Class;
|
||
|
|
||
|
load requirements => ['activate', 'deactivate'];
|
||
|
|
||
|
1;
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
load role => 'MyApp::User';
|
||
|
|
||
|
1;
|
||
|
|
||
|
The `roles` (or role) option is used to load and inherit functionality
|
||
|
from other validation classes. These classes should be used and
|
||
|
thought-of as roles although they can also be fully-functioning
|
||
|
validation classes. This option accepts an arrayref or single argument.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
load roles => ['MyApp::User', 'MyApp::Visitor'];
|
||
|
|
||
|
1;
|
||
|
|
||
|
The message keyword (or msg) registers a class-level error message
|
||
|
template that will be used in place of the error message defined in the
|
||
|
corresponding directive class if defined. Error messages can also be
|
||
|
overridden at the individual field-level as well. See the
|
||
|
Validation::Class::Directive::Messages for instructions on how to
|
||
|
override error messages at the field-level.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
field email_address => {
|
||
|
required => 1,
|
||
|
min_length => 3,
|
||
|
messages => {
|
||
|
# field-level error message override
|
||
|
min_length => '%s is not even close to being a valid email address'
|
||
|
}
|
||
|
};
|
||
|
|
||
|
# class-level error message overrides
|
||
|
message required => '%s is needed to proceed';
|
||
|
message min_length => '%s needs more characters';
|
||
|
|
||
|
1;
|
||
|
|
||
|
The message keyword takes two arguments, the name of the directive
|
||
|
whose error message you wish to override and a string which will be
|
||
|
used to as a template which is feed to sprintf to format the message.
|
||
|
|
||
|
The method keyword (or mth) is used to register an auto-validating
|
||
|
method. Similar to method signatures, an auto-validating method can
|
||
|
leverage pre-existing validation rules and profiles to ensure a method
|
||
|
has the required pre/post-conditions and data necessary for execution.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
method 'register' => {
|
||
|
|
||
|
input => ['name', '+email', 'username', '+password', '+password2'],
|
||
|
output => ['+id'], # optional output validation, dies on failure
|
||
|
using => sub {
|
||
|
|
||
|
my ($self, @args) = @_;
|
||
|
|
||
|
# do something registrationy
|
||
|
$self->id(...); # set the ID field for output validation
|
||
|
|
||
|
return $self;
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $person = MyApp::Person->new(params => $params);
|
||
|
|
||
|
if ($person->register) {
|
||
|
|
||
|
# handle the successful registration
|
||
|
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
The method keyword takes two arguments, the name of the method to be
|
||
|
created and a hashref of required key/value pairs. The hashref may have
|
||
|
a `using` key whose value is the coderef to be executed upon successful
|
||
|
validation. The `using` key is only optional when a pre-existing
|
||
|
subroutine has the same name or the method being declared prefixed with
|
||
|
a dash or dash-process-dash. The following are valid subroutine names
|
||
|
to be called by the method declaration in absence of a `using` key.
|
||
|
Please note, unlike the ensure keyword, any pre-existing subroutines
|
||
|
will not be wrapped-and-replaced and can be executed without validation
|
||
|
if called directly.
|
||
|
|
||
|
sub _name {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
sub _process_name {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
The hashref may have an input key (e.g. input, input_document,
|
||
|
input_profile, or input_method). The `input` key (specifically) must
|
||
|
have a value which must be either an arrayref of fields to be
|
||
|
validated, or a scalar value which matches (a validation profile or
|
||
|
auto-validating method name), which will be used to perform data
|
||
|
validation before the aforementioned coderef has been executed. Whether
|
||
|
and what the method returns is yours to decide. The method will return
|
||
|
undefined if validation fails.
|
||
|
|
||
|
# alternate usage
|
||
|
|
||
|
method 'registration' => {
|
||
|
input => ['name', '+email', 'username', '+password', '+password2'],
|
||
|
output => ['+id'], # optional output validation, dies on failure
|
||
|
};
|
||
|
|
||
|
sub _process_registration {
|
||
|
my ($self, @args) = @_;
|
||
|
$self->id(...); # set the ID field for output validation
|
||
|
return $self;
|
||
|
}
|
||
|
|
||
|
Optionally the hashref may also have an output key (e.g. output,
|
||
|
output_document, output_profile, or output_method). The `output` key
|
||
|
(specifically) must have a value which must be either an arrayref of
|
||
|
fields to be validated, or a scalar value which matches (a validation
|
||
|
profile or auto-validating method name), which will be used to perform
|
||
|
data validation after the aforementioned coderef has been executed.
|
||
|
|
||
|
Please note that output validation failure will cause the program to
|
||
|
die, the premise behind this decision is based on the assumption that
|
||
|
given successfully validated input a routine's output should be
|
||
|
predictable and if an error occurs it is most-likely a program error as
|
||
|
opposed to a user error.
|
||
|
|
||
|
See the ignore_failure and report_failure attributes on the prototype
|
||
|
to control how method validation failures are handled.
|
||
|
|
||
|
The mixin keyword (or mxn) registers a validation rule template that
|
||
|
can be applied (or "mixed-in") to any field by specifying the mixin
|
||
|
directive. Mixin directives are processed first so existing field
|
||
|
directives will override any directives created by the mixin directive.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
mixin 'boilerplate' => {
|
||
|
required => 1,
|
||
|
min_length => 1,
|
||
|
max_length => 255
|
||
|
};
|
||
|
|
||
|
field 'username' => {
|
||
|
# min_length, max_length, .. required will be overridden
|
||
|
mixin => 'boilerplate',
|
||
|
required => 0
|
||
|
};
|
||
|
|
||
|
Since version 7.900015, all classes are automatically configured with
|
||
|
the following default mixins for the sake of convenience:
|
||
|
|
||
|
mixin ':flg' => {
|
||
|
required => 1,
|
||
|
min_length => 1,
|
||
|
filters => [qw/trim strip numeric/],
|
||
|
between => [0, 1]
|
||
|
};
|
||
|
|
||
|
mixin ':num' => {
|
||
|
required => 1,
|
||
|
min_length => 1,
|
||
|
filters => [qw/trim strip numeric/]
|
||
|
};
|
||
|
|
||
|
mixin ':str' => {
|
||
|
required => 1,
|
||
|
min_length => 1,
|
||
|
filters => [qw/trim strip/]
|
||
|
};
|
||
|
|
||
|
Please note that the aforementioned mixin names are prefixed with a
|
||
|
semi-colon but are treated as an exception to the rule. Prefixing mixin
|
||
|
names with a double plus-symbol instructs the register to merge your
|
||
|
declaration with any pre-existing declarations within the same scope
|
||
|
(e.g. mixins imported via loading roles), whereas prefixing mixin names
|
||
|
with a single plus-symbol instructs the register to overwrite any
|
||
|
pre-existing declarations.
|
||
|
|
||
|
package MyApp::Moderator;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
set role => 'MyApp::Person';
|
||
|
|
||
|
# overwrite and append existing mixin
|
||
|
mixin '++boilerplate' => {
|
||
|
min_symbols => 1
|
||
|
};
|
||
|
|
||
|
# redefine existing mixin
|
||
|
mixin '+username' => {
|
||
|
required => 1
|
||
|
};
|
||
|
|
||
|
1;
|
||
|
|
||
|
The mixin keyword takes two arguments, the mixin name and a hashref of
|
||
|
key/values pairs known as directives.
|
||
|
|
||
|
The new method instantiates a new class object, it performs a series of
|
||
|
actions (magic) required for the class to function properly, and for
|
||
|
that reason, this method should never be overridden. Use the build
|
||
|
keyword for hooking into the instantiation process.
|
||
|
|
||
|
In the event a foreign (pre-existing) `new` method is detected, an
|
||
|
`initialize_validator` method will be injected into the class
|
||
|
containing the code (magic) necessary to normalize your environment.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
# hook
|
||
|
build sub {
|
||
|
|
||
|
my ($self, @args) = @_; # on instantiation
|
||
|
|
||
|
};
|
||
|
|
||
|
sub new {
|
||
|
|
||
|
# rolled my own
|
||
|
my $self = bless {}, shift;
|
||
|
|
||
|
# execute magic
|
||
|
$self->initialize_validator;
|
||
|
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
The profile keyword (or pro) registers a validation profile (coderef)
|
||
|
which as in the traditional use of the term is a sequence of validation
|
||
|
routines that validates data relevant to a specific action.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
profile 'check_email' => sub {
|
||
|
|
||
|
my ($self, @args) = @_;
|
||
|
|
||
|
if ($self->email_exists) {
|
||
|
my $email = $self->fields->get('email');
|
||
|
$email->errors->add('Email already exists');
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
|
||
|
};
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $user = MyApp::Person->new(params => $params);
|
||
|
|
||
|
unless ($user->validate_profile('check_email')) {
|
||
|
# handle failures
|
||
|
}
|
||
|
|
||
|
1;
|
||
|
|
||
|
The profile keyword takes two arguments, a profile name and coderef
|
||
|
which will be used to execute a sequence of actions for validation
|
||
|
purposes.
|
||
|
|
||
|
The prototype method (or proto) returns an instance of the associated
|
||
|
class prototype. The class prototype is responsible for manipulating
|
||
|
and validating the data model (the class). It is not likely that you'll
|
||
|
need to access this method directly, see Validation::Class::Prototype.
|
||
|
|
||
|
package MyApp::Person;
|
||
|
|
||
|
use Validation::Class;
|
||
|
|
||
|
package main;
|
||
|
|
||
|
my $person = MyApp::Person->new;
|
||
|
|
||
|
my $prototype = $person->prototype;
|
||
|
|
||
|
1;
|
||
|
|
||
|
PROXY METHODS
|
||
|
|
||
|
Validation::Class mostly provides sugar functions for modeling your
|
||
|
data validation requirements. Each class you create is associated with
|
||
|
a prototype class which provides the data validation engine and keeps
|
||
|
your class namespace free from pollution, please see
|
||
|
Validation::Class::Prototype for more information on specific methods
|
||
|
and attributes. Validation::Class injects a few proxy methods into your
|
||
|
class which are basically aliases to the corresponding prototype class
|
||
|
methods, however it is possible to access the prototype directly using
|
||
|
the proto/prototype methods.
|
||
|
|
||
|
=proxy_method class
|
||
|
|
||
|
$self->class;
|
||
|
|
||
|
See "class" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method clear_queue
|
||
|
|
||
|
$self->clear_queue;
|
||
|
|
||
|
See "clear_queue" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method error_count
|
||
|
|
||
|
$self->error_count;
|
||
|
|
||
|
See "error_count" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method error_fields
|
||
|
|
||
|
$self->error_fields;
|
||
|
|
||
|
See "error_fields" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method errors
|
||
|
|
||
|
$self->errors;
|
||
|
|
||
|
See "errors" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method errors_to_string
|
||
|
|
||
|
$self->errors_to_string;
|
||
|
|
||
|
See "errors_to_string" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method get_errors
|
||
|
|
||
|
$self->get_errors;
|
||
|
|
||
|
See "get_errors" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method get_fields
|
||
|
|
||
|
$self->get_fields;
|
||
|
|
||
|
See "get_fields" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method get_hash
|
||
|
|
||
|
$self->get_hash;
|
||
|
|
||
|
See "get_hash" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method get_params
|
||
|
|
||
|
$self->get_params;
|
||
|
|
||
|
See "get_params" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method get_values
|
||
|
|
||
|
$self->get_values;
|
||
|
|
||
|
See "get_values" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method fields
|
||
|
|
||
|
$self->fields;
|
||
|
|
||
|
See "fields" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method filtering
|
||
|
|
||
|
$self->filtering;
|
||
|
|
||
|
See "filtering" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method ignore_failure
|
||
|
|
||
|
$self->ignore_failure;
|
||
|
|
||
|
See "ignore_failure" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method ignore_intervention
|
||
|
|
||
|
$self->ignore_intervention;
|
||
|
|
||
|
See "ignore_intervention" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method ignore_unknown
|
||
|
|
||
|
$self->ignore_unknown;
|
||
|
|
||
|
See "ignore_unknown" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method is_valid
|
||
|
|
||
|
$self->is_valid;
|
||
|
|
||
|
See "is_valid" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method param
|
||
|
|
||
|
$self->param;
|
||
|
|
||
|
See "param" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method params
|
||
|
|
||
|
$self->params;
|
||
|
|
||
|
See "params" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method plugin
|
||
|
|
||
|
$self->plugin;
|
||
|
|
||
|
See "plugin" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method queue
|
||
|
|
||
|
$self->queue;
|
||
|
|
||
|
See "queue" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method report_failure
|
||
|
|
||
|
$self->report_failure;
|
||
|
|
||
|
See "report_failure" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method report_unknown
|
||
|
|
||
|
$self->report_unknown;
|
||
|
|
||
|
See "report_unknown" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method reset_errors
|
||
|
|
||
|
$self->reset_errors;
|
||
|
|
||
|
See "reset_errors" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method reset_fields
|
||
|
|
||
|
$self->reset_fields;
|
||
|
|
||
|
See "reset_fields" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method reset_params
|
||
|
|
||
|
$self->reset_params;
|
||
|
|
||
|
See "reset_params" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method set_errors
|
||
|
|
||
|
$self->set_errors;
|
||
|
|
||
|
See "set_errors" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method set_fields
|
||
|
|
||
|
$self->set_fields;
|
||
|
|
||
|
See "set_fields" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method set_params
|
||
|
|
||
|
$self->set_params;
|
||
|
|
||
|
See "set_params" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method set_method
|
||
|
|
||
|
$self->set_method;
|
||
|
|
||
|
See "set_method" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method stash
|
||
|
|
||
|
$self->stash;
|
||
|
|
||
|
See "stash" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method validate
|
||
|
|
||
|
$self->validate;
|
||
|
|
||
|
See "validate" in Validation::Class::Prototype for full documentation.
|
||
|
|
||
|
=proxy_method validate_document
|
||
|
|
||
|
$self->validate_document;
|
||
|
|
||
|
See "validate_document" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method validate_method
|
||
|
|
||
|
$self->validate_method;
|
||
|
|
||
|
See "validate_method" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
=proxy_method validate_profile
|
||
|
|
||
|
$self->validate_profile;
|
||
|
|
||
|
See "validate_profile" in Validation::Class::Prototype for full
|
||
|
documentation.
|
||
|
|
||
|
EXTENSIBILITY
|
||
|
|
||
|
Validation::Class does NOT provide method modifiers but can be easily
|
||
|
extended with Class::Method::Modifiers.
|
||
|
|
||
|
before
|
||
|
|
||
|
before foo => sub { ... };
|
||
|
|
||
|
See "before method(s) => sub { ... }" in Class::Method::Modifiers for
|
||
|
full documentation.
|
||
|
|
||
|
around
|
||
|
|
||
|
around foo => sub { ... };
|
||
|
|
||
|
See "around method(s) => sub { ... }" in Class::Method::Modifiers for
|
||
|
full documentation.
|
||
|
|
||
|
after
|
||
|
|
||
|
after foo => sub { ... };
|
||
|
|
||
|
See "after method(s) => sub { ... }" in Class::Method::Modifiers for
|
||
|
full documentation.
|
||
|
|
||
|
SEE ALSO
|
||
|
|
||
|
Validation::Class does not validate blessed objects. If you need a
|
||
|
means for validating object types you should use a modern object system
|
||
|
like Moo, Mouse, or Moose. Alternatively, you could use decoupled
|
||
|
object validators like Type::Tiny, Params::Validate or Specio.
|
||
|
|
||
|
POD ERRORS
|
||
|
|
||
|
Hey! The above document had some coding errors, which are explained
|
||
|
below:
|
||
|
|
||
|
Around line 96:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 120:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 142:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 164:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 210:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 428:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 473:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 528:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 555:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 564:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 585:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 615:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 638:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 669:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 764:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 837:
|
||
|
|
||
|
Unknown directive: =method
|
||
|
|
||
|
Around line 871:
|
||
|
|
||
|
Unknown directive: =keyword
|
||
|
|
||
|
Around line 908:
|
||
|
|
||
|
Unknown directive: =method
|
||
|
|
||
|
Around line 1182:
|
||
|
|
||
|
=back without =over
|
||
|
|