Commit | Line | Data |
04abc0cc |
1 | package Catalyst::Plugin::FormValidator::Simple; |
2 | use strict; |
3 | use base qw/Catalyst::Plugin::FormValidator/; |
4 | # doesn't use parent module at all, but this is required for Catalyst::Plugin::FillInForm |
5 | |
3176e564 |
6 | use MRO::Compat; |
04abc0cc |
7 | require FormValidator::Simple; |
8 | |
9 | our $VERSION = '0.13'; |
10 | |
11 | sub setup { |
12 | my $self = shift; |
3176e564 |
13 | $self->maybe::next::method(@_); |
04abc0cc |
14 | my $setting = $self->config->{validator}; |
15 | my $plugins = $setting && exists $setting->{plugins} |
16 | ? $setting->{plugins} |
17 | : []; |
18 | FormValidator::Simple->import(@$plugins); |
19 | if ( $setting && exists $setting->{messages} ) { |
20 | FormValidator::Simple->set_messages( $setting->{messages} ); |
21 | } |
22 | if ( $setting && exists $setting->{options} ) { |
23 | FormValidator::Simple->set_option( %{ $setting->{options} } ); |
24 | } |
25 | if ( $setting && exists $setting->{message_format} ) { |
26 | FormValidator::Simple->set_message_format( $setting->{message_format} ); |
27 | } |
28 | if ( $setting && exists $setting->{message_decode_from} ) { |
29 | FormValidator::Simple->set_message_decode_from( $setting->{message_decode_from} ); |
30 | } |
31 | } |
32 | |
33 | sub prepare { |
34 | my $c = shift; |
3176e564 |
35 | $c->maybe::next::method(@_); |
04abc0cc |
36 | $c->{validator} = FormValidator::Simple->new; |
37 | return $c; |
38 | } |
39 | |
40 | sub form { |
41 | my $c = shift; |
42 | if ($_[0]) { |
43 | my $form = $_[1] ? [@_] : $_[0]; |
44 | $c->{validator}->check($c->req, $form); |
45 | } |
46 | return $c->{validator}->results; |
47 | } |
48 | |
49 | sub set_invalid_form { |
50 | my $c = shift; |
51 | $c->{validator}->set_invalid(@_); |
52 | return $c->{validator}->results; |
53 | } |
54 | |
55 | 1; |
56 | __END__ |
57 | |
58 | =head1 NAME |
59 | |
60 | Catalyst::Plugin::FormValidator::Simple - Validator for Catalyst with FormValidator::Simple |
61 | |
62 | =head1 SYNOPSIS |
63 | |
64 | use Catalyst qw/FormValidator::Simple FillInForm/; |
65 | |
66 | # set option |
67 | MyApp->config->{validator} = { |
68 | plugins => ['CreditCard', 'Japanese'], |
69 | options => { charset => 'euc'}, |
70 | } |
71 | |
72 | in your controller |
73 | |
74 | sub defaulti : Private { |
75 | |
76 | my ($self, $c) = @_; |
77 | |
78 | $c->form( |
79 | param1 => [qw/NOT_BLANK ASCII/, [qw/LENGTH 4 10/]], |
80 | param2 => [qw/NOT_BLANK/, [qw/JLENGTH 4 10/]], |
81 | mail1 => [qw/NOT_BLANK EMAIL_LOOSE/], |
82 | mail2 => [qw/NOT_BLANK EMAIL_LOOSE/], |
83 | { mail => [qw/mail1 mail2/] } => ['DUPLICATION'], |
84 | ); |
85 | |
86 | print $c->form->valid('param1'); |
87 | |
88 | if ( some condition... ) { |
89 | |
90 | $c->form( |
91 | other_param => [qw/NOT_INT/], |
92 | ); |
93 | } |
94 | |
95 | if ( some condition... ) { |
96 | |
97 | # set your original invalid type. |
98 | $c->set_invalid_form( param3 => 'MY_ERROR' ); |
99 | |
100 | } |
101 | |
102 | if ( $c->form->has_error ) { |
103 | |
104 | if ( $c->form->missing('param1') ) { |
105 | ... |
106 | } |
107 | |
108 | if ( $c->form->invalid( param1 => 'ASCII' ) ) { |
109 | ... |
110 | } |
111 | |
112 | if ( $c->form->invalid( param3 => 'MY_ERROR' ) ) { |
113 | ... |
114 | } |
115 | |
116 | } |
117 | } |
118 | |
119 | =head1 DESCRIPTION |
120 | |
121 | This plugin allows you to validate request parameters with FormValidator::Simple. |
122 | See L<FormValidator::Simple> for more information. |
123 | |
124 | This behaves like as L<Catalyst::Plugin::FormValidator>. |
125 | |
126 | =head1 CONFIGURATION |
127 | |
128 | set config with 'validator' key. |
129 | |
130 | MyApp->config->{validator} = { ... }; |
131 | |
132 | or |
133 | |
134 | MyApp->config( |
135 | validator => { ... }, |
136 | ); |
137 | |
138 | =head2 PLUGINS |
139 | |
140 | If you want to use some plugins for FormValidator::Simple, you can set like following. |
141 | |
142 | MyApp->config( |
143 | validator => { |
144 | plugins => [qw/Japanese CreditCard DBIC::Unique/], |
145 | }, |
146 | ); |
147 | |
148 | In this example, FormValidator::Simple::Plugin::Japanese, FormValidator::Simple::Plugin::CreditCard, |
149 | and FormValidator::Simple::Plugin::DBIC::Unique are loaded. |
150 | |
151 | =head2 OPTIONS |
152 | |
153 | When you set some options needed by specific validations, do like this. |
154 | |
155 | MyApp->config( |
156 | validator => { |
157 | plugins => [qw/Japanese CreditCard DBIC::Unique/], |
158 | options => { |
159 | charset => 'euc', |
160 | dbic_base_class => 'MyApp::Model::DBIC', |
161 | }, |
162 | }, |
163 | ); |
164 | |
165 | 'charset' is necessary for Plugin::Japanese, and 'dbic_cbase_class' is used in Plugin::DBIC::Unique. |
166 | |
167 | =head1 VALIDATION |
168 | |
169 | use 'form' method, see L<FormValidator::Simple> in detail. |
170 | |
171 | sub do_add : Local { |
172 | my ( $self, $c ) = @_; |
173 | |
174 | # execute validation. |
175 | $c->form( |
176 | name => [qw/NOT_BLANK ASCII/, [qw/LENGTH 0 20/] ], |
177 | email => [qw/NOT_BLANK EMAIL_LOOSE/, [qw/LENGTH 0 20/] ], |
178 | { unique => [qw/name email/] } => [qw/DBIC_UNIQUE User name email/], |
179 | ); |
180 | |
181 | if ( ... ) { |
182 | |
183 | # execute validation one more time in specific condition. |
184 | $c->form( |
185 | ... |
186 | ); |
187 | |
188 | } |
189 | |
190 | # See Catalyst::Plugin::RequestToken for '$c->validate_token' |
191 | if ( $c->validate_token ) { |
192 | |
193 | # you can force to set invalid data. |
194 | $c->set_invalid_form( token => 'TOKEN' ); |
195 | |
196 | } |
197 | |
198 | # check result. |
199 | # you can pick up result-object with 'form' method |
200 | |
201 | my $result = $c->form; |
202 | |
203 | if ( $result->has_error ) { |
204 | |
205 | # this is same as |
206 | # if ( $result->has_missing or $result->has_invalid ) |
207 | |
208 | $c->detach('add'); |
209 | |
210 | } |
211 | |
212 | } |
213 | |
214 | =head1 HANDLING SUCCESSFUL RESULT |
215 | |
216 | After it passes all validations, you may wanna put input-data into database. |
217 | It's a elegant way to use [ L<Class::DBI> and L<Class::DBI::FromForm> ] or [ L<DBIx::Class> and L<DBIx::Class::WebForm> ]. |
218 | |
219 | sub do_add : Local { |
220 | my ( $self, $c ) = @_; |
221 | |
222 | $c->form( |
223 | name => [qw/NOT_BLANK/], |
224 | email => [qw/NOT_BLANK/], |
225 | ); |
226 | |
227 | my $result = $c->form; |
228 | if ( $result->has_error ) { |
229 | $c->detach('add'); |
230 | } |
231 | |
232 | my $user = MyProj::Model::DBIC::User->create_from_form($result); |
233 | |
234 | # this behaves like this... |
235 | # MyProj::Model::DBIC::User->create({ |
236 | # name => $result->valid('name'), |
237 | # email => $result->valid('email'), |
238 | # }); |
239 | # |
240 | # if the key exists as the table's column, set the value with 'valid' |
241 | } |
242 | |
243 | Here, I explain about 'valid' method. If the value indicated with key-name passes validations, |
244 | You can get the data with 'valid', |
245 | |
246 | my $result = $c->form( |
247 | name => [qw/NOT_BLANK/], |
248 | email => [qw/NOT_BLANK/], |
249 | ); |
250 | |
251 | print $result->valid('name'); |
252 | |
253 | print $result->valid('email'); |
254 | |
255 | But, this is for only single key validation normally. |
256 | |
257 | my $result = $c->form( |
258 | name => [qw/NOT_BLANK/], # single key validation |
259 | { mail_dup => [qw/email email2/] } => ['DUPLICATION'] # multiple keys one |
260 | ); |
261 | |
262 | print $result->valid('name'); # print out the value of 'name' |
263 | |
264 | print $result->valid('mail_dup'); # no value. |
265 | |
266 | There are exceptions. These are 'DATETIME', 'DATE'. |
267 | |
268 | my $result = $c->form( |
269 | { created_on => [qw/created_year created_month created_day/] } |
270 | => |
271 | [qw/DATETIME/], |
272 | ); |
273 | |
274 | print $result->valid('created_on'); #print out datetime string like "2005-11-23 00:00:00". |
275 | |
276 | If you set some class around datetime in configuration. It returns object of the class you indicate. |
277 | You can choose from L<Time::Piece> and L<DateTime>. For example... |
278 | |
279 | MyApp->config( |
280 | validator => { |
281 | plugins => [...], |
282 | options => { |
283 | datetime_class => 'Time::Piece', |
284 | }, |
285 | }, |
286 | ); |
287 | |
288 | or |
289 | |
290 | MyApp->config( |
291 | validator => { |
292 | plugins => [...], |
293 | options => { |
294 | datetime_class => 'DateTime', |
295 | time_zone => 'Asia/Tokyo', |
296 | }, |
297 | }, |
298 | ); |
299 | |
300 | then |
301 | |
302 | my $result = $c->form( |
303 | { created_on => [qw/created_year created_month created_day/] } |
304 | => |
305 | [qw/DATETIME/], |
306 | ); |
307 | |
308 | my $dt = $result->valid('created_on'); |
309 | |
310 | print $dt->ymd; |
311 | |
312 | MyProj::Model::CDBI::User->create_from_form($result); |
313 | |
314 | This may be useful when you define 'has_a' relation for datetime columns. |
315 | For example, in your table class inherits 'Class::DBI' |
316 | |
317 | __PACKAGE__->has_a( created_on => 'DateTime', |
318 | inflate => ..., |
319 | deflate => ..., |
320 | ); |
321 | |
322 | And see also L<Class::DBI::Plugin::TimePiece>, L<Class::DBI::Plugin::DateTime>. |
323 | |
324 | =head1 MESSAGE HANDLING |
325 | |
326 | in template file, you can handle it in detail. |
327 | |
328 | [% IF c.form.has_error %] |
329 | <p>Input Error</p> |
330 | <ul> |
331 | [% IF c.form.missing('name') %] |
332 | <li>input name!</li> |
333 | [% END %] |
334 | [% IF c.form.invalid('name') %] |
335 | <li>name is wrong</li> |
336 | [% END %] |
337 | [% IF c.form.invalid('name', 'ASCII') %] |
338 | <li>input name with ascii code.</li> |
339 | [% END %] |
340 | [% IF c.form.invalid('name', 'LENGTH') %] |
341 | <li>wrong length for name.</li> |
342 | [% END %] |
343 | </ul> |
344 | [% END %] |
345 | |
346 | or, make it more easy. |
347 | |
348 | [% IF c.form.has_error %] |
349 | <p>Input Error</p> |
350 | <ul> |
351 | [% FOREACH key IN c.form.error %] |
352 | [% FOREACH type IN c.form.error(key) %] |
353 | <li>Invalid: [% key %] - [% type %]</li> |
354 | [% END %] |
355 | [% END %] |
356 | </li> |
357 | [% END %] |
358 | |
359 | And you can also use messages configuration as hash reference. |
360 | |
361 | MyApp->config( |
362 | validator => { |
363 | plugins => [...], |
364 | messages => { |
365 | user => { |
366 | name => { |
367 | NOT_BLANK => 'Input name!', |
368 | ASCII => 'Input name with ascii code!', |
369 | }, |
370 | email => { |
371 | DEFAULT => 'email is wrong.!', |
372 | NOT_BLANK => 'input email.!' |
373 | }, |
374 | }, |
375 | company => { |
376 | name => { |
377 | NOT_BLANK => 'Input name!', |
378 | }, |
379 | }, |
380 | }, |
381 | }, |
382 | ); |
383 | |
384 | or YAML file. set file name |
385 | |
386 | MyApp->config( |
387 | validator => { |
388 | plugins => [...], |
389 | messages => 'conf/messages.yml', |
390 | }, |
391 | ); |
392 | |
393 | and prepare yaml file like following, |
394 | |
395 | DEFAULT: |
396 | name: |
397 | DEFAULT: name is invalid |
398 | user: |
399 | name: |
400 | NOT_BLANK: Input name! |
401 | ASCII: Input name with ascii code! |
402 | email: |
403 | DEFAULT: Email is wrong! |
404 | NOT_BLANK: Input email! |
405 | company: |
406 | name: |
407 | NOT_BLANK: Input name! |
408 | |
409 | the format is... |
410 | |
411 | Action1_Name: |
412 | Key1_Name: |
413 | Validation1_Name: Message |
414 | Validation2_Name: Message |
415 | Key2_Name: |
416 | Validation1_Name: Message |
417 | Action2_Name: |
418 | Key1_Name: |
419 | ... |
420 | |
421 | After messages configuration, call messages() method from result-object. |
422 | and set action-name as argument. |
423 | |
424 | [% IF c.form.has_error %] |
425 | <ul> |
426 | [% FOREACH message IN c.form.messages('user') %] |
427 | <li>[% message %]</li> |
428 | [% END %] |
429 | </ul> |
430 | [% END %] |
431 | |
432 | you can set each message format |
433 | |
434 | MyApp->config( |
435 | validator => { |
436 | messages => 'messages.yml', |
437 | message_format => '<p>%s</p>' |
438 | }, |
439 | ); |
440 | |
441 | [% IF c.form.has_error %] |
442 | [% c.form.messages('user').join("\n") %] |
443 | [% END %] |
444 | |
445 | =head1 SEE ALSO |
446 | |
447 | L<FormValidator::Simple> |
448 | |
449 | L<Catalyst> |
450 | |
451 | =head1 AUTHOR |
452 | |
453 | Lyo Kato E<lt>lyo.kato@gmail.comE<gt> |
454 | |
455 | =head1 COPYRIGHT AND LICENSE |
456 | |
457 | Copyright(C) 2005 by Lyo Kato |
458 | |
459 | This library is free software; you can redistribute it and/or |
460 | modify it under the same terms as Perl itself. |
461 | |
462 | =cut |
463 | |