[Catalyst] Data::FormValidator Plugin
Tomohiro Teranishi
tomohiro.teranishi at gmail.com
Sat Mar 24 14:33:13 GMT 2007
Hi,
I am a big fun of catalyst freamwork and I made a plugin for
Data::FormValidator called 'C::P::FormValidator::Lazy' . I am
wonderling if this plugin should stay in my local or publish to CPAN.
Can I have any suggestion??
I attach source code and also below is subversion repo url.
http://tomyhero-perl-module.googlecode.com/svn/trunk/Catalyst-Plugin-FormVa=
lidator-Lazy/
thanks,
Tomohiro
-------------- next part --------------
package Catalyst::Plugin::FormValidator::Lazy ;
use strict;
use warnings;
use base qw(Catalyst::Plugin::FormValidator);
use NEXT;
use UNIVERSAL::require;
our $VERSION =3D '0.01';
#{{{ setup
sub setup {
my $c =3D shift;
my $conf =3D $c->config->{form_validator_lazy};
my $pkg =3D $conf->{method_pkg} ;
$pkg->require or die $@;
$conf->{_strict}
=3D _make_constraints( $pkg , $conf->{strict} , 'strict' );
$conf->{_loose}
=3D _make_constraints( $pkg , $conf->{loose} , 'loose' );
$conf->{_regexp}
=3D _make_constraint_regexp_map( $pkg , $conf->{regexp_map} );
$c->NEXT::setup( @_ );
return $c;
}
#}}}
#{{{ has_dfv_error
sub has_dfv_error {
my $c =3D shift;
if ( $c->form->has_invalid or $c->form->has_missing ) {
return 1;
}
else {
return 0;
}
}
#}}}
#{{{ form =
sub form {
my $c =3D shift;
if ( $_[0] ) {
my $form =3D $_[1] ? {@_} : $_[0];
my $conf =3D $c->config->{form_validator_lazy};
my $custom_parameters =3D undef;
if ( !$form->{constraints} ) {
my %constraints =3D %{ $conf->{_strict} };
$form->{constraints} =3D \%constraints;
if ( $form->{constraints_loose} ) {
for my $key ( @{ $form->{constraints_loose} } ) {
$form->{constraints}{ $key } =3D $c->config->{_loose}{ =
$key };
}
delete $form->{constraints_loose};
}
}
if( !$form->{constraint_regexp_map} ) {
$form->{constraint_regexp_map} =3D $conf->{_regexp} ;
}
if( $form->{custom_parameters} ) {
$custom_parameters =3D $form->{custom_parameters} ;
delete $form->{custom_parameters} ;
}
$c->{form} =3D
Data::FormValidator->check( $custom_parameters || $c->request->pa=
rameters , $form );
if( $conf->{mess_stash} ){
for my $key ( $c->{form}->invalid ) {
$c->stash->{invalid}{ $key } =3D 1;
}
=
for my $key ( $c->{form}->missing ) {
$c->stash->{missing}{ $key } =3D 1;
}
}
}
return $c->{form};
}
#}}}
#{{{ _make_constraint_regexp_map
sub _make_constraint_regexp_map {
my $pkg =3D shift;
my $data =3D shift;
my $constraints =3D {};
foreach my $key ( keys %{ $data } ) {
my $value =3D $data->{ $key } ;
if( ref $value eq 'ARRAY' ) {
my $method =3D $value->[0]; =
my @args =3D @{ $value };
shift @args;
my $sub =3D $pkg . '::' . 'static' . '_' . $method ;
$constraints->{ qr/$key/ } =
=3D sub { =
my $item =3D shift ; =
no strict;
my $result =3D $sub->( $item , at args );
return $result;
}
;
}
else {
$constraints->{ qr/$key/ } =3D qr/$value/;
}
}
return $constraints;
}
#}}}
#{{{ _make_constraints
sub _make_constraints {
my $pkg =3D shift;
my $data =3D shift;
my $mode =3D shift;
my $constraints =3D {};
foreach my $key ( keys %{ $data } ) {
my $value =3D $data->{ $key };
if ( $value eq 'method' ) {
local *glob =3D $pkg . '::' . $mode . '_' . $key;
$constraints->{ $key } =3D \&glob ;
}
elsif ( ref $value eq 'ARRAY' ) {
my $method =3D $value->[0]; =
my @args =3D @{ $value };
shift @args;
my $sub =3D $pkg . '::' . 'static' . '_' . $method ;
$constraints->{ $key } =
=3D sub { =
my $item =3D shift ; =
no strict;
my $result =3D $sub->( $item , at args );
return $result;
}
;
}
else {
$constraints->{ $key } =3D qr/$value/;
}
}
return $constraints;
}
#}}}
1;
=3Dhead1 NAME
Catalyst::Plugin::FormValidator::Lazy - Catalst FormValidator Plugin in Laz=
y way =
=3Dhead1 DESCRIPTION
Instead of writting constraints in your controller source code , this plugi=
n let you
use config file. and more...
=3Dhead1 SYNOPSYS
use Catalyst qw( FormValidator::Lazy ); =
=
sub foo : Local {
my ( $s , $c ) =3D @_;
$c->form(
required =3D> [qw/user_name password monster/],
constraints_loose =3D> [qw/user_name/],
custom_parameters =3D> {
user_name =3D> 'tomyhero',
password =3D> 'hi_mom', =
monster =3D> 'doragon',
},
);
=
return if $c->has_dfv_error ;
# do something!
}
=
foo.tt
<td><input type=3D"text" name=3D"user_name"></td>
<td> [% IF invalid.user_name %]User Name Is Invalid [% END -%][% I=
F missing.user_name %]User Name is Missing [% END -%] </td>
app.yml
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
mess_stash : 1
regexp_map : =
'_id$' : '^\d+$'
'_cd$' : =
- string
strict :
user_name : method
password : '^[a-zA-Z0-9]+$'
doragon : =
- string
- 10 =
loose :
user_name : method
password : '.+'
TestApp/Constraints.pm
Package TestApp::Constraints;
sub strict_user_name {
my $value =3D shift;
return $value eq 'tomyhero' ? 1 : 0 ;
}
sub loose_user_name {
my $value =3D shift;
return 1 ;
}
sub static_string {
my $value =3D shift;
my $length =3D shift;
return length $value <=3D $length ? 1 : 0 ; =
}
1;
=3Dhead1 LAZY WAY
=3Dhead2 I want to forget about constraints. =
I am not a smart person who can think about many thing together. When I
codeing controller I evern not want to think about constraints. I want
to write constraints when I finish everything or when I finish design DB
layout or whatever when I feel I want to work on constraints staff. =
that is why this plugin use config file to solve this problem.
app.yml
form_validator_lazy :
strict :
user_name : '^[a-zA-Z0-9]+$' =
password : '^[a-zA-Z0-9]+$'
in your controller.
# even no constraints here , do not worry , it is ready!
$c->form(
required =3D> [qw/user_name password/],
);
=3Dhead2 I do not want config data is complicated.
I like simple. When I think about too much I always get headache.
I did not want to set constraints per controller like bellow.
controller_name_a:
user_name : '^[a-zA-Z0-9]+$'
password : '^[a-zA-Z0-9]+$'
controlller_name_b: =
user_name : '^[a-zA-Z0-9]+$'
password : '^[a-zA-Z0-9]+$'
When I design a system , I named request parameter very carefully so
that a parameter never contain different kind of validation . I mean below
situation never happen. =
# some case this
user_name =3D> qr/^[a-zA-Z]+$/;
# other case this
user_name =3D> qr/^[a-zA-Z0-9]+$/;
But I realize some case we need to have 2 kind of validation for a key. like
fazzy search...
form_validator_lazy :
strict :
user_name : qr/^[a-zA-Z]+$/
loose :
user_name : qr/^[a-zA-Z%]+$/
that is why you can set strict and loose for your config file. strict is
default. When you want to use loose constraints then,
$c->form(
required =3D> [qw/user_name/],
constraints_loose =3D> [qw/user_name/],
);
easy??
=3Dhead2 I want to use method for constraints!!!
Yeah , even I am lazy to create methods for constraints , I need them.. =
We need to set which package containt the methods
using config file.
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
How to write??
package TestApp::Constraints;
=
sub strict_user_name {
my $user_name =3D shift;
=
return $user_name eq 'tomyhero' ? 1 : 0 ;
}
=
sub loose_user_name {
my $user_name =3D shift;
return $user_name =3D~ /^tom/ ? 1 : 0 ;
}
1;
how to use it??
the keyword 'method' automatically read method from package. and the method
name is ${prefix}_${parameter_key_name} . =
app.yml
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
strict :
user_name : method # TestApp::Constraints::strict_user_name
loose :
user_name : method # TestApp::Constraints::loose_user_name
=
easy?
=3Dhead2 Oh.. I do not want same function but different name =
If I follow strict_ and loose_ methods rule then I will end up writng like
below methods.
package TestApp::Constraints;
=
sub strict_user_id {
my $id =3D shift;
return $id =3D~ /^\d+$/ ? 1 : 0 ;
}
sub strict_goods_id {
my $id =3D shift;
return $id =3D~ /^\d+$/ ? 1 : 0 ;
}
app.yml
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
strict :
user_id : method =
goods_id: method
I hate this. So that I add static_ prefix method...
how to use it??
app.yml
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
strict :
user_id : =
- number
goods_id:
- number
package TestApp::Constraints;
=
sub static_number {
my $id =3D shift;
return $id =3D~ /^\d+$/ ? 1 : 0 ;
}
Now , not really great but I think it OK.
I forget to tell , static_ method can have arg(s). =
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
strict :
user_id : =
- number =
- 10
goods_id:
- number
- 3
package TestApp::Constraints;
=
sub static_number {
my $id =3D shift;
my $length =3D shift;
return 0 of length $id > $length ; =
return $id =3D~ /^\d+$/ ? 1 : 0 ;
}
I think this is nice. =
=3Dhead2 I even do not want to type parameter at config.
Yeah , I am lazy to type even parameter key...
app.yml
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
strict :
user_id : '^\d+$' =
member_id: '^\d+$'
person_id: '^\d+$'
human_id : '^\d+$'
like this situation you can do like this. So you can save even typeing para=
meters!
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
regexp :
'_id$' : '^\d+$'
=3Dhead2 I am lazy to use two methods for error checking.
Instead of this
if ( $c->form->has_invalid or $c->form->has_missing ) {
$c->detach('hi_mom');
}
use this.
if( $c->has_dfv_error ) {
$c->detach('hi_mom');
}
=3Dhead2 I want to customaize parameters!!! =
you can use custom_parameters hash key!
# get parameters from custom_parameters instead of $c->request->paramet=
ers
# Of course you do not need to set if you do not use it. this is option=
. =
$c->form(
custom_parameters =3D> { user_name =3D> 'tomohiro' , password =3D> =
'hi_mom' },
required =3D> [qw/user_name password/],
);
=3Dhead2 I am lazy to retrive invalid or missing error key from array in so=
me case.
Desiners want to set error message at specific postision sometimes. =
app.yml
form_validator_lazy :
method_pkg : 'TestApp::Constraints'
mess_stash : 1 # default is off. so you must set it on
foo.tt
<td><input type=3D"text" name=3D"user_name"></td>
<td> [% IF invalid.user_name %]User Name Is Invalid [% END -%][% IF m=
issing.user_name %]User Name is Missing [% END -%] </td>
=3Dhead1 METHOD
=3Dhead2 form
Returns a L<Data::FormValidator::Results> object.
=3Dhead2 has_dfv_error
Having invalid or missing error or not.
=3Dhead1 SEE ALSO
L<Catalyst::Plugin::FormValidator>
L<Data::FormValidator>
=3Dhead1 AUTHOR
Tomohiro Teranishi C<tomohiro.teranishi at gmail.com>
=3Dcut
More information about the Catalyst
mailing list