[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>&nbsp;[% 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>&nbsp;[% 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