File Coverage

blib/lib/Dancer2/Plugin/TemplateFlute/Form.pm
Criterion Covered Total %
statement 51 51 100.0
branch 10 16 62.5
condition n/a
subroutine 12 12 100.0
pod 6 6 100.0
total 79 85 92.9


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::TemplateFlute::Form;
2              
3 3     3   148480 use Carp;
  3         4  
  3         146  
4 3     3   434 use Hash::MultiValue;
  3         1597  
  3         353  
5 3     3   14 use Types::Standard -types;
  3         4  
  3         34  
6 3     3   7870 use Moo;
  3         3  
  3         13  
7 3     3   1944 use namespace::clean;
  3         21894  
  3         11  
8              
9             =head1 NAME
10              
11             Dancer2::Plugin::TemplateFlute::Form - form object for Template::Flute
12              
13             =cut
14              
15             my $_coerce_to_hash_multivalue = sub {
16             if ( !defined $_[0] ) {
17             Hash::MultiValue->new;
18             }
19             elsif ( ref( $_[0] ) eq 'Hash::MultiValue' ) {
20             $_[0];
21             }
22             elsif ( ref( $_[0] ) eq 'HASH' ) {
23             Hash::MultiValue->from_mixed( $_[0] );
24             }
25             else {
26             croak "Unable to coerce to Hash::MultiValue";
27             }
28             };
29              
30             #
31             # attributes
32             #
33              
34             has action => (
35             is => 'ro',
36             isa => Str,
37             predicate => 1,
38             writer => 'set_action',
39             );
40              
41             has errors => (
42             is => 'ro',
43             lazy => 1,
44             isa => InstanceOf ['Hash::MultiValue'],
45             default => sub { Hash::MultiValue->new },
46             coerce => $_coerce_to_hash_multivalue,
47             clearer => 1,
48             writer => '_set_errors',
49             );
50              
51             sub add_error {
52             my $self = shift;
53             $self->errors->add(@_);
54             }
55              
56             sub set_error {
57             my $self = shift;
58             $self->errors->set(@_);
59             }
60              
61             sub set_errors {
62             my $self = shift;
63             $self->_set_errors(@_);
64             }
65              
66             after 'add_error', 'set_error', 'set_errors' => sub {
67             $_[0]->set_valid(0);
68             };
69              
70             has fields => (
71             is => 'ro',
72             lazy => 1,
73             isa => ArrayRef [Str],
74             default => sub { [] },
75             clearer => 1,
76             writer => 'set_fields',
77             );
78              
79             has log_cb => (
80             is => 'ro',
81             isa => CodeRef,
82             predicate => 1,
83             );
84              
85             has name => (
86             is => 'ro',
87             isa => Str,
88             default => 'main',
89             );
90              
91             has pristine => (
92             is => 'ro',
93             isa => Defined & Bool,
94             default => 1,
95             writer => 'set_pristine',
96             );
97              
98             has session => (
99             is => 'ro',
100             isa => HasMethods [ 'read', 'write' ],
101             required => 1,
102             );
103              
104             # We use a private writer since we want to have to_session called whenever
105             # the public set_valid method is called but we also have a need to be
106             # able to update this attribute without writing the form back to the session.
107             has valid => (
108             is => 'ro',
109             isa => Bool,
110             clearer => 1,
111             writer => '_set_valid',
112             );
113              
114             sub set_valid {
115 5     5 1 5624 my ( $self, $value ) = @_;
116 5         54 $self->_set_valid($value);
117 5         1231 $self->log( "debug", "Setting valid for form ",
118             $self->name, " to $value." );
119 5         385 $self->to_session;
120             }
121              
122             has values => (
123             is => 'ro',
124             lazy => 1,
125             isa => InstanceOf ['Hash::MultiValue'],
126             default => sub { Hash::MultiValue->new },
127             coerce => $_coerce_to_hash_multivalue,
128             trigger => sub { $_[0]->set_pristine(0) if $_[1]->keys },
129             clearer => 1,
130             writer => 'fill',
131             );
132              
133             #
134             # methods
135             #
136              
137             sub errors_hashed {
138 2     2 1 2833 my $self = shift;
139 2         4 my @hashed;
140              
141             $self->errors->each(
142 2     5   42 sub { push @hashed, +{ name => $_[0], label => $_[1] } } );
  5         46  
143              
144 2         19 return \@hashed;
145             }
146              
147             sub from_session {
148 3     3 1 941 my ($self) = @_;
149              
150 3         21 $self->log( debug => "Reading form ", $self->name, " from session");
151              
152 3 100       907 if ( my $forms_ref = $self->session->read('form') ) {
153 2 50       63 if ( exists $forms_ref->{ $self->name } ) {
154 2         5 my $form = $forms_ref->{ $self->name };
155              
156             # set_valid causes write back to session so use private
157             # method instead. Also set_errors causes set_valid to be
158             # called so use private method there too.
159 2 100       10 $self->set_action( $form->{action} ) if $form->{action};
160 2 50       483 $self->set_fields( $form->{fields} ) if $form->{fields};
161 2 50       528 $self->_set_errors( $form->{errors} ) if $form->{errors};
162 2 50       170 $self->fill( $form->{values} ) if $form->{values};
163 2 50       126 $self->_set_valid( $form->{valid} ) if defined $form->{valid};
164              
165 2         31 return 1;
166             }
167             }
168 1         27 return 0;
169             }
170              
171             sub log {
172 14     14 1 27 my ($self, $level, @message) = @_;
173 14 50       85 $self->log_cb->($level, join('',@message)) if $self->has_log_cb;
174             }
175              
176             sub reset {
177 1     1 1 12322 my $self = shift;
178 1         5 $self->clear_fields;
179 1         353 $self->clear_errors;
180 1         288 $self->clear_values;
181 1         277 $self->clear_valid;
182 1         279 $self->set_pristine(1);
183 1         23 $self->to_session;
184             }
185              
186             sub to_session {
187 6     6 1 9 my $self = shift;
188 6         4 my ($forms_ref);
189              
190 6         16 $self->log( debug => "Writing form ", $self->name, " to session");
191              
192             # get current form information from session
193 6         388 $forms_ref = $self->session->read('form');
194              
195             # update our form
196 6         202 $forms_ref->{ $self->name } = {
197             action => $self->action,
198             name => $self->name,
199             fields => $self->fields,
200             errors => $self->errors->mixed,
201             values => $self->values->mixed,
202             valid => $self->valid,
203             };
204              
205             # update form information
206 6         383 $self->session->write( form => $forms_ref );
207             }
208              
209             =head1 ATTRIBUTES
210              
211             =head2 name
212              
213             The name of the form.
214              
215             Defaults to 'main',
216              
217             =head2 action
218              
219             The form action.
220              
221             =over
222              
223             =item writer: set_action
224              
225             =item predicate: has_action
226              
227             =back
228              
229             =head2 errors
230            
231             Errors stored in a L object.
232              
233             Get form errors:
234              
235             $errors = $form->errors;
236              
237             =over
238              
239             =item writer: set_errors
240              
241             Set form errors (this will overwrite all existing errors):
242            
243             $form->set_errors(
244             username => 'Minimum 8 characters',
245             username => 'Must contain at least one number',
246             email => 'Invalid email address',
247             );
248              
249             =item clearer: clear_errors
250              
251             =back
252              
253             B Avoid using C<< $form->errors->add() >> or C<< $form->errors->set() >>
254             since doing that means that L does not automatically get set to C<0>.
255             Instead use one of L or L methods.
256              
257             =head2 fields
258              
259             Get form fields:
260              
261             $fields = $form->fields;
262              
263             =over
264              
265             =item writer: set_fields
266              
267             $form->set_fields([qw/username email password verify/]);
268              
269             =item clearer: clear_fields
270              
271             =back
272              
273             =head2 log_cb
274              
275             A code reference that can be used to log things. Signature must be like:
276              
277             $log_cb->( $level, $message );
278              
279             Logging is via L method.
280              
281             =over
282              
283             =item predicate: has_log_cb
284              
285             =back
286              
287             =head2 pristine
288              
289             Determines whether a form is pristine or not.
290              
291             This can be used to fill the form with default values and suppress display
292             of errors.
293              
294             A form is pristine until it receives form field input from the request or
295             out of the session.
296              
297             =over
298              
299             =item writer: set_pristine
300              
301             =back
302              
303             =head2 session
304              
305             A session object. Must have methods C and C.
306              
307             Required.
308              
309             =head2 valid
310              
311             Determine whether form values are valid:
312              
313             $form->valid();
314              
315             Return values are 1 (valid), 0 (invalid) or C (unknown).
316              
317             =over
318              
319             =item writer: set_valid
320              
321             =item clearer: clear_valid
322              
323             =back
324              
325             The form status automatically changes to "invalid" when L is set
326             or either L or L are called.
327            
328             =head2 values
329              
330             Get form values as hash reference:
331              
332             $values = $form->values;
333              
334             =over
335              
336             =item writer: fill
337              
338             Fill form values:
339              
340             $form->fill({username => 'racke', email => 'racke@linuxia.de'});
341              
342             =item clearer: clear_values
343              
344             =back
345              
346             =head1 METHODS
347              
348             =head2 add_error
349              
350             Add an error:
351              
352             $form->add_error( $key, $value [, $value ... ]);
353              
354             =head2 errors_hashed
355              
356             Returns form errors as array reference filled with hash references
357             for each error.
358              
359             For example these L:
360              
361             { username => 'Minimum 8 characters',
362             email => 'Invalid email address' }
363              
364             will be returned as:
365              
366             [
367             { name => 'username', value => 'Minimum 8 characters' },
368             { name => 'email', value => 'Invalid email address' },
369             ]
370              
371             =head2 from_session
372              
373             Loads form data from session key C
.
374             Returns 1 if session contains data for this form, 0 otherwise.
375              
376             =head2 log $level, @message
377              
378             Log message via L.
379              
380             =head2 reset
381              
382             Reset form information (fields, errors, values, valid) and
383             updates session accordingly.
384              
385             =head2 set_error
386              
387             Set a specific error:
388              
389             $form->set_error( $key, $value [, $value ... ]);
390              
391             =head2 to_session
392              
393             Saves form name, form fields, form values and form errors into
394             session key C.
395              
396              
397             =head1 AUTHORS
398              
399             Original Dancer plugin by:
400              
401             Stefan Hornburg (Racke), C<< >>
402              
403             Initial port to Dancer2 by:
404              
405             Evan Brown (evanernest), C<< >>
406              
407             Rehacking to Dancer2's plugin2 and general rework:
408              
409             Peter Mottram (SysPete), C<< >>
410              
411             =head1 BUGS
412              
413             Please report any bugs or feature requests via GitHub issues:
414             L.
415              
416             We will be notified, and then you'll automatically be notified of progress
417             on your bug as we make changes.
418              
419             =head1 ACKNOWLEDGEMENTS
420              
421              
422             =head1 LICENSE AND COPYRIGHT
423              
424             Copyright 2011-2016 Stefan Hornburg (Racke).
425              
426             This program is free software; you can redistribute it and/or modify it
427             under the terms of either: the GNU General Public License as published
428             by the Free Software Foundation; or the Artistic License.
429              
430             See http://dev.perl.org/licenses/ for more information.
431              
432             =cut
433              
434             1;