NAME¶
Validation::Class - Self-Validating Object System and Data Validation Framework
VERSION¶
version 7.70
SYNOPSIS¶
package MyApp::User;
use Validation::Class;
mixin basic => {
required => 1,
max_length => 255,
filters => [qw/trim strip/]
};
field login => {
mixin => 'basic',
min_length => 5
};
field password => {
mixin => 'basic',
min_length => 5,
min_symbols => 1
};
package main;
my $user = MyApp::User->new(login => 'admin', password => 'secr3t');
unless ($user->validate('login', 'password')) {
# do something with the errors,
# e.g. print $user->errors_to_string
}
1;
Validation::Class is a data validation framework and simple object system. It
allows you to model data and construct objects with focus on structure,
reusability and data validation. It expects user input errors (without dying),
validation only occurs when you ask it to. Validation::Class classes are
designed to ensure consistency and promote reuse of data validation rules.
Validation::Class::Intro will help you better understand the framework's
rationale and typical use-cases while Validation::Class::Prototype will help
you discover all the bells-and-whistles included in the framework.
DESCRIPTION¶
Validation::Class is much more than a robust data validation framework, in-fact
it is more of a data modeling framework and can be used as an alternative to
minimalistic object systems such as Moo, Mo, etc. Validation::Class aims to
provide the building blocks for easily definable self-validating data models.
For more information on the validation class object system, review "the
object system" section.
Validation classes are typically defined using the following keywords:
* field - a field is a data validation rule
* mixin - a field template
* directive - a field/mixin rule attribute
* filter - a directive which transforms the field parameter value
* method - a self-validating sub-routine
* object - a simple object builder
To keep your class namespace clean and free from pollution, all inherited
functionality is configured on your class' prototype (a cached class
configuration object) which leaves you free to create and overwrite method
names in your class without breaking the Validation::Class framework, this all
happens much in the same way Moose uses it's MOP (meta-object-protocol) having
most of the framework functionality residing in the Moose::Meta namespace. For
more information on the validation class prototype, review "the prototype
class" section.
One very important (and intentional) difference between Moose/Moose-like systems
and Validation::Class classes is in the handling of errors. There are
generally two types of errors that occur in an application, user-errors which
are expected and should be handled and reported, and system-errors which are
unexpected and should cause the application to terminate or otherwise handle
the exception. It is not always desired and/or appropriate to crash from a
failure to validate a particular parameter. In Validation::Class, the
application is not terminated or validate automatically unless you configure
it to.
Additionally, please review the Validation::Class::Intro for a more in-depth
understanding of how to leverage Validation::Class.
KEYWORDS¶
attribute¶
The attribute keyword (or has) creates a class attribute. This is only a
minimalistic variant of what you may have encountered in other object systems
such as Moose, Mouse, Moo, Mo, etc.
package MyApp::User;
use Validate::Class;
attribute 'bothered' => 1;
attribute 'attitude' => sub {
return $self->bothered ? 1 : 0
};
1;
The attribute keyword takes two arguments, the attribute name and a constant or
coderef that will be used as its default value.
build¶
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-day OO systems.
package MyApp::User;
use Validation::Class;
build sub {
my ($self, %args) = @_;
# ... do something
};
# die like a Moose
use Carp;
build sub {
my ($self, %args) = @_;
my @attributes = qw();
foreach my $attribute (@attributes) {
confess "Attribute ($attribute) is required"
unless $self->$attribute;
}
};
The build keyword takes one argument, a coderef which is passed the instantiated
class object.
directive¶
The directive keyword (or dir) creates custom validator directives to be used in
your field definitions. It is a means of extending the pre-existing directives
table before runtime and is ideal for creating custom directive extension
packages to be used in all your classes.
package MyApp::Directives;
use Validation::Class;
use Data::Validate::Email;
directive 'is_email' => sub {
my ($dir, $value, $field, $self) = @_;
my $validator = Data::Validate::Email->new;
unless ($validator->is_email($value)) {
my $handle = $field->{label} || $field->{name};
$field->{errors}->add("$handle must be a valid email address");
return 0;
}
return 1;
};
package MyApp::User;
use Validate::Class;
use MyApp::Directives;
field 'email' => {
is_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, the value of directive, the value of the field
(parameter value), the field object (hashref), and the instantiated class
object. The validator MUST return true or false.
Additionally, if you only desire to extend the list of acceptable directives,
you can create a no-op by simply returning true, e.g.:
directive 'new_addition' => sub {1};
field¶
The field keyword (or fld) creates 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.
package MyApp::User;
use Validation::Class;
field 'login' => {
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.
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.
field 'login' => {
required => 1,
min_length => 1,
max_length => 255,
...
};
field 'preference.send_reminders' => {
required => 1,
max_length => 1,
...
};
field 'preference.send_reminders.text:0' => {
...
};
my $value = $self->login;
$self->login($new_value); # arrayrefs and hashrefs will be flattened
$self->preference_send_reminders;
$self->preference_send_reminders_text_0;
Protip: Field directives are used to validate scalar and array data. Don't use
fields to store and validate blessed objects. Please see the *has* keyword
instead.
filter¶
The filter keyword (or flt) creates custom filters to be used in your field
definitions. It is a means of extending the pre-existing filters table before
runtime and is ideal for creating custom directive extension packages to be
used in all your classes.
package MyApp::Directives;
use Validation::Class;
filter 'flatten' => sub {
$_[0] =~ s/[\t\r\n]+/ /g;
$_[0] # return
};
package MyApp::User;
use Validate::Class;
use MyApp::Directives;
field 'description' => {
filters => ['trim', '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.
load¶
The load keyword (or set), which can also be used as a method, provides options
for extending the current class by attaching other Validation::Class classes
as relatives, roles, plugins, etc. The process of applying roles to the
current class mainly involve copying the role's methods and configuration.
package MyApp;
use Validation::Class;
# load stuff (extend MyApp)
load {
# run package commands
};
1;
The "load.classes" option, can be a constant or arrayref and uses
Module::Find to load
all child classes (in-all-subdirectories) for
convenient access through the
class() method. Existing parameters and
configuration options are passed to the child class' constructor. All
attributes can be easily overwritten using the attribute's accessors on the
child class. These child classes are often referred to as relatives. This
option accepts a constant or an arrayref of constants.
package MyApp;
use Validation::Class;
# load all child classes
load {
classes => [
__PACKAGE__
]
};
package main;
my $app = MyApp->new;
my $rel = $app->class('relative'); # new MyApp::Relative object
my $rel = $app->class('data_source'); # MyApp::DataSource
my $rel = $app->class('datasource-first'); # MyApp::Datasource::First
1;
The "load.plugins" option is used to load plugins that support
Validation::Class. A Validation::Class plugin is little more than a class that
implements a "new" method that extends the associated validation
class object. As usual, an official Validation::Class plugin can be referred
to using shorthand while custom plugins are called by prefixing a plus symbol
to the fully-qualified plugin name. Learn more about plugins at
Validation::Class::Intro. This option accepts a constant or an arrayref of
constants.
package MyVal;
use Validation::Class;
load {
plugins => [
'CPANPlugin', # Validation::Class::Plugin::CPANPlugin
'+MyVal::Plugin'
]
};
1;
The "load.roles" option is used to load and inherit functionality from
child classes, these classes should be used and thought-of as roles. Any
validation class can be used as a role with this option. This option accepts a
constant or an arrayref of constants.
package MyVal::User;
use Validation::Class;
load {
roles => [
'MyVal::Person'
]
};
1;
Purely for the sake of aesthetics we have designed an alternate syntax for
executing load/set commands, the syntax is as follows:
package MyVal::User;
use Validation::Class;
load roles => ['MyVal::Person'];
load classes => [__PACKAGE__];
load plugins => [
'CPANPlugin', # Validation::Class::Plugin::CPANPlugin
'+MyVal::Plugin'
];
method¶
The method keyword (or mth) is used to create 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 data
necessary to proceed.
package MyApp::User;
use Validation::Class;
method 'register' => {
input => ['name', '+email', 'login', '+password'],
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 $user = MyApp::User->new(params => $params);
if ($user->register) {
...
}
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 must have an
"input" variable whose value is either an arrayref of fields to be
validated, or a constant value which matches a validation profile name. The
hashref must also have a "using" variable whose value is a coderef
which will be executed upon successfully validating the input. Whether and
what the method returns is yours to decide.
Optionally the required hashref can have an "output" variable whose
value is either an arrayref of fields to be validated, or a constant value
which matches a validation profile name which will be used to perform data
validation
after the 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 switch to control how method input
validation failures are handled.
mixin¶
The mixin keyword (or mxn) creates a validation rules template that can be
applied to any field using the mixin directive. Mixin directives are processed
first so existing field directives will override the mixed-in directives.
package MyApp::User;
use Validation::Class;
mixin 'constrain' => {
required => 1,
min_length => 1,
max_length => 255,
...
};
# e.g.
field 'login' => {
mixin => 'constrain',
...
};
The mixin keyword takes two arguments, the mixin name and a hashref of
key/values pairs known as directives.
object¶
The object keyword (or obj) registers a class object builder which builds and
returns a class object on-demand. The object keyword also creates a method on
the calling class which invokes the builder. Unlike class attributes, this
method does not cache or otherwise store the returned class object it
constructs.
package MyApp::Database;
use DBI;
use Validation::Class;
fld name => {
required => 1,
};
fld host => {
required => 1,
};
fld port => {
required => 1,
};
fld user => {
required => 1,
};
fld pass => {
# ...
};
obj _build_dbh => {
type => 'DBI',
init => 'connect', # defaults to new
args => sub {
my ($self) = @_;
my @conn_str_parts =
('dbi', 'mysql', map { $self->$_ } qw(name host port));
return (join(':', @conn_str_parts), $self->user, $self->pass);
}
};
has dbh => sub { shift->_build_dbh }; # cache the _build_dbh object
sub connect {
my ($self) = @_;
my @parameters = ('name', 'host', 'port', 'user');
if ($self->validate(@parameters)) {
if ($self->dbh) {
my $db = $self->dbh;
# ... do something else with DBI
return 1;
}
$self->set_errors($DBI::errstr);
}
return 0;
}
package main;
my $database = MyApp::Database->new(
name => 'test',
host => 'localhost',
port => '3306',
user => 'root'
);
if ($database->connect) {
# ...
}
The object keyword takes two arguments, an object builder name and a hashref of
key/value pairs which are used to instruct the builder on how to construct the
object. The supplied hashref should be configured as follows:
{
# class to construct
type => 'ClassName',
# optional: constructor name (defaults to new)
init => 'new',
# optional: coderef which returns arguments for the constructor
args => sub {}
}
profile¶
The profile keyword (or pro) stores a validation profile (coderef) which as in
the traditional use of the term is a sequence of validation routines that
validate data relevant to a specific action.
package MyApp::User;
use Validation::Class;
profile 'signup' => sub {
my ($self, @args) = @_;
return $self->validate(qw(
+name
+email
+email_confirmation
-login
+password
+password_confirmation
));
};
package main;
my $user = MyApp::User->new(params => $params);
unless ($user->validate_profile('signup')) {
die $user->errors_to_string;
}
The profile keyword takes two arguments, a profile name and coderef which will
be used to execute a sequence of actions for validation purposes.
METHODS¶
new¶
The new method instantiates a new class object, it performs a series of actions
(magic) required for the class function properly, and for that reason, this
method should never be overridden. Use the build keyword to hooking into the
instantiation process.
package MyApp;
use Validation::Class;
# optionally
build sub {
my ($self) = @_; # is instantiated
};
package main;
my $app = MyApp->new;
...
prototype¶
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 "THE PROTOTYPE CLASS" in Validation::Class.
package MyApp;
use Validation::Class;
package main;
my $app = MyApp->new;
my $prototype = $app->prototype;
...
THE PROTOTYPE CLASS¶
This module provides mechanisms (sugar functions to model your data) which allow
you to define self-validating classes. Each class you create is associated
with a *prototype* class which provides data validation functionality and
keeps your class' namespace free from pollution, please see
Validation::Class::Prototype for more information on specific methods, and
attributes.
All derived classes will have a prototype-class attached to it which does all
the heavy lifting (regarding validation and error handling). The prototype
injects a few proxy methods into your class which are basically aliases to
your prototype class methods, however it is possible to access the prototype
directly using the proto/prototype methods.
package MyApp::User;
use Validation::Class;
package main;
my $user = MyApp::User->new;
my $proto = $user->prototype;
$proto->error_count # same as calling $self->error_count
THE OBJECT SYSTEM¶
All derived classes will benefit from the light-weight, straight-forward and
simple object system Validation::Class provides. The conventional constructor
"new" should be used to instantiate a new object, and the
"bld"/"build" keywords can be used to hook into the
instantiation process. Your classes can be configured to cooperate with an
existing design or modern OO framework like Moose, Mouse, Moo, etc. The
following example explains how to setup a Validation::Class class in
cooperation with Moose (while this example focuses on Moose, the approach is
the same regardless of the existing system):
package MyApp;
use Moose;
use Validation::Class 'field'; # only export as needed
sub BUILD {
my ($self, $args) = @_;
# you must run initialization routines yourself ...
# automatically run initialization routines
$self->initialize(params => $args->{params});
}
field login => {
min_length => 5
max_length => 50
};
field password => {
min_length => 8,
min_symbols => 1
max_length => 50
};
1;
This cooperation works by simply detecting the existence of a method named
"new", the name traditionally reserved for a class constructor which
if detected signals Validation::Class to install a method named
"initialize" as opposed to installing its own constructor. The
installed method, "initialize", encapsulates the functionality which
prepares the class for interaction with its corresponding prototype class,
this function must be called before using the Validation::Class features
provided. If this concept isn't clear to you you needn't worry as this is very
low-level, all you need you understand is that Validation::Class will install
a constructor or a method named initialize if a constructor already exists,
either way, the installed method should be called before executing methods on
the class.
As previously stated, Validation::Class injects a few proxy methods into your
class which are basically aliases to your prototype class methods. You can
find additional information on the prototype class and its method at
Validation::Class::Prototype. The following is a list of *proxy* methods,
methods which are injected into your class as shorthand to methods defined in
the prototype class (these methods are overridden):
class¶
$self->class;
See "class" in Validation::Class::Prototype for full documentation.
clear_queue¶
$self->clear_queue;
See "clear_queue" in Validation::Class::Prototype for full
documentation.
error_count¶
$self->error_count;
See "error_count" in Validation::Class::Prototype for full
documentation.
error_fields¶
$self->error_fields;
See "error_fields" in Validation::Class::Prototype for full
documentation.
errors¶
$self->errors;
See "errors" in Validation::Class::Prototype for full documentation.
head2 errors_to_string
$self->errors_to_string;
See "errors_to_string" in Validation::Class::Prototype for full
documentation.
get_errors¶
$self->get_errors;
See "get_errors" in Validation::Class::Prototype for full
documentation.
get_fields¶
$self->get_fields;
See "get_fields" in Validation::Class::Prototype for full
documentation.
get_params¶
$self->get_params;
See "get_params" in Validation::Class::Prototype for full
documentation.
fields¶
$self->fields;
See "fields" in Validation::Class::Prototype for full documentation.
filtering¶
$self->filtering;
See "filtering" in Validation::Class::Prototype for full
documentation.
hash_inflator¶
$self->hash_inflator;
See "hash_inflator" in Validation::Class::Prototype for full
documentation.
ignore_failure¶
$self->ignore_failure;
See "ignore_failure" in Validation::Class::Prototype for full
documentation.
ignore_unknown¶
$self->ignore_unknown;
See "ignore_unknown" in Validation::Class::Prototype for full
documentation.
param¶
$self->param;
See "param" in Validation::Class::Prototype for full documentation.
params¶
$self->params;
See "params" in Validation::Class::Prototype for full documentation.
plugin¶
$self->plugin;
See "plugin" in Validation::Class::Prototype for full documentation.
queue¶
$self->queue;
See "queue" in Validation::Class::Prototype for full documentation.
report_failure¶
$self->report_failure;
See "report_failure" in Validation::Class::Prototype for full
documentation.
report_unknown¶
$self->report_unknown;
See "report_unknown" in Validation::Class::Prototype for full
documentation.
reset_errors¶
$self->reset_errors;
See "reset_errors" in Validation::Class::Prototype for full
documentation.
reset_fields¶
$self->reset_fields;
See "reset_fields" in Validation::Class::Prototype for full
documentation.
reset_params¶
$self->reset_params;
See "reset_params" in Validation::Class::Prototype for full
documentation.
set_errors¶
$self->set_errors;
See "set_errors" in Validation::Class::Prototype for full
documentation.
set_fields¶
$self->set_fields;
See "set_fields" in Validation::Class::Prototype for full
documentation.
set_params¶
$self->set_params;
See "set_params" in Validation::Class::Prototype for full
documentation.
set_method¶
$self->set_method;
See "set_method" in Validation::Class::Prototype for full
documentation.
stash¶
$self->stash;
See "stash" in Validation::Class::Prototype for full documentation.
validate¶
$self->validate;
See "validate" in Validation::Class::Prototype for full documentation.
validate_profile¶
$self->validate_profile;
See "validate_profile" in Validation::Class::Prototype for full
documentation.
EXTENDING VALIDATION::CLASS¶
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¶
You might do well to look into Validate::Tiny for simple use-cases, it has
virtually no dependencies and solid test coverage. Data::Verifier is a great
approach to adding robust validation options to your existing Moose classes. I
have also heard some good things about Data::FormValidator as well.
AUTHOR¶
Al Newkirk <anewkirk@ana.io>
COPYRIGHT AND LICENSE¶
This software is copyright (c) 2011 by Al Newkirk.
This is free software; you can redistribute it and/or modify it under the same
terms as the Perl 5 programming language system itself.