DPLICATIONとデフォルトのバリデーション、DBIC_UNIQUE 対応。DBIC_UNIQUEは微妙な感じ。
--- ../Catalyst-Plugin-FormValidator-Simple-Auto-0.15/./lib/Catalyst/Plugin/FormValidator/Simple/Auto.pm 2007-04-10 10:57:23.000000000 +0900 +++ ./lib/Catalyst/Plugin/FormValidator/Simple/Auto.pm 2007-12-12 03:13:17.000000000 +0900 @@ -6,6 +6,7 @@ use Catalyst::Exception; use UNIVERSAL::isa; use YAML; +use Clone (); use FormValidator::Simple; our $VERSION = '0.15'; @@ -90,6 +91,63 @@ - rule: NOT_BLANK message: param1 is required! +=head1 OTHER SYNTAX + +The followings are a bit difference from normal way. + +=head2 DEFAULT RULE + +If you want to use same validation rule to same param. +You can write the follwing. + + # profiles.yml + DEFAULT: + password: + - rule: NOT_BLANK + message: password is required!!! + - rule: INT + message: password must be integer!!! + param1: + - rule: NOT_BLANK + message: param1 is required! + +This C<DEFAULT> is not action name. +This name is reserved to define common rule. +And write as the following. + + action1: + _USE_DEFAULT_ + - password + - param1 + +This C<_USE_DEFAULT_> is not param name. +In it, you can specify which common rule you use. + +=head2 COMBINATION CHECK + +For example, checking wheter 2 password is same or not. +Write the following. + + # profiles.yml + confirm: + password: + - rule: DUPLICATION + with: [password, password2] + message: 2 password must be same. + date: + - rule: DATE + with: [y, m, d] + message: y, m, d not date + +=head2 DBIC_UNIQUE + +You need FormValidator::Simple::Plugin::DBIC_UNIQUE. + + # profiles.yml + confirm: + - rule: [DBIC_UNIQUE, 'Bookmark', 'Bookmark', 'url'] + message: URL is unique + =head1 METHODS =head2 validator_profile @@ -138,22 +196,47 @@ $config->{profiles} = $profiles; } + # use Tie::Trace qw/:all/; + # watch my $profiles_multi; + my $profiles_multi = $config->{profiles_multi} = {}; my $messages; - my $profiles = $config->{profiles}; + + use Tie::Trace qw/:all/; + my $profiles; + $profiles = $config->{profiles}; + my $default_validation = Clone::clone $profiles->{DEFAULT}; + for my $action ( keys %{ $profiles || {} } ) { my $profile = $profiles->{$action} || {}; + if(my $use_default = delete $profile->{$c->config->{default_string} || '_USE_DEFAULT_'}){ + foreach my $param (@$use_default) { + my $rules = $profile->{$param}; + $profile->{$param} = $default_validation->{$param}; + if (defined $rules and ref $rules) { + push @{$profile->{$param}}, @$rules; + } + } + } + for my $param ( keys %$profile ) { my $rules = $profile->{$param} || []; my $i = 0; for my $rule (@$rules) { + if ( ref $rule eq 'HASH' and defined $rule->{rule} ) { my $rule_name = ref $rule->{rule} eq 'ARRAY' ? $rule->{rule}[0] : $rule->{rule}; $messages->{$action}{$param} ||= {}; $messages->{$action}{$param}{ $rule_name } = $rule->{message} if defined $rule->{message}; - $rule = $rule->{rule}; + if ( exists $rule->{with} and my @with = @{$rule->{with}} ) { + push @{$profiles_multi->{$action} ||= []}, { $param => \@with } => $rule->{rule}; + splice @$rules, $i, 1; + $i--; + } else { + $rule = $rule->{rule}; + } } elsif (ref $rule eq 'HASH' and defined $rule->{self_rule} ) { $messages->{$action}{$param} ||= {}; @@ -162,6 +245,7 @@ } $i++; } + # delete $profile->{$param} unless @$rules; } } @@ -185,14 +269,47 @@ sub prepare { my $c = shift->NEXT::prepare(@_); - if ( my $profile = $c->config->{validator}{profiles}{ $c->action->reverse } ) { - $c->validator_profile( $c->action->reverse ); - $c->form(%$profile); + my $action = $c->action->reverse; + my @profile = $c->_fvs_profile($action); + if ( @profile ) { + $c->validator_profile( $action ); + $c->form(@profile); } $c } +my %_fvs_profile; + +use Data::Dumper; + +sub _fvs_profile { + my($c, $action) = @_; + + return @{Clone::clone $_fvs_profile{$action}} if defined $_fvs_profile{$action}; + + my @profile = (%{$c->config->{validator}{profiles}{ $action } || {} }, @{$c->config->{validator}{profiles_multi}{$action} || []}); + + if (@profile) { + my $profile_max = $#profile; + for (my $i = 0; $i < $profile_max; $i +=2) { + my $rules = $profile[$i + 1]; + unless (ref $rules) { + $rules = $profile[$i + 1] = [$profile[$i + 1]]; + } + + foreach my $rule (@$rules) { + next if ref $rule ne 'ARRAY' or $rule->[0] ne 'DBIC_UNIQUE' or ($rule->[0] eq 'DBIC_UNIQUE' and ref $rule->[1]); + $rule->[1] = $c->model($rule->[1])->resultset($rule->[2]); + splice @$rule, 2, 1; + } + } + } + $_fvs_profile{$action} = \@profile; + + return @profile; +} + =head2 forward =cut @@ -204,12 +321,15 @@ local $NEXT::NEXT{ $c, 'forward' }; my $res; - if ( my $profile = $c->config->{validator}{profiles}{ $action } ) { + my @profile = $c->_fvs_profile($action); + + if ( @profile ) { + # first time validation if (not $c->validator_profile) { $c->{validator_profile} = $action; - $c->form(%$profile); + $c->form(@profile); $res = $c->NEXT::forward(@_); } else { @@ -217,7 +337,7 @@ local $c->{validator} = FormValidator::Simple->new; local $c->{validator_profile} = $action; - $c->form(%$profile); + $c->form(@profile); $res = $c->NEXT::forward(@_); } } --- ../Catalyst-Plugin-FormValidator-Simple-Auto-0.15/./t/03_store_profile.t 2007-04-08 02:02:32.000000000 +0900 +++ ./t/03_store_profile.t 2007-12-07 00:11:55.000000000 +0900 @@ -17,6 +17,10 @@ profiles => { action1 => { param1 => ['NOT_BLANK', 'ASCII'], + password => [{ + rule => 'DUPLICATION', + with => [qw/password1 password2/], + }] }, }, }, --- ../Catalyst-Plugin-FormValidator-Simple-Auto-0.15/./t/04_bundle_message.t 2007-04-10 10:55:33.000000000 +0900 +++ ./t/04_bundle_message.t 2007-12-07 00:11:55.000000000 +0900 @@ -15,11 +15,19 @@ name => 'TestApp', validator => { profiles => { + DEFAULT => { + password1 => [ { rule => 'NOT_BLANK', message => 'NOT_BLANK_P1!!!'} ], + password2 => [ { rule => 'NOT_BLANK', message => 'NOT_BLANK_P2!!!'} ], + }, action1 => { + _USE_DEFAULT_ => [qw/password1 password2/], param1 => [ { rule => 'NOT_BLANK', message => 'NOT_BLANK!!!' }, { rule => 'ASCII', message => 'ASCII!!!' }, ], + password => [ + { rule => 'DUPLICATION', with => [qw/password1 password2/] ,message => 'DUPLICATION!!!' }, + ], }, action2_submit => { param1 => [ 'NOT_BLANK', 'ASCII' ], }, action3 => { @@ -34,7 +42,13 @@ my ( $self, $c ) = @_; if ($c->form->has_error) { - $c->res->body( $c->form->message->get( $c->validator_profile, 'param1', $c->form->error('param1') ) ); +# $c->res->body( join ",", map $c->form->message->get( $c->validator_profile, $_, $c->form->error($_) ), qw/pram1 password/ ); + + my @msgs; + foreach my $p (sort $c->form->error){ + push @msgs, $c->form->message->get( $c->validator_profile, $p, $c->form->error($p)); + } + $c->res->body(join ",", @msgs); } else { $c->res->body('no errors'); @@ -80,12 +94,12 @@ # action driven validation ok( my $res = request('/action1'), 'request ok' ); -is( $res->content, 'NOT_BLANK!!!', 'is NOT_BLANK error'); +is( $res->content, 'NOT_BLANK!!!,NOT_BLANK_P1!!!,NOT_BLANK_P2!!!', 'is NOT_BLANK error'); -ok( $res = request('/action1?param1=aaa bbb'), 'request ok' ); +ok( $res = request('/action1?param1=aaa bbb&password1=123&password2=123'), 'request ok' ); is( $res->content, 'ASCII!!!', 'is ASCII error'); -ok( $res = request('/action1?param1=aaa'), 'request ok' ); +ok( $res = request('/action1?param1=aaa&password1=b&password2=b'), 'request ok' ); is( $res->content, 'no errors', 'is no errors'); --- ../Catalyst-Plugin-FormValidator-Simple-Auto-0.15/./t/02_basic.t 2007-02-18 12:55:55.000000000 +0900 +++ ./t/02_basic.t 2007-12-07 09:14:14.000000000 +0900 @@ -15,11 +15,28 @@ name => 'TestApp', validator => { profiles => { + DEFAULT => { + password1 => ['NOT_BLANK', 'INT'], + password2 => ['NOT_BLANK', 'INT'], + date => [ + { + rule => 'DATE', + with => [qw/y m d/], + }, + ], + }, action1 => { + _USE_DEFAULT_ => [qw/password1 password2 date/], param1 => ['NOT_BLANK', 'ASCII'], + password => [{rule => 'DUPLICATION', with => ['password1', 'password2'] }], }, action2_submit => { + _USE_DEFAULT_ => [qw/password1 password2/], param1 => ['NOT_BLANK', 'ASCII'], + password => [{ + rule => 'DUPLICATION', + with => ['password1', 'password2'] + }] }, }, }, @@ -30,7 +47,7 @@ my ( $self, $c ) = @_; if ($c->form->has_error) { - $c->res->body( $c->form->error('param1') ); + $c->res->body( join ",", map $c->form->error($_), sort $c->form->error); } else { $c->res->body('no errors'); @@ -52,7 +69,7 @@ my ( $self, $c ) = @_; if ($c->form->has_error) { - $c->res->body( $c->form->error('param1') ); + $c->res->body( join ",", map $c->form->error($_), sort $c->form->error); } else { $c->res->body('no errors'); @@ -61,29 +78,32 @@ } use Catalyst::Test 'TestApp'; -use Test::More tests => 14; +use Test::More tests => 16; use HTTP::Request::Common; # action driven validation ok( my $res = request('/action1'), 'request ok' ); -is( $res->content, 'NOT_BLANK', 'is NOT_BLANK error'); +is( $res->content, 'DATE,NOT_BLANK,NOT_BLANK,NOT_BLANK', 'is NOT_BLANK error'); -ok( $res = request('/action1?param1=aaa bbb'), 'request ok' ); -is( $res->content, 'ASCII', 'is ASCII error'); +ok( $res = request('/action1?param1=aaa bbb&password1=a&password2=a'), 'request ok' ); +is( $res->content, 'DATE,ASCII,INT,INT', 'is ASCII & INT error'); -ok( $res = request('/action1?param1=aaa'), 'request ok' ); +ok( $res = request('/action1?param1=aaa&password1=123&password2=1234&y=2007&m=13&d=31'), 'request ok' ); +is( $res->content, 'DATE,DUPLICATION', 'is DATE/DUPLICATION error'); + +ok( $res = request('/action1?param1=aaa&password1=1234&password2=1234&y=2007&m=12&d=31'), 'request ok' ); is( $res->content, 'no errors', 'is no errors'); # forward driven validation -ok( $res = request(POST '/action2', [ param1 => '' ]), 'request ok' ); -is( $res->content, 'NOT_BLANK', 'is NOT_BLANK error'); +ok( $res = request(POST '/action2', [ param1 => '', password1 => '', password2 => '' ]), 'request ok' ); +is( $res->content, 'NOT_BLANK,NOT_BLANK,NOT_BLANK', 'is NOT_BLANK error'); -ok( $res = request(POST '/action2', [ param1 => 'aaa bbb' ]), 'request ok' ); -is( $res->content, 'ASCII', 'is ASCII error'); +ok( $res = request(POST '/action2', [ param1 => 'aaa bbb', password1 => 'abc', password2=> 'abc' ]), 'request ok' ); +is( $res->content, 'ASCII,INT,INT', 'is ASCII/INT error'); -ok( $res = request(POST '/action2', [ param1 => 'ab' ]), 'request ok' ); +ok( $res = request(POST '/action2', [ param1 => 'ab', password1 => 123, password2=> 123 ]), 'request ok' ); is( $res->content, 'no errors', 'is no errors'); ok( $res = request('/action2'), 'request ok' );