File Coverage

blib/lib/Data/Form/Elements.pm
Criterion Covered Total %
statement 90 108 83.3
branch 33 40 82.5
condition 4 6 66.6
subroutine 14 18 77.7
pod 8 8 100.0
total 149 180 82.7


line stmt bran cond sub pod time code
1             package Data::Form::Elements;
2              
3 3     3   105986 use strict;
  3         22  
  3         106  
4 3     3   20 use warnings;
  3         4  
  3         81  
5              
6 3     3   28 use Carp;
  3         5  
  3         312  
7              
8             # we are wrapping Data::FormValidator to do our heavy lifting.
9             # I am just trying to use as little code as possible to set a form
10             # up.
11 3     3   2324 use Data::FormValidator;
  3         87071  
  3         1043  
12              
13             =head1 Data::Form::Elements
14              
15             Data::Form::Elements - a wrapper API for Data::FormValidator and a module for
16             providing elemental access to the fields of a form, from a generic
17             perspective. The form in question does not need to be an HTML form.
18             Basically, if Data::FormValidator can use it as a form, so can we.
19              
20             =head1 Version
21              
22             Version 0.60
23              
24             =cut
25             our $VERSION = '0.61';
26              
27             =head1 Synopsis
28              
29             A quick example of using this module for a login form:
30              
31             use Data::Form::Elements;
32              
33             my $form = Data::Form::Elements->new();
34              
35             # add a couple elements
36             $form->add_element( "username", {
37             required => 1, errmsg => "Please provide your username." } );
38             $form->add_element( "password", {
39             required => 1, errmsg => "Please provide your password." } );
40              
41             ...
42              
43             $form->validate( %ARGS );
44              
45             if ( $form->is_valid() ) {
46             # continue logging on ...
47             }
48            
49             =head1 Functions
50              
51             =head2 new()
52              
53             Simple constructor.
54              
55             =cut
56             sub new {
57 4     4 1 19762 my $class = shift;
58             # my $elements = shift;
59             # my $profile = shift;
60            
61 4         11 my $self = {};
62            
63             # our form elements, their messages and values
64 4         15 $self->{elements} = {}; # $elements;
65              
66             # stash our validation profile
67 4         14 $self->{profile} = {}; # $profile;
68            
69             # use Data::Dumper;
70            
71             # make a placeholder for our validator
72 4         58 $self->{validator} = {};
73              
74 4         12 bless $self, $class;
75              
76 4         13 return $self;
77             }
78              
79             =head2 add_element()
80              
81             Add an element to the form object.
82             A full form element looks like this
83              
84             $form->add_element( "sort_position" , {
85             required => 0,
86             valid => 0,
87             value => '',
88             errmsg => 'Please choose where this section will show up on the list.',
89             constratints => qr/^\d+$/,
90             invmsg => 'Only numbers are allowed for this field. Please use the dropdown to select the position for this section.' });
91            
92             By default, only the name (key) is required. the required element will
93             default to 0 if it is not specified. If required is set to 1 and the
94             errmsg has not been initialized, it will also be set to a default.
95              
96             =cut
97              
98             sub add_element {
99 16     16 1 197 my ( $self, $param_name, $param_details ) = @_;
100              
101             # get our elements hash
102 16         28 my $elements = $self->{elements};
103              
104 16 100       46 unless ( exists $$param_details{required} ) {
105 4         10 $$param_details{required} = 0;
106             }
107            
108 16 100       58 if ( $$param_details{required} == 1 ) {
109             # do we have an error message set?
110 12 100       38 unless ( exists( $$param_details{errmsg} ) ) {
111 4         16 $$param_details{errmsg} = "Please fill in this field.";
112             }
113            
114             }
115             # TODO: do we have an invalid message set?
116 16 100       39 if ( exists $$param_details{constraints} ) {
117             # do we have an error message set?
118 8 50       19 unless ( exists( $$param_details{invmsg} ) ) {
119 0         0 $$param_details{invmsg} = "The data for this field is in the wrong format.";
120             }
121            
122             }
123              
124             # set up our default valid, value and message fields
125 16         28 $$param_details{valid} = 0;
126 16         27 $$param_details{value} = '';
127 16         27 $$param_details{message} = '';
128            
129             # put this element into our object's list.
130 16         25 $$elements{ $param_name } = $param_details;
131            
132             # send our newly updated elements hash back to the object
133 16         36 $self->{elements} = $elements;
134            
135             }
136              
137             =head2 _params()
138              
139             Deprecated for external use. Returns a list of the elements in this form.
140              
141             This was changed to be an "internal" method at the behest of David Baird for
142             compatibility with Apache::Request and CGI. If you really need to get the
143             list of form elements, call $form->param().
144              
145             =cut
146             sub _params {
147 0     0   0 my ( $self ) = @_;
148              
149 0         0 my @params;
150              
151             my %constraints;
152 0         0 foreach my $el ( keys %{$self->{elements}} ) {
  0         0  
153 0         0 push @params, $el;
154             }
155            
156 0         0 return @params;
157             }
158              
159             =head2 dump_form()
160              
161             use Data::Dumper to help debug a form.
162              
163             =cut
164             sub dump_form {
165 0     0 1 0 my ( $self ) = @_;
166              
167 3     3   4367 use Data::Dumper;
  3         24686  
  3         502  
168              
169 0         0 print Dumper( $self->{elements} );
170             }
171              
172             =head2 dump_validator()
173              
174             use Data::Dumper to help debug a form's underlying Data::FormValidator.
175              
176             =cut
177             sub dump_validator {
178 0     0 1 0 my ( $self ) = @_;
179              
180 3     3   25 use Data::Dumper;
  3         6  
  3         2322  
181              
182 0         0 print Dumper( $self->{validator} );
183             }
184              
185              
186             =head2 validate()
187              
188             Takes a hash of values, a CGI object or an Apache::Request object for the form elements
189             and validates them against the rules you have set up. Support for CGI and
190             Apache::Request objects sent in by David Baird L.
191              
192             Hash Ref Example:
193             $form->validate( \%ARGS );
194             if ( $form->is_valid() ) {
195             # continue processing form...
196             }
197              
198             CGI object Example
199              
200             $form->validate( \$query );
201             if ( $form->is_valid() ) {
202             # continue processing form...
203             }
204            
205             Apache::Request Example
206              
207             $form->validate( \$r );
208             if ( $form->is_valid() ) {
209             # continue processing form...
210             }
211            
212             =cut
213             sub validate {
214 8     8 1 3736 my ( $self, $form ) = @_;
215            
216             # $form can be a hashref, or an object with a param method that
217             # operates like in CGI or Apache::Request
218            
219 8 100       103 croak 'Form is not a reference' unless ref( $form );
220            
221 4         7 my %raw_form;
222            
223 4 50       17 if ( ref( $form ) eq 'HASH' ) {
    0          
224 4         21 %raw_form = %$form;
225             }
226             elsif ( $form->can( 'param' ) ) {
227             # for CGI or Apache::Request objects, calling
228             # $form->param() in list context returns a list of keys.
229             # Calling $form->param( $key ) returns the value for that
230             # form field.
231 0         0 %raw_form = map { $_ => $form->param( $_ ) } $form->param;
  0         0  
232             } else {
233 0         0 croak sprintf '%s form does not have a param method',
234             ref( $form );
235             }
236              
237             # pull in our elements
238 4         9 my %elements = %{$self->{elements}};
  4         19  
239            
240             # build our profile for use with Data::FormValidator
241             # TODO: make this its own internal (_buildProfile) function
242 4         10 my @required;
243             my @optional;
244              
245 0         0 my %constraints;
246 0         0 my %dependencies;
247              
248 4         14 foreach my $el ( keys %elements ) {
249              
250 16 100       36 if ( $elements{$el}{required} == 1 ) {
251 12         17 push @required, $el;
252             } else {
253 4         57 push @optional, $el;
254             }
255              
256 16 100       46 if ( exists $elements{$el}{constraints} ) {
257 8         19 $constraints{ $el } = $elements{$el}{constraints};
258             }
259 16 50       47 if ( exists $elements{$el}{dependencies} ) {
260 0         0 $dependencies{ $el } = $elements{$el}{dependencies};
261             }
262             }
263            
264 4         40 my %profile = (
265             required => [@required],
266             optional => [@optional],
267             filters => ['trim'],
268             # TODO: make a constraints wrapper for each form element object.
269             constraints => \%constraints,
270             dependencies => \%dependencies
271             );
272            
273             # populate our elements array with the new values from $raw_form
274 4         19 my %form_els = %raw_form;
275              
276 4         13 foreach my $el ( keys %elements ) {
277             # print "el: $el\n";
278             # print "form_el: ", $form_els{$el}, "\n";
279              
280 16         33 $elements{$el}{value} = $form_els{$el};
281             }
282              
283            
284             # create our initial validator
285 4         42 my $validator = Data::FormValidator->check( \%raw_form, \%profile );
286            
287             # check out our new values.
288             # For instance, if we have 'trim' for a filter, then we want to be able to
289             # get at that for use with future $form->param() calls
290 4         293165 foreach my $field ( keys %elements ) {
291             # print "Our form : !", $elements{$field}{value}, "!\n";
292             # print "Valid from Validator: !", $validator->{valid}{$field}, "!\n";
293             # print "Invalid from Validator: !", $validator->{invalid}{$field}, "!\n";
294 16 100       69 if ( exists $validator->{valid}{$field} ) {
295 10         28 $elements{$field}{value} = $validator->{valid}{$field};
296             }
297 16 100       42 if ( exists $validator->{invalid}{$field} ) {
298             # don't reset the value here, as D::FV will not preserve the data
299             # from an invalid field, except in an interal hash that we will
300             # not access.
301             # $elements{$field}{value} = $validator->{invalid}{$field};
302             }
303             }
304            
305             # populate any relevant error messages
306 4 100 66     23 if ( $validator->has_missing or $validator->has_invalid ) {
307             # process the form elements, since we didn't pass
308             # foreach my $field ( @{$self->{profile}{required}} ) {
309 2         22 foreach my $field ( keys %elements ) {
310 8 100       41 if ( $validator->missing($field) ) {
311 2         23 $self->{elements}{$field}{message} .= $self->{elements}{$field}{errmsg};
312             }
313 8 100       48 if ( $validator->invalid($field) ) {
314 4         45 $self->{elements}{$field}{message} .= $self->{elements}{$field}{invmsg};
315             }
316             }
317             }
318              
319 4         98 $self->{validator} = $validator;
320             }
321              
322              
323             =head2 is_valid()
324              
325             Returns true/false.
326              
327             =cut
328             sub is_valid {
329 4     4 1 1106 my ($self) = @_;
330              
331 4         8 my $valid = 0;
332            
333             # eval this, since we may not have a proper validator when this is called
334 4         7 eval {
335 4 100 66     19 unless ( $self->{validator}->has_missing or $self->{validator}->has_invalid ) {
336 2         32 $valid = 1;
337             }
338             };
339              
340 4         37 return $valid;
341             }
342              
343              
344             =head2 param()
345              
346             Getter/Setter methods for setting an individual form element.
347              
348             Example:
349             # getter
350             print $form->param("username");
351              
352             # setter
353             $form->param("username", "jason");
354            
355             =cut
356             sub param {
357 34     34 1 79 my ($self, $element, $value) = @_;
358              
359 34 50       75 return $self->_params unless defined($element);
360              
361 34 100       76 unless ( defined( $value ) ) {
362             # just return the value
363 33         215 return $self->{elements}{$element}{value};
364             } else {
365             # set a new value
366 1         6 $self->{elements}{$element}{value} = $value;
367             }
368             }
369              
370             =head2 message()
371              
372             returns the error or invalid message for a form element, if there is one.
373             Returns undef if no message exists.
374              
375             =cut
376              
377             sub message {
378 16     16 1 32 my ($self, $element) = @_;
379              
380 16         97 return $self->{elements}{$element}{message};
381             }
382              
383              
384             =head1 Field Name Accessor Methods
385              
386             Thanks to Dr. David R. Baird, we now also have basic accessor methods for form
387             elements. For example, now you can use either of the following lines to get a
388             value.
389              
390             # normal, function based method.
391             print $form->param("username"), "
\n";
392             # accessor method
393             print $form->username, "
\n";
394            
395             Thanks a ton, David!
396              
397             =cut
398              
399 3     3   23 use vars '$AUTOLOAD';
  3         13  
  3         490  
400              
401             sub AUTOLOAD {
402 18     18   35 my ($self, $new_value) = @_;
403              
404             # get everything after the last ':'
405 18 50       139 $AUTOLOAD =~ /([^:]+)$/ ||
406             croak "Can't extract key from $AUTOLOAD";
407            
408 18         44 my $key = $1;
409            
410 18         50 return $self->param( $key, $new_value );
411             }
412              
413             # this is required for AUTOLOAD
414 0     0     sub DESTROY {}
415              
416             =head1 Author
417              
418             jason gessner, C<< >>
419              
420             =head1 Bugs
421              
422             Please report any bugs or feature requests to
423             C, or through the web interface at
424             L. I will be notified, and then you'll automatically
425             be notified of progress on your bug as I make changes.
426              
427             =head1 Copyright & License
428              
429             Copyright 2004 me, All Rights Reserved.
430              
431             This program is free software; you can redistribute it and/or modify it
432             under the same terms as Perl itself.
433              
434             =cut
435              
436             1;