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-FormValidator-Lazy/

thanks,

Tomohiro
package Catalyst::Plugin::FormValidator::Lazy ;

use strict;
use warnings;
use base qw(Catalyst::Plugin::FormValidator);
use NEXT;
use UNIVERSAL::require;

our $VERSION = '0.01';

#{{{ setup
sub setup {
    my $c = shift;

    my $conf = $c->config->{form_validator_lazy};
    my $pkg = $conf->{method_pkg} ;
    $pkg->require or die $@;

    $conf->{_strict}
        = _make_constraints( $pkg , $conf->{strict} , 'strict' );

    $conf->{_loose}
        = _make_constraints( $pkg , $conf->{loose} , 'loose' );

    $conf->{_regexp}
        = _make_constraint_regexp_map( $pkg , $conf->{regexp_map} );

    $c->NEXT::setup( @_ );

    return $c;
}
#}}}

#{{{ has_dfv_error
sub has_dfv_error {
    my $c = shift;

    if ( $c->form->has_invalid or $c->form->has_missing ) {
        return 1;
    }
    else {
        return 0;
    }
}
#}}}

#{{{ form 
sub form {
    my $c = shift;
    if ( $_[0] ) {
        my $form = $_[1] ? [EMAIL PROTECTED] : $_[0];
        my $conf = $c->config->{form_validator_lazy};
        my $custom_parameters = undef;

        if ( !$form->{constraints} ) {
            my %constraints = %{ $conf->{_strict} };
            $form->{constraints} = \%constraints;

            if ( $form->{constraints_loose} ) {
                for my $key ( @{ $form->{constraints_loose} } ) {
                    $form->{constraints}{ $key } = $c->config->{_loose}{ $key };
                }
                delete $form->{constraints_loose};
            }

        }
        if( !$form->{constraint_regexp_map} ) {
            $form->{constraint_regexp_map} = $conf->{_regexp} ;
        }

        if( $form->{custom_parameters} ) {
            $custom_parameters = $form->{custom_parameters} ;
            delete $form->{custom_parameters} ;
        }

        $c->{form} =
          Data::FormValidator->check( $custom_parameters || 
$c->request->parameters , $form );

        if( $conf->{mess_stash} ){
            for my $key ( $c->{form}->invalid  ) {
                $c->stash->{invalid}{ $key } = 1;
            }
        
            for my $key ( $c->{form}->missing  ) {
                $c->stash->{missing}{ $key } = 1;
            }
        }
    }
    return $c->{form};
}
#}}}

#{{{ _make_constraint_regexp_map
sub _make_constraint_regexp_map {
    my $pkg  = shift;
    my $data = shift;
    my $constraints = {};
    foreach my $key ( keys %{ $data } ) {
             my $value = $data->{ $key } ;
             if( ref $value eq 'ARRAY' ) {
                my $method = $value->[0]; 
                my @args = @{ $value };
                shift @args;
                my $sub =  $pkg . '::' . 'static' .  '_' .  $method  ;
                $constraints->{ qr/$key/ } 
                    = sub { 
                        my $item = shift ; 
                        no strict;
                        my $result =  $sub->( $item  ,@args );
                        return $result;
                      }
                    ;
             }
             else {
                $constraints->{ qr/$key/ } = qr/$value/;
             }
    }

    return $constraints;
}
#}}}

#{{{ _make_constraints
sub _make_constraints {
    my $pkg  = shift;
    my $data = shift;
    my $mode = shift;

    my $constraints = {};

    foreach my $key ( keys %{ $data } ) {
        my $value = $data->{ $key };

        if ( $value eq 'method' ) {
            local *glob =  $pkg . '::' . $mode .  '_' .  $key;
            $constraints->{ $key } = \&glob ;
        }
        elsif ( ref $value eq 'ARRAY' ) {
            my $method = $value->[0]; 
            my @args = @{ $value };
            shift @args;
            my $sub =  $pkg . '::' . 'static' .  '_' .  $method  ;
            $constraints->{ $key } 
                = sub { 
                    my $item = shift ; 
                    no strict;
                    my $result =  $sub->( $item  ,@args );
                    return $result;
                  }
                ;
        }
        else {
             $constraints->{ $key } = qr/$value/;
        }
    }
    return $constraints;
}
#}}}

1;

=head1 NAME

Catalyst::Plugin::FormValidator::Lazy - Catalst FormValidator Plugin in Lazy 
way 

=head1 DESCRIPTION

Instead of writting constraints in your controller source code , this plugin 
let you
use config file. and more...

=head1 SYNOPSYS

 use Catalyst qw( FormValidator::Lazy ); 
 
 sub foo : Local {
    my ( $s , $c ) = @_;
    $c->form(
        required            => [qw/user_name password monster/],
        constraints_loose   => [qw/user_name/],
        custom_parameters   => {
                                    user_name => 'tomyhero',
                                    password  => 'hi_mom', 
                                    monster   => 'doragon',
                                },
     );
     
     return if $c->has_dfv_error ;

    # do something!
 }
 
foo.tt

    <td><input type="text" name="user_name"></td>
    <td>&nbsp;[% IF invalid.user_name %]User Name Is Invalid [% END -%][% IF 
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 = shift;
    return $value eq 'tomyhero' ? 1 : 0 ;
 }

 sub loose_user_name {
    my $value = shift;
    return 1 ;
 }

 sub static_string {
    my $value  = shift;
    my $length = shift;

    return length $value <= $length ? 1 : 0 ; 
 }

 1;

=head1 LAZY WAY

=head2 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 => [qw/user_name password/],
    );

=head2 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 => qr/^[a-zA-Z]+$/;
 # other case this
 user_name => 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 => [qw/user_name/],
    constraints_loose => [qw/user_name/],
 );

easy??

=head2 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 = shift;
    
        return $user_name eq 'tomyhero' ? 1 : 0 ;
    }
    
    sub loose_user_name {
        my $user_name = shift;
        return $user_name =~ /^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?

=head2 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 = shift;
        return $id =~ /^\d+$/ ? 1 : 0 ;
    }

    sub strict_goods_id {
        my $id = shift;
        return $id =~ /^\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 = shift;
        return $id =~ /^\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     = shift;
        my $length = shift;
        return 0 of length $id > $length ; 
        return $id =~ /^\d+$/ ? 1 : 0 ;
    }

I think this is nice. 

=head2 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 
parameters!

 form_validator_lazy :
    method_pkg : 'TestApp::Constraints'
    regexp     :
        '_id$' : '^\d+$'

=head2 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');
    }

=head2 I want to customaize parameters!!! 

you can use custom_parameters hash key!

    # get parameters from custom_parameters instead of $c->request->parameters
    # Of course you do not need to set if you do not use it. this is option. 
    $c->form(
        custom_parameters => { user_name => 'tomohiro' , password => 'hi_mom' },
        required => [qw/user_name password/],
    );

=head2 I am lazy to retrive invalid or missing error key from array in some 
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="text" name="user_name"></td>
 <td>&nbsp;[% IF invalid.user_name %]User Name Is Invalid [% END -%][% IF 
missing.user_name %]User Name is Missing [% END -%] </td>

=head1 METHOD

=head2 form

Returns a L<Data::FormValidator::Results> object.

=head2 has_dfv_error

Having invalid or missing error or not.

=head1 SEE ALSO

L<Catalyst::Plugin::FormValidator>
L<Data::FormValidator>

=head1 AUTHOR

Tomohiro Teranishi C<[EMAIL PROTECTED]>

=cut

_______________________________________________
List: [email protected]
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/[email protected]/
Dev site: http://dev.catalyst.perl.org/

Reply via email to