—package
Dancer::Plugin::ValidateTiny;
use
strict;
use
warnings;
use
Dancer::Plugin;
use
Email::Valid;
our
$VERSION
=
'0.05'
;
my
$settings
= plugin_setting;
register
validator
=>
sub
{
my
(
$params
,
$rules_file
) =
@_
;
my
$result
= {};
# Loading rules from file
my
$rules
= _load_rules(
$rules_file
);
# Validating
my
$validator
= Validate::Tiny->new(
$params
,
$rules
);
# If you need a full Validate::Tiny object
if
(
$settings
->{is_full} eq 1)
{
return
$validator
;
}
if
(
$validator
->success)
{
# All ok
$result
= {
result
=>
$validator
->data,
valid
=>
$validator
->success
};
}
else
{
# Returning errors
if
(
exists
$settings
->{error_prefix})
{
# With error prefixes from config
$result
= {
result
=> _set_error_prefixes(
$validator
->error),
valid
=>
$validator
->success
};
}
else
{
# Without error prefixes
$result
= {
result
=>
$validator
->error,
valid
=>
$validator
->success
};
}
}
# Combining filtered params and validation results
%{
$result
->{result}} = (%{
$result
->{result}}, %{
$validator
->data});
# Returning validated data
return
$result
;
};
sub
_set_error_prefixes
{
my
$errors
=
shift
;
foreach
my
$error
(
keys
%{
$errors
})
{
# Replacing keys with prefix. O_o
$errors
->{
$settings
->{error_prefix} .
$error
} =
delete
$errors
->{
$error
};
}
return
$errors
;
}
sub
_load_rules
{
my
$rules_file
=
shift
;
# Checking plugin settings and rules file for existing
die
"Rules directory not specified in plugin settings!"
if
!
$settings
->{rules_dir};
die
"Rules file not specified!"
if
!
$rules_file
;
# Making full path to rules file
$rules_file
= setting(
'appdir'
) .
'/'
.
$settings
->{rules_dir} .
"/"
.
$rules_file
;
# Putting rules from file to $rules
my
$rules
=
do
$rules_file
||
die
$! .
"\n"
. $@;
return
$rules
;
}
sub
check_email
{
my
(
,
$message
) =
@_
;
Email::Valid->address(
) ?
undef
:
$message
;
}
register_plugin;
1;
__END__
=head1 NAME
Dancer::Plugin::ValidateTiny - Validate::Tiny Dancer plugin.
=head1 VERSION
Version 0.05
=head1 SYNOPSIS
Easy and cool validating data with L<Validate::Tiny> module:
use Dancer::Plugin::ValidateTiny;
post '/' => sub {
my $params = params;
my $data_valid = 0;
# Validating params with rule file
my $data = validator($params, 'form.pl');
if($data->{valid}) { ... }
};
Rule file is pretty too:
{
# Fields for validating
fields => [ qw/login email password password2/ ],
filters => [
qr/.+/ => filter(qw/trim strip/),
email => filter('lc'),
],
checks => [
[ qw/login email password password2/ ] => is_required("Field required!"),
login => is_long_between( 2, 25, 'Your login should have between 2 and 25 characters.' ),
email => sub {
check_email($_[0], "Please enter a valid email address.");
},
password => is_long_between( 4, 40, 'Your password should have between 4 and 40 characters.' ),
password2 => is_equal("password", "Passwords don't match"),
],
}
Note, that C<@_> in anonymous sub in C<checks> section contains value to be checked
and a reference to the filtered input hash. Check L<Validate::Tiny> documentation for
this.
=head1 DESCRIPTION
Simple Dancer plugin for use L<Validate::Tiny> module.
It provides simple use for L<Validate::Tiny> way of validating user input with
Dancer applications with some additions and modifications, such as separate files
for rules and additional functions for data validation.
=head1 METHODS
=head2 validator
This is the main method, that receiving C<params> from C<POST> or C<GET> (or whatever), and
filename, which contains rules for validation:
my $params = params;
my $data = validator($params, 'form.pl');
After this, in C<$data> you'll have a structure like:
{
'valid' => 0,
'result' => {
'err_login' => 'Your login should have between 4 and 25 characters.',
'err_email' => 'Please enter a valid email address.',
'err_password' => 'Field required!'
'login' => 'foo',
'email' => 'test input',
'password' => ''
}
};
Where C<valid> field is an indicator, that you can use like C<if($data-E<gt>{valid}) { ... }>.
And C<result> field, that contains B<already filtered> params and error messages for
them with special prefixes. Note, that you can set up L</error_prefix> in config file.
=head1 RULE FILES
In your Dancer application directory you need to create sub-directory for rule files
and place here rules, that you will use for validation. In this files you need to create
a simple structure like this one:
{
fields => [qw/city zip_code/],
checks => [
[qw/city zip_code/] => is_required("Field required!"),
city => is_long_at_most( 40, 'City name is too long' ),
zip_code => is_long_at_least( 5, 'Bad zip code' ),
],
}
For other rules, you can refer to the documentation of L<Validate::Tiny> module.
After creating rule file, you just need to specify it's name in L</validator> method.
Simple, yeah? :)
=head1 ADDITIONAL RULES
There is some additional subroutines, that you can use in rule files:
=head2 check_email
{
fields => "email",
filters => [
email => filter('trim', 'strip', 'lc')
],
checks => [
email => sub { check_email($_[0], "Please enter a valid e-mail address.") },
],
}
This subroutine checking e-mail address conforms to the RFC822 specification with L<Email::Valid>.
Note, that C<checks> processing data, that B<already filtered> by C<filters>.
=head1 CONFIG
In your config file you can use these settings:
plugins:
ValidateTiny:
rules_dir: validation
error_prefix: err_
is_full: 0
Where:
=head2 rules_dir
Directory, where you will store your rule files. Plugin looking it in your Dancer
application root.
=head2 error_prefix
Prefix, that used to separate error fields from normal values in C<result> hash.
It is very convenient when you use the template engine, such as L<Template::Toolkit>
or L<HTML::Template>. You simply pass the data to the template engine, and it handles
the logic of output errors and/or warnings for user.
=head2 is_full
If this option is set to C<1>, call of C<validator> returning
an object, that you can use as standart L<Validate::Tiny> object.
=head1 SEE ALSO
L<Validate::Tiny> L<Dancer::Plugin::FormValidator> L<Dancer::Plugin::DataFu>
=head1 AUTHOR
Alexey Kolganov, C<< <kalgan@cpan.org> >>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2011 by Alexey Kolganov
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.1 or,
at your option, any later version of Perl 5 you may have available.
=cut