root/lang/perl/Catalyst-Plugin-FormValidator-Lazy/trunk/lib/Catalyst/Plugin/FormValidator/Lazy.pm @ 2788

Revision 2788, 12.5 kB (checked in by tomyhero, 5 years ago)

lang/perl/Catalyst-Plugin-FormValidator?-Lazy : I remove prepre method before but I return it back for some reason.

Line 
1package Catalyst::Plugin::FormValidator::Lazy ;
2
3use strict;
4use warnings;
5use NEXT;
6use UNIVERSAL::require;
7use Data::FormValidator;
8
9our $VERSION = '0.05';
10
11#{{{ setup
12sub setup {
13    my $c = shift;
14
15    my $conf = $c->config->{form_validator_lazy};
16    my $pkg = $conf->{method_pkg} ;
17    $pkg->require or die $@;
18
19    $conf->{_strict}
20        = _make_constraints( $pkg , $conf->{strict} , 'strict' );
21
22    $conf->{_loose}
23        = _make_constraints( $pkg , $conf->{loose} , 'loose' );
24
25    $conf->{_regexp}
26        = _make_constraint_regexp_map( $pkg , $conf->{regexp_map} );
27
28    $c->NEXT::setup( @_ );
29
30    return $c;
31}
32#}}}
33
34
35#{{{ has_dfv_error
36sub has_dfv_error {
37    my $c = shift;
38
39    if ( $c->form->has_invalid or $c->form->has_missing or exists $c->stash->{custom_invalid} ) {
40        return 1;
41    }
42    else {
43        return 0;
44    }
45}
46#}}}
47
48sub prepare {
49    my $c = shift;
50    $c = $c->NEXT::prepare(@_);
51    $c->{form} = Data::FormValidator->check( $c->request->parameters, {} );
52    return $c;
53}
54
55#{{{ form
56sub form {
57    my $c = shift;
58    if ( $_[0] ) {
59        my $form = $_[1] ? {@_} : $_[0];
60        my $conf = $c->config->{form_validator_lazy};
61        my $custom_parameters = undef;
62
63        if ( !$form->{constraints} ) {
64            my %constraints = %{ $conf->{_strict} };
65            $form->{constraints} = \%constraints;
66
67            if ( $form->{constraints_loose} ) {
68                for my $key ( @{ $form->{constraints_loose} } ) {
69                    $form->{constraints}{ $key } = $c->config->{_loose}{ $key };
70                }
71                delete $form->{constraints_loose};
72            }
73
74        }
75        if( !$form->{constraint_regexp_map} ) {
76            $form->{constraint_regexp_map} = $conf->{_regexp} ;
77        }
78
79        if( $form->{custom_parameters} ) {
80            $custom_parameters = $form->{custom_parameters} ;
81            delete $form->{custom_parameters} ;
82        }
83
84        $c->{form} =
85          Data::FormValidator->check( $custom_parameters || $c->request->parameters , $form );
86
87        $c->stash->{v} = $c->{form}{valid} ;
88        for my $key ( $c->{form}->invalid  ) {
89            $c->stash->{invalid}{ $key } = 1;
90        }
91
92        for my $key ( $c->{form}->missing  ) {
93            $c->stash->{missing}{ $key } = 1;
94        }
95    }
96    return $c->{form};
97}
98#}}}
99
100#{{{ dfv_push_invalid
101sub dfv_push_invalid {
102    my $c   = shift;
103    my $key = shift;
104   
105    if ( ref $key eq 'ARRAY') {
106        $c->stash->{custom_invalid} = {};
107        &_array2hashkey( $c->stash->{custom_invalid} , $key , 1 );
108    }
109    else {
110        $c->stash->{custom_invalid}{ $key } = 1;
111    }
112
113}
114#}}}
115
116#{{{ _array2hashkey
117sub _array2hashkey {
118    my $hash  = shift;
119    my $keys  = shift;
120    my $value = shift;
121
122    return if !scalar @{ $keys };
123
124    my $key = shift @{$keys};
125    $hash->{$key} = scalar @{ $keys } ? {} : $value;
126    _array2hashkey( $hash->{$key} , $keys , $value ) ;
127}
128#}}}
129
130#{{{ _make_constraint_regexp_map
131sub _make_constraint_regexp_map {
132    my $pkg  = shift;
133    my $data = shift;
134    my $constraints = {};
135    foreach my $key ( keys %{ $data } ) {
136             my $value = $data->{ $key } ;
137             if( ref $value eq 'ARRAY' ) {
138                my $method = $value->[0];
139                my @args = @{ $value };
140                shift @args;
141                my $sub =  $pkg . '::' . 'static' .  '_' .  $method  ;
142                $constraints->{ qr/$key/ }
143                    = sub {
144                        my $item = shift ;
145                        no strict;
146                        my $result =  $sub->( $item  ,@args );
147                        return $result;
148                      }
149                    ;
150             }
151             else {
152                $constraints->{ qr/$key/ } = qr/$value/;
153             }
154    }
155
156    return $constraints;
157}
158#}}}
159
160#{{{ _make_constraints
161sub _make_constraints {
162    my $pkg  = shift;
163    my $data = shift;
164    my $mode = shift;
165
166    my $constraints = {};
167
168    foreach my $key ( keys %{ $data } ) {
169        my $value = $data->{ $key };
170
171        if ( $value eq 'method' ) {
172            local *glob =  $pkg . '::' . $mode .  '_' .  $key;
173            $constraints->{ $key } = \&glob ;
174        }
175        elsif ( ref $value eq 'ARRAY' ) {
176            my $method = $value->[0];
177            my @args = @{ $value };
178            shift @args;
179            my $sub =  $pkg . '::' . 'static' .  '_' .  $method  ;
180            $constraints->{ $key }
181                = sub {
182                    my $item = shift ;
183                    no strict;
184                    my $result =  $sub->( $item  ,@args );
185                    return $result;
186                  }
187                ;
188        }
189        else {
190             $constraints->{ $key } = qr/$value/;
191        }
192    }
193    return $constraints;
194}
195#}}}
196
1971;
198
199=head1 NAME
200
201Catalyst::Plugin::FormValidator::Lazy - Catalyst FormValidator Plugin in Lazy way
202
203=head1 DESCRIPTION
204
205Instead of writting constraints in your controller source code , this plugin let you
206use config file. and more...
207
208=head1 SYNOPSYS
209
210 use Catalyst qw( FormValidator::Lazy );
211 
212 sub foo : Local {
213    my ( $s , $c ) = @_;
214    $c->form(
215        required            => [qw/user_name password monster/],
216        constraints_loose   => [qw/user_name/],
217        custom_parameters   => {
218                                    user_name => 'tomyhero',
219                                    password  => 'hi_mom',
220                                    monster   => 'doragon',
221                                },
222     );
223     
224     return if $c->has_dfv_error ;
225
226    # do something!
227 }
228 
229foo.tt
230
231    <td><input type="text" name="user_name"></td>
232    <td>&nbsp;[% IF invalid.user_name %]User Name Is Invalid [% END -%][% IF missing.user_name %]User Name is Missing [% END -%] </td>
233
234app.yml
235
236 form_validator_lazy :
237    method_pkg : 'TestApp::Constraints'
238    regexp_map :
239        '_id$' : '^\d+$'
240        '_cd$' :
241            - string
242    strict     :
243        user_name : method
244        password  : '^[a-zA-Z0-9]+$'
245        doragon   :
246            - string
247            - 10
248   loose       :
249        user_name : method
250        password  : '.+'
251
252TestApp/Constraints.pm
253
254 Package TestApp::Constraints;
255
256 sub strict_user_name {
257    my $value = shift;
258    return $value eq 'tomyhero' ? 1 : 0 ;
259 }
260
261 sub loose_user_name {
262    my $value = shift;
263    return 1 ;
264 }
265
266 sub static_string {
267    my $value  = shift;
268    my $length = shift;
269
270    return length $value <= $length ? 1 : 0 ;
271 }
272
273 1;
274
275=head1 LAZY WAY
276
277=head2 I want to forget about constraints.
278
279I am not a smart person who can think about many thing together. When I
280codeing controller I evern not want to think about constraints. I want
281to write constraints when I finish everything or when I finish design DB
282layout or whatever when I feel I want to work on constraints staff.
283
284that is why this plugin use config file to solve this problem.
285
286app.yml
287
288 form_validator_lazy :
289    strict     :
290        user_name : '^[a-zA-Z0-9]+$'
291        password  : '^[a-zA-Z0-9]+$'
292
293in your controller.
294
295    # even no constraints here , do not worry , it is ready!
296    $c->form(
297        required => [qw/user_name password/],
298    );
299
300=head2 I do not want config data is complicated.
301
302I like simple. When I think about too much I always get headache.
303I did not want to set constraints per controller like bellow.
304
305 controller_name_a:
306    user_name : '^[a-zA-Z0-9]+$'
307    password  : '^[a-zA-Z0-9]+$'
308 controlller_name_b:
309    user_name : '^[a-zA-Z0-9]+$'
310    password  : '^[a-zA-Z0-9]+$'
311
312When I design  a system , I named request parameter very carefully so
313that a parameter never contain different kind of validation . I mean below
314situation never happen.
315
316 # some case this
317 user_name => qr/^[a-zA-Z]+$/;
318 # other case this
319 user_name => qr/^[a-zA-Z0-9]+$/;
320
321But I realize some case we need to have 2 kind of validation for a key. like
322fazzy search...
323
324 form_validator_lazy :
325    strict     :
326        user_name : qr/^[a-zA-Z]+$/
327    loose      :
328        user_name : qr/^[a-zA-Z%]+$/
329
330that is why you can set strict and loose for your config file.  strict is
331default. When you want to use loose constraints then,
332
333 $c->form(
334    required => [qw/user_name/],
335    constraints_loose => [qw/user_name/],
336 );
337
338easy??
339
340=head2 I want to use method for constraints!!!
341
342Yeah , even I am lazy to create methods for constraints , I need them..
343We need to set which package containt the methods
344
345using config file.
346
347 form_validator_lazy :
348    method_pkg : 'TestApp::Constraints'
349
350How to write??
351
352    package TestApp::Constraints;
353   
354    sub strict_user_name {
355        my $user_name = shift;
356   
357        return $user_name eq 'tomyhero' ? 1 : 0 ;
358    }
359   
360    sub loose_user_name {
361        my $user_name = shift;
362        return $user_name =~ /^tom/ ? 1 : 0 ;
363    }
364
365    1;
366
367how to use it??
368the keyword 'method' automatically read method from package. and the method
369name is ${prefix}_${parameter_key_name} .
370
371app.yml
372
373 form_validator_lazy :
374    method_pkg : 'TestApp::Constraints'
375    strict :
376        user_name : method # TestApp::Constraints::strict_user_name
377    loose  :
378        user_name : method # TestApp::Constraints::loose_user_name
379   
380easy?
381
382=head2 Oh.. I do not want same function but different name
383
384If I follow strict_ and loose_ methods rule then I will end up writng like
385below methods.
386
387    package TestApp::Constraints;
388   
389    sub strict_user_id {
390        my $id = shift;
391        return $id =~ /^\d+$/ ? 1 : 0 ;
392    }
393
394    sub strict_goods_id {
395        my $id = shift;
396        return $id =~ /^\d+$/ ? 1 : 0 ;
397    }
398
399app.yml
400
401 form_validator_lazy :
402    method_pkg : 'TestApp::Constraints'
403    strict :
404        user_id : method
405        goods_id: method
406
407
408I hate this. So that I add static_ prefix method...
409how to use it??
410
411 app.yml
412
413 form_validator_lazy :
414    method_pkg : 'TestApp::Constraints'
415    strict :
416        user_id :
417            - number
418        goods_id:
419            - number
420
421
422    package TestApp::Constraints;
423   
424    sub static_number {
425        my $id = shift;
426        return $id =~ /^\d+$/ ? 1 : 0 ;
427    }
428
429Now , not really great but I think it OK.
430
431I forget to tell , static_ method can have arg(s).
432
433 form_validator_lazy :
434    method_pkg : 'TestApp::Constraints'
435    strict :
436        user_id :
437            - number
438            - 10
439        goods_id:
440            - number
441            - 3
442
443
444    package TestApp::Constraints;
445   
446    sub static_number {
447        my $id     = shift;
448        my $length = shift;
449        return 0 of length $id > $length ;
450        return $id =~ /^\d+$/ ? 1 : 0 ;
451    }
452
453I think this is nice.
454
455=head2 I even do not want to type parameter at config.
456
457Yeah , I am lazy to type even parameter key...
458
459app.yml
460
461 form_validator_lazy :
462    method_pkg : 'TestApp::Constraints'
463    strict :
464        user_id  : '^\d+$'
465        member_id: '^\d+$'
466        person_id: '^\d+$'
467        human_id : '^\d+$'
468
469like this situation you can do like this. So you can save even typeing parameters!
470
471 form_validator_lazy :
472    method_pkg : 'TestApp::Constraints'
473    regexp_map     :
474        '_id$' : '^\d+$'
475
476=head2 I am lazy to use two methods for error checking.
477
478Instead of this
479
480    if ( $c->form->has_invalid or $c->form->has_missing ) {
481        $c->detach('hi_mom');
482    }
483
484use this.
485
486    if( $c->has_dfv_error ) {
487        $c->detach('hi_mom');
488    }
489
490=head2 I want to customaize parameters!!!
491
492you can use custom_parameters hash key!
493
494    # get parameters from custom_parameters instead of $c->request->parameters
495    # Of course you do not need to set if you do not use it. this is option.
496    $c->form(
497        custom_parameters => { user_name => 'tomohiro' , password => 'hi_mom' },
498        required => [qw/user_name password/],
499    );
500
501=head2 I am lazy to retrive invalid or missing error key from array in some case.
502
503Desiners want to set error message at specific postision sometimes.
504And also your validated data is ready to use at $c->stash->{v}
505
506app.yml
507
508 form_validator_lazy :
509    method_pkg : 'TestApp::Constraints'
510
511foo.tt
512
513 <td><input type="text" name="user_name"></td>
514 <td>&nbsp;[% IF invalid.user_name %]User Name Is Invalid [% END -%][% IF missing.user_name %]User Name is Missing [% END -%] </td>
515
516=head2 I want to add custom errors.
517
518Yes you can.
519
520 $c->dfv_push_invalid( 'key_name' );
521
522or
523
524 $c->dfv_push_invalid( ['key1' , 'key2'] );
525
526and after this , $c->has_dfv_error will return 1 and also set
527
528 $c->stash->{custom_error}{key_name} = 1;
529 $c->stash->{custom_error}{key1}{key2} = 1,
530
531=head1 METHOD
532
533=head2 form
534
535Returns a L<Data::FormValidator::Results> object.
536
537=head2 has_dfv_error
538
539Having invalid or missing error or not.
540
541=head2 dfv_push_invalid
542
543You can add your custom error with this module.
544
545=head1 SEE ALSO
546
547L<Data::FormValidator>
548
549=head1 AUTHOR
550
551Tomohiro Teranishi C<tomohiro.teranishi@gmail.com>
552
553=cut
554
Note: See TracBrowser for help on using the browser.