Validation with simple chains of constraints
my $query = CGI->new; $query->param( param1 => 'ABCD' ); $query->param( param2 => 12345 ); $query->param( mail1 => '[email protected]' ); $query->param( mail2 => '[email protected]' ); $query->param( year => 2005 ); $query->param( month => 11 ); $query->param( day => 27 ); my $result = FormValidator::Simple->check( $query => [ param1 => ['NOT_BLANK', 'ASCII', ['LENGTH', 2, 5]], param2 => ['NOT_BLANK', 'INT' ], mail1 => ['NOT_BLANK', 'EMAIL_LOOSE'], mail2 => ['NOT_BLANK', 'EMAIL_LOOSE'], { mails => ['mail1', 'mail2' ] } => ['DUPLICATION'], { date => ['year', 'month', 'day'] } => ['DATE'], ] ); if ( $result->has_error ) { my $tt = Template->new({ INCLUDE_PATH => './tmpl' }); $tt->process('template.html', { result => $result }); }
template example
[% IF result.has_error %] <p>Found Input Error</p> <ul>
[% IF result.missing('param1') %] <li>param1 is blank.</li> [% END %]
[% IF result.invalid('param1') %] <li>param1 is invalid.</li> [% END %]
[% IF result.invalid('param1', 'ASCII') %] <li>param1 needs ascii code.</li> [% END %]
[% IF result.invalid('param1', 'LENGTH') %] <li>input into param1 with characters that's length should be between two and five. </li> [% END %]
</ul> [% END %]
example2
[% IF result.has_error %] <ul> [% FOREACH key IN result.error %] [% FOREACH type IN result.error(key) %] <li>invalid: [% key %] - [% type %]</li> [% END %] [% END %] </ul> [% END %]
This module provides you a sweet way of form data validation with simple constraints chains. You can write constraints on single line for each input data.
This idea is based on Sledge::Plugin::Validator, and most of validation code is borrowed from this plugin.
(Sledge is a \s-1MVC\s0 web application framework: http://sl.edge.jp [Japanese] )
The result object this module returns behaves like Data::FormValidator::Results.
FormValidator::Simple->check( $q => [ #profile ] );
Use 'check' method.
A hash reference includes input data, or an object of some class that has a method named 'param', for example \s-1CGI\s0, is needed as first argument.
And set profile as array reference into second argument. Profile consists of some pairs of input data and constraints.
my $q = CGI->new; $q->param( param1 => 'hoge' );
FormValidator::Simple->check( $q => [ param1 => [ ['NOT_BLANK'], ['LENGTH', 4, 10] ], ] );
In this case, param1 is the name of a form element. and the array ref \*(L"[ ['\s-1NOT_BLANK\s0']... ]\*(R" is a constraints chain.
Write constraints chain as arrayref, and you can set some constraints into it. In the last example, two constraints '\s-1NOT_BLANK\s0', and '\s-1LENGTH\s0' are set. Each constraints is should be set as arrayref, but in case the constraint has no argument, it can be written as scalar text.
FormValidator::Simple->check( $q => [ param1 => [ 'NOT_BLANK', ['LENGTH', 4, 10] ], ] );
Now, in this sample '\s-1NOT_BLANK\s0' constraint is not an arrayref, but '\s-1LENGTH\s0' isn't. Because '\s-1LENGTH\s0' has two arguments, 4 and 10.
When you want to check about multiple input data, do like this.
my $q = CGI->new; $q->param( mail1 => '[email protected]' ); $q->param( mail2 => '[email protected]' );
my $result = FormValidator::Simple->check( $q => [ { mails => ['mail1', 'mail2'] } => [ 'DUPLICATION' ], ] )
[% IF result.invalid('mails') %] <p>mail1 and mail2 aren't same.</p> [% END %]
and here's an another example.
my $q = CGI->new; $q->param( year => 2005 ); $q->param( month => 12 ); $q->param( day => 27 );
my $result = FormValidator::Simple->check( $q => [ { date => ['year', 'month', 'day'] } => [ 'DATE' ], ] );
[% IF result.invalid('date') %] <p>Set correct date.</p> [% END %]
my $valid = FormValidator::Simple->new();
$valid->check( $q => [ param1 => [qw/NOT_BLANK ASCII/, [qw/LENGTH 4 10/] ], ] );
$valid->check( $q => [ param2 => [qw/NOT_BLANK/], ] );
my $results = $valid->results;
if ( found some error... ) { $results->set_invalid('param3' => 'MY_ERROR'); }
template example
[% IF results.invalid('param1') %] ... [% END %] [% IF results.invalid('param2') %] ... [% END %] [% IF results.invalid('param3', 'MY_ERROR') %] ... [% END %]
Option setting is needed by some validation, especially in plugins.
You can set them in two ways.
FormValidator::Simple->set_option( dbic_base_class => 'MyProj::Model::DBIC', charset => 'euc', );
or
$valid = FormValidator::Simple->new( dbic_base_class => 'MyProj::Model::DBIC', charset => 'euc', );
$valid->check(...)
You can use follow variety validations. and each validations can be used as negative validation with '\s-1NOT_\s0' prefix.
FormValidator::Simple->check( $q => [ param1 => [ 'INT', ['LENGTH', 4, 10] ], param2 => [ 'NOT_INT', ['NOT_LENGTH', 4, 10] ], ] );
check if the data has space or not.
check if the data is integer or not.
unsigined integer check. for example, if -1234 is input, the validation judges it invalid.
$q->param( 'num1' => '123.45678' );
my $result = FormValidator::Simple->check( $q => [ num1 => [ ['DECIMAL', 3, 5] ], ] ); each numbers (3,5) mean maximum digits before/after '.'
check is the data consists of only ascii code.
check the length of the data. my $result = FormValidator::Simple->check( $q => [ param1 => [ ['LENGTH', 4] ], ] ); check if the length of the data is 4 or not. my $result = FormValidator::Simple->check( $q => [ param1 => [ ['LENGTH', 4, 10] ], ] ); when you set two arguments, it checks if the length of data is in the range between 4 and 10.
verify it is a http(s)-url my $result = FormValidator::Simple->check( $q => [ param1 => [ 'HTTP_URL' ], ] );
verify the quantity of selected parameters is counted over allowed minimum. <input type="checkbox" name="hobby" value="music" /> Music <input type="checkbox" name="hobby" value="movie" /> Movie <input type="checkbox" name="hobby" value="game" /> Game
my $result = FormValidator::Simple->check( $q => [ hobby => ['NOT_BLANK', ['SELECTED_AT_LEAST', 2] ], ] );
check with regular expression. my $result = FormValidator::Simple->check( $q => [ param1 => [ ['REGEX', qr/^hoge$/ ] ], ] );
check if the two data are same or not. my $result = FormValidator::Simple->check( $q => [ { duplication_check => ['param1', 'param2'] } => [ 'DUPLICATION' ], ] );
check with Email::Valid.
check with Email::Valid, including mx check.
check with Email::Valid::Loose.
check with Email::Valid::Loose, including mx check.
check with Date::Calc my $result = FormValidator::Simple->check( $q => [ { date => [qw/year month day/] } => [ 'DATE' ] ] );
check with Date::Calc my $result = FormValidator::Simple->check( $q => [ { time => [qw/hour min sec/] } => ['TIME'], ] );
check with Date::Calc my $result = FormValidator::Simple->check( $q => [ { datetime => [qw/year month day hour min sec/] } => ['DATETIME'] ] );
check with DateTime::Format::Strptime. my $q = CGI->new; $q->param( datetime => '2006-04-26T19:09:21+0900' );
my $result = FormValidator::Simple->check( $q => [ datetime => [ [ 'DATETIME_STRPTIME', '%Y-%m-%dT%T%z' ] ], ] );
check with DateTime::Format::***. for example, DateTime::Format::HTTP, DateTime::Format::Mail, DateTime::Format::MySQL and etc. my $q = CGI->new; $q->param( datetime => '2004-04-26 19:09:21' );
my $result = FormValidator::Simple->check( $q => [ datetime => [ [qw/DATETIME_FORMAT MySQL/] ], ] );
numeric comparison my $result = FormValidator::Simple->check( $q => [ age => [ ['GREATER_THAN', 25] ], ] );
numeric comparison my $result = FormValidator::Simple->check( $q => [ age => [ ['LESS_THAN', 25] ], ] );
numeric comparison my $result = FormValidator::Simple->check( $q => [ age => [ ['EQUAL_TO', 25] ], ] );
numeric comparison my $result = FormValidator::Simple->check( $q => [ age => [ ['BETWEEN', 20, 25] ], ] );
check if there is not blank data in multiple data. my $result = FormValidator::Simple->check( $q => [ { some_data => [qw/param1 param2 param3/] } => ['ANY'] ] );
check if the food ordered is in menu my $result = FormValidator::Simple->check( $q => [ food => [ ['IN_ARRAY', qw/noodle soba spaghetti/] ], ] };
use FormValidator::Simple qw/Japanese CreditCard/;
FormValidator::Simple::Plugin::Japanese, FormValidator::Simple::Plugin::CreditCard are loaded.
or use 'load_plugin' method.
use FormValidator::Simple; FormValidator::Simple->load_plugin('FormValidator::Simple::Plugin::CreditCard');
If you want to load plugin which name isn't in FormValidator::Simple::Plugin namespace, use +.
use FormValidator::Simple qw/+MyApp::ValidatorPlugin/;
You can custom your own message with key and type.
[% IF result.has_error %] [% FOREACH key IN result.error %] [% FOREACH type IN result.error(key) %] <p>error message:[% type %] - [% key %]</p> [% END %] [% END %] [% END %]
And you can also set messages configuration before. You can prepare configuration as hash reference.
FormValidator::Simple->set_messages( { action1 => { name => { NOT_BLANK => 'input name!', LENGTH => 'input name (length should be between 0 and 10)!', }, email => { DEFAULT => 'input correct email address!', }, }, } );
or a \s-1YAML\s0 file.
# messages.yml DEFAULT: name: DEFAULT: name is invalid! action1: name: NOT_BLANK: input name! LENGTH: input name(length should be between 0 and 10)! email: DEFAULT: input correct email address! action2: name: DEFAULT: ...
# in your perl-script, set the file's path. FormValidator::Simple->set_messages('messages.yml');
\s-1DEFAULT\s0 is a special type. If it can't find setting for indicated validation-type, it uses message set for \s-1DEFAULT\s0.
after setting, execute check(),
my $result = FormValidator::Simple->check( $q => [ name => [qw/NOT_BLANK/, [qw/LENGTH 0 10/] ], email => [qw/NOT_BLANK EMAIL_LOOSE/, [qw/LENGTH 0 20/] ], ] );
# matching result and messages for indicated action. my $messages = $result->messages('action1');
foreach my $message ( @$messages ) { print $message, "\n"; }
# or you can get messages as hash style. # each fieldname is the key my $field_messages = $result->field_messages('action1'); if ($field_messages->{name}) { foreach my $message ( @{ $field_messages->{name} } ) { print $message, "\n"; } }
When it can't find indicated action, name, and type, it searches proper message from \s-1DEFAULT\s0 action. If in template file,
[% IF result.has_error %] [% FOREACH msg IN result.messages('action1') %] <p>[% msg %]</p> [% END %] [% END %]
you can set each message format.
FormValidator::Simple->set_message_format('<p>%s</p>'); my $result = FormValidator::Simple->check( $q => [ ...profile ] );
[% IF result.has_error %] [% result.messages('action1').join("\n") %] [% END %]
See FormValidator::Simple::Results
If you set encoding like follows, it automatically decode the result messages.
FormValidtor::Simple->set_mesasges_decode_from('utf-8');
Data::FormValidator
http://sl.edge.jp/ (Japanese)
http://sourceforge.jp/projects/sledge
Lyo Kato <[email protected]>
This library is free software. You can redistribute it and/or modify it under the same terms as perl itself.