File Coverage

blib/lib/Catalyst/Plugin/FormValidator/Simple/Auto.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::FormValidator::Simple::Auto;
2 2     2   5905 use strict;
  2         6  
  2         68  
3 2     2   10 use warnings;
  2         4  
  2         59  
4 2     2   9 use base qw/Class::Accessor::Fast/;
  2         3  
  2         1982  
5              
6 2     2   11912 use Catalyst::Exception;
  0            
  0            
7             use UNIVERSAL::isa;
8             use YAML;
9             use FormValidator::Simple;
10             use MRO::Compat;
11              
12             our $VERSION = '0.18';
13              
14             __PACKAGE__->mk_accessors(qw/validator_profile/);
15              
16             =head1 NAME
17              
18             Catalyst::Plugin::FormValidator::Simple::Auto - Smart validation with FormValidator::Simple
19              
20             =head1 SYNOPSIS
21              
22             Loading:
23              
24             use Catalyst qw/
25             ConfigLoader
26             FormValidator::Simple
27             FormValidator::Simple::Auto
28             /;
29              
30             myapp.yml:
31              
32             validator:
33             profiles: __path_to(profiles.yml)__
34             messages: __path_to(messages.yml)__
35             message_format: <span class="error">%s</span>
36             # and other FormValidator::Simple config
37              
38             profiles.yml:
39              
40             # profiles.yml
41             action1:
42             param1:
43             - NOT_BLANK
44             - ASCII
45             - [ 'LENGTH', 4, 10 ]
46             param2:
47             - NOT_BLANK
48              
49             Then, using in your action:
50              
51             sub action1 : Global {
52             my ($self, $c) = @_;
53            
54             # $c->form($profile) already executed!
55             unless ($c->form->has_error) {
56             ...
57             }
58             }
59              
60             =head1 DESCRIPTION
61              
62             This plugin provide auto validation to Plugin::FormValidator::Simple.
63              
64             You can define validation profiles into config or YAML file, and no longer have to write it in actions.
65              
66             =head1 BUNDLING ERROR MESSAGES
67              
68             With 0.08 or earlier version, you need define validator profiles and error messages in separately.
69              
70             So, you had to write two settings like this:
71              
72             # profiles.yml
73             action1:
74             param1:
75             - NOT_BLANK
76            
77             # messages.yml
78             action1:
79             param1:
80             NOT_BLANK: param1 is required!
81              
82             It's bothered!
83              
84             Since 0.09, you can place error messages in profiles config.
85              
86             Above two configs is equals to:
87              
88             # profiles.yml
89             action1:
90             param1:
91             - rule: NOT_BLANK
92             message: param1 is required!
93              
94             =head1 METHODS
95              
96             =head2 validator_profile
97              
98             An accessor for current profile name
99              
100             =head2 form_messages
101              
102             =head2 form_messages( 'key' );
103              
104             Return error messages about current validator profile.
105              
106             If the key isn't presented, return all messages as hash.
107              
108             =cut
109              
110             sub form_messages {
111             my ($c, $key) = @_;
112             my $messages = $c->form->field_messages($c->validator_profile);
113              
114             $key ? $messages->{$key} : $messages;
115             }
116              
117             =head1 EXTENDED METHODS
118              
119             =head2 setup
120              
121             =cut
122              
123             sub setup {
124             my $c = shift;
125             my $config = $c->config->{validator};
126              
127             Catalyst::Exception->throw(message => __PACKAGE__
128             . qq/: You need to load "Catalyst::Plugin::FormValidator::Simple"/
129             ) unless $c->isa('Catalyst::Plugin::FormValidator::Simple');
130              
131             $c->log->warn(__PACKAGE__ . qq/: You must set validator profiles/)
132             unless $config->{profiles};
133              
134             if ($config->{profiles} and ref $config->{profiles} ne 'HASH') {
135             my $profiles = eval {
136             no warnings 'once';
137             local $YAML::UseAliases = 0;
138             YAML::Load(YAML::Dump(YAML::LoadFile($config->{profiles})))
139             ; # XXX: remove yaml aliases
140             };
141             Catalyst::Exception->throw(message => __PACKAGE__ . qq/: $@/) if $@;
142              
143             $config->{profiles} = $profiles;
144             }
145              
146             my $messages;
147             my $profiles = $config->{profiles};
148             for my $action (keys %{$profiles || {}}) {
149             my $profile = $profiles->{$action} || {};
150              
151             for my $param (keys %$profile) {
152             my $rules = $profile->{$param} || [];
153              
154             my $i = 0;
155             for my $rule (@$rules) {
156             if (ref $rule eq 'HASH' and defined $rule->{rule}) {
157             my $rule_name
158             = ref $rule->{rule} eq 'ARRAY'
159             ? $rule->{rule}[0]
160             : $rule->{rule};
161             $messages->{$action}{$param} ||= {};
162             $messages->{$action}{$param}{$rule_name}
163             = $rule->{message}
164             if defined $rule->{message};
165             $rule = $rule->{rule};
166             } elsif (ref $rule eq 'HASH' and defined $rule->{self_rule}) {
167             $messages->{$action}{$param} ||= {};
168             $messages->{$action}{$param}{$rule->{self_rule}}
169             = $rule->{message}
170             if defined $rule->{message};
171             delete $rules->[$i];
172             }
173             $i++;
174             }
175             }
176             }
177              
178             # XXX: replace messages. ponder about hash merging
179             $config->{messages} = $messages if $messages;
180              
181             $c->next::method(@_);
182             }
183              
184             =head2 setup_finalize
185              
186             =cut
187              
188             sub setup_finalize {
189             my $c = shift;
190              
191             # fix plugin order
192             {
193             no strict 'refs';
194             my $pkg = __PACKAGE__;
195             @{"$c\::ISA"} = ($pkg, grep !/^$pkg$/, @{"$c\::ISA"});
196             }
197             $c->next::method(@_);
198             }
199              
200             =head2 prepare
201              
202             =cut
203              
204             sub prepare {
205             my $c = shift->next::method(@_);
206              
207             if (my $profile = $c->config->{validator}{profiles}{$c->action->reverse})
208             {
209             $c->validator_profile($c->action->reverse);
210             $c->form(%$profile);
211             }
212              
213             $c;
214             }
215              
216             =head2 forward
217              
218             =cut
219              
220             sub forward {
221             my $c = shift;
222             my $action = $c->dispatcher->_invoke_as_path($c, @_);
223              
224             my $res;
225             if (my $profile = $c->config->{validator}{profiles}{$action}) {
226              
227             # first time validation
228             if (not $c->validator_profile) {
229             $c->{validator_profile} = $action;
230              
231             $c->form(%$profile);
232             $res = $c->next::method(@_);
233             } else {
234              
235             # don't override validator stuffs when not first time validation
236             local $c->{validator} = FormValidator::Simple->new;
237             local $c->{validator_profile} = $action;
238              
239             $c->form(%$profile);
240             $res = $c->next::method(@_);
241             }
242             } else {
243             $res = $c->next::method(@_);
244             }
245              
246             $res;
247             }
248              
249             =head1 ORIGINAL IDEA
250              
251             Daisuke Maki <dmaki@cpan.org>
252              
253             =head1 AUTHOR
254              
255             Daisuke Murase <typester@cpan.org>
256              
257             =head1 COPYRIGHT
258              
259             This program is free software; you can redistribute
260             it and/or modify it under the same terms as Perl itself.
261              
262             The full text of the license can be found in the
263             LICENSE file included with this module.
264              
265             =cut
266              
267             1;