File Coverage

blib/lib/Form/Processor/Field.pm
Criterion Covered Total %
statement 119 162 73.4
branch 55 82 67.0
condition 20 33 60.6
subroutine 29 40 72.5
pod 19 34 55.8
total 242 351 68.9


line stmt bran cond sub pod time code
1             package Form::Processor::Field;
2             $Form::Processor::Field::VERSION = '1.162360';
3 35     35   149 use strict;
  35         31  
  35         767  
4 35     35   97 use warnings;
  35         32  
  35         644  
5 35     35   100 use base 'Rose::Object';
  35         35  
  35         11997  
6 35     35   14452 use Form::Processor::I18N; # only needed if running without a form object.
  35         48  
  35         798  
7 35     35   213 use Scalar::Util;
  35         32  
  35         3788  
8              
9              
10              
11              
12              
13             use Rose::Object::MakeMethods::Generic (
14 35         754 scalar => [
15             'name', # Field's name
16             'init_value', # initial value populated by init_from_object - used to look for changes
17             # not to be confused with the form method init_value().
18             'value', # scalar internal value -- same as init_value at start.
19             'input', # input value from parameter
20             'temp', # Temporary storage for fields to save validated data - DEPRECATED -- not really needed.
21             'type', # field type (e.g. 'Text', 'Select' ... )
22             'label', # Text label -- not really used much, yet.
23             'style', # Field's generic style to use for css formatting
24             #'form', # The parent form (defined below)
25             'sub_form', # The field is made up of a sub-form.
26             # This is a more generic field type that can be used
27             # in template to determine what type of html widget to generate
28             widget => { interface => 'get_set_init' },
29             order => { interface => 'get_set_init' },
30             required_message => { interface => 'get_set_init' },
31              
32             # Allow ragne checks -- done after validation so
33             # must only be used on appropriate fields
34             # These really should be defined in a subclass that only deals
35             # with numbers.
36             range_start => { interface => 'get_set_init' },
37             range_end => { interface => 'get_set_init' },
38              
39             value_format => { interface => 'get_set_init' }, # sprintf format to use when converting input to value
40              
41             # Often the fields need a unique id for js, so many a
42             # handy way to get this.
43             id => { interface => 'get_set_init' },
44              
45             max_size => { interface => 'get_set_init' },
46              
47             ],
48              
49             boolean => [
50              
51             # These should probably be 'get_set' here and then 'get_set_init' any
52             # place that needs to define an initial value.
53             password => { interface => 'get_set_init' }, # don't return field in $form->fif
54             required => { interface => 'get_set_init' }, # field is requried
55             writeonly => { interface => 'get_set_init' }, # don't call format_value on this field
56             clear => { interface => 'get_set_init' }, # don't validate and remove from database
57              
58             # disabled and readonly mirror the html form specification
59             # disabled fields are not suppose to be "successful" and thus
60             # should not be updated. But.. see "noupdate" below.
61             disabled => { interface => 'get_set_init' } . # Don't update this field in the database.
62              
63             # readonly fields are basically like hidden fields that the UI
64             # should no be able to modify but still are submitted.
65             readonly => { interface => 'get_set_init' }, # Flag to indicate readonly field
66              
67             # Since disabled and readonly effect the UI differently
68             # use a separate flag to tell the model to not update a field.
69             noupdate => { interface => 'get_set_init' }, # don't update this field in the database
70              
71             must_submit => { interface => 'get_set' } # override use_existing_values
72             ],
73              
74             array => [
75             errors => {},
76             reset_errors => { interface => 'reset', hash_key => 'errors' },
77             add_error_str => { interface => 'push', hash_key => 'errors' },
78             ],
79 35     35   14514 );
  35         183277  
80              
81              
82             ## Should $value be overridden to only return a value if there are not
83             # any errors?
84              
85             # ABSTRACT: Base class for Fields used with Form::Processor
86              
87              
88              
89             sub init {
90 51     51 1 17009 my $self = shift;
91              
92 51         201 $self->SUPER::init( @_ );
93              
94 51 50       348 die "Need to supply name parameter"
95             unless $self->name;
96             }
97              
98              
99             sub full_name {
100 9     9 1 27 my $field = shift;
101              
102 9         11 my $name = $field->name;
103 9   50     32 my $form = $field->form || return $name;
104 9   50     17 my $parent = $form->parent_field || return $name;
105 0         0 return $parent->name . '.' . $name;
106             }
107              
108              
109             sub form {
110 128     128 1 869 my $self = shift;
111 128 100       620 return Scalar::Util::weaken( $self->{form} = shift ) if ( @_ );
112 78         112 return $self->{form};
113             }
114              
115              
116             sub init_id {
117 0     0 0 0 my $field = shift;
118 0 0       0 my $form_name = $field->form ? $field->form->name : 'fld-';
119 0         0 return $field->form->name . $field->name
120             }
121              
122              
123 0     0 1 0 sub init_widget {'text'}
124              
125              
126 17     17 0 121 sub init_order {1}
127              
128              
129             sub set_order {
130 0     0 1 0 my $field = shift;
131 0         0 my $form = $field->form;
132 0   0     0 my $order = $form->field_counter || 1;
133 0         0 $field->order( $order );
134 0         0 $form->field_counter( $order + 1 );
135             }
136              
137              
138 3     3 0 22 sub init_required {0}
139              
140              
141             sub add_error {
142 64     64 1 667 my $self = shift;
143              
144 64         116 my $form = $self->form;
145              
146 64         59 my $lh;
147              
148             # By default errors get attached to the field where they happen.
149 64         57 my $error_field = $self;
150              
151             # Running without a form object?
152 64 100       118 if ( $form ) {
153 13         28 $lh = $form->language_handle;
154              
155             # If we are a sub-form then redirect errors to the parent field
156 13 50       56 $error_field = $form->parent_field if $form->parent_field;
157             }
158             else {
159 51   50     471 $lh = $Form::Processor::LANGUAGE_HANDLE || $ENV{LANGUAGE_HANDLE} || Form::Processor::I18N->get_handle ||
160             die "Failed call to Text::Maketext->get_handle";
161             }
162              
163 64         3011 $self->add_error_str( $lh->maketext( @_ ) );
164              
165 64         8824 return;
166              
167             }
168              
169              
170 34     34 0 270 sub init_max_size {10_000} # sanity check
171              
172              
173              
174 44     44 0 234 sub init_range_start {return}
175 46     46 0 185 sub init_range_end {return}
176              
177              
178             sub validate_field {
179 176     176 1 25967 my $field = shift;
180              
181 176         437 $field->reset_errors;
182 176         548 $field->value( undef );
183              
184              
185             # See if anything was submitted
186 176 100       305 unless ( $field->any_input ) {
187 8 100       21 $field->add_error( $field->required_message )
188             if $field->required;
189              
190 8         25 return !$field->required;
191             }
192              
193 168 100       345 return unless $field->test_multiple;
194 165 100       262 return unless $field->test_options;
195              
196              
197             # Check for max length new .20.
198 139 50       324 if ( my $size = $field->max_size ) {
199              
200 139         532 my $value = $field->input;
201              
202 139 50       288 if ( length( $value ) > $size ) {
203 0         0 $field->add_error( 'Please limit to [quant,_1,character]. You submitted [_2]', $size, length $value );
204 0         0 return;
205             }
206             }
207              
208              
209 139 100       254 return unless $field->validate;
210 113 100       234 return unless $field->test_ranges;
211              
212              
213             # Now move data from input -> value
214 109         213 $field->input_to_value;
215              
216 109 50       153 return $field->validate_value unless $field->has_error;
217              
218 0         0 return;
219             }
220              
221              
222 139     139 1 262 sub validate {1}
223              
224              
225 109     109 1 156 sub validate_value {1}
226              
227              
228 90     90 0 375 sub init_value_format {return}
229              
230              
231             sub input_to_value {
232 91     91 1 67 my $field = shift;
233              
234 91 50       200 return if defined $field->value; # already set by validate method.
235              
236 91         195 my $format = $field->value_format;
237              
238 91 100       139 if ( $format ) {
239 1         16 $field->value( sprintf( $format, $field->input ) );
240             }
241              
242             else {
243 90         183 $field->value( $field->input );
244             }
245             }
246              
247              
248             sub test_ranges {
249 113     113 1 102 my $field = shift;
250 113 100 66     445 return 1 if $field->can( 'options' ) || $field->has_error;
251              
252 52         80 my $input = $field->input;
253              
254              
255 52 50       100 return 1 unless defined $input;
256              
257 52         127 my $low = $field->range_start;
258 52         137 my $high = $field->range_end;
259              
260 52 100 100     165 if ( defined $low && defined $high ) {
261 6 100 100     24 return $input >= $low && $input <= $high
262             ? 1
263             : $field->add_error( 'value must be between [_1] and [_2]', $low, $high );
264             }
265              
266 46 100       70 if ( defined $low ) {
267 2 100       5 return $input >= $low
268             ? 1
269             : $field->add_error( 'value must be greater than or equal to [_1]', $low );
270             }
271              
272 44 50       64 if ( defined $high ) {
273 0 0       0 return $input <= $high
274             ? 1
275             : $field->add_error( 'value must be less than or equal to [_1]', $high );
276             }
277              
278 44         82 return 1;
279             }
280              
281              
282              
283              
284              
285             sub trim_value {
286 11     11 1 315 my ( $self, $value ) = @_;
287              
288 11 100       32 return unless defined $value;
289              
290 7 50       15 my @values = ref $value eq 'ARRAY' ? @$value : ( $value );
291              
292 7         8 for ( @values ) {
293 7 50       12 next if ref $_;
294 7         14 s/^\s+//;
295 7         16 s/\s+$//;
296             }
297              
298 7 50       30 return @values > 1 ? \@values : $values[0];
299             }
300              
301              
302 4     4 0 57 sub init_required_message {'This field is required'}
303              
304              
305             sub test_multiple {
306 168     168 1 140 my ( $self ) = @_;
307              
308 168         194 my $value = $self->input;
309              
310 168 100 100     379 if ( ref $value eq 'ARRAY' && !( $self->can( 'multiple' ) && $self->multiple ) ) {
      100        
311 3         14 $self->add_error( 'This field does not take multiple values' );
312 3         7 return;
313             }
314              
315 165         284 return 1;
316             }
317              
318              
319             sub any_input {
320 176     176 1 187 my ( $self ) = @_;
321              
322              
323 176         151 my $found;
324              
325 176         218 my $value = $self->input;
326              
327             # check for one value as defined
328 176 100       423 return grep {/\S/} @$value
  17         52  
329             if ref $value eq 'ARRAY';
330              
331 168   100     1060 return defined $value && $value =~ /\S/;
332             }
333              
334              
335             sub test_options {
336 165     165 1 137 my ( $self ) = @_;
337              
338 165 100       612 return 1 unless $self->can( 'options' );
339              
340             # create a lookup hash
341 87         150 my %options = map { $_->{value} => 1 } $self->options;
  1494         2194  
342              
343 87         221 my $input = $self->input;
344              
345 87 50       141 return 1 unless defined $input; # nothing to check
346              
347 87 100       175 for my $value ( ref $input eq 'ARRAY' ? @$input : ( $input ) ) {
348 94 100       171 unless ( $options{$value} ) {
349 26         78 $self->add_error( "'[_1]' is not a valid value", $value );
350 26         122 return;
351             }
352             }
353              
354 61         164 return 1;
355             }
356              
357              
358              
359             sub format_value {
360 2     2 1 2 my $self = shift;
361 2         5 my $value = $self->value;
362 2 50       16 return defined $value ? ( $self->name, $value ) : ();
363             }
364              
365              
366 0     0 0 0 sub init_noupdate {0}
367              
368              
369 0     0 0 0 sub init_disabled {0}
370 0     0 0 0 sub init_readonly {0}
371              
372              
373 3     3 0 14 sub init_clear {0}
374              
375              
376 0     0 0 0 sub init_writeonly {0}
377              
378              
379              
380 0     0 0 0 sub init_password {0}
381              
382              
383             sub value_changed {
384 0     0 1 0 my ( $self ) = @_;
385              
386 0         0 my @cmp;
387              
388 0         0 for ( qw/ init_value value / ) {
389 0         0 my $val = $self->$_;
390 0 0       0 $val = '' unless defined $val;
391              
392             push @cmp, join '|',
393             sort
394             map {
395 0 0 0     0 ref( $_ ) && $_->isa( 'DateTime' )
  0 0       0  
396             ? $_->iso8601
397             : "$_"
398             } ref( $val ) eq 'ARRAY' ? @$val : $val;
399              
400             }
401              
402 0         0 return $cmp[0] ne $cmp[1];
403             }
404              
405              
406 0 0   0 1 0 sub required_text { shift->required ? 'required' : 'optional' }
407              
408              
409             sub has_error {
410 331     331 1 376 my $self = shift;
411 331         536 my $errors = $self->errors;
412 331 100       1994 return unless $errors;
413 62         188 return scalar @$errors;
414             }
415              
416              
417              
418              
419              
420             sub dump {
421 0     0 0   my $f = shift;
422 0           require Data::Dumper;
423 0           warn "\n---------- [ ", $f->name, " ] ---------------\n";
424 0           warn "Field Type: ", ref( $f ), "\n";
425 0   0       warn "Required: ", ( $f->required || '0' ), "\n";
426 0   0       warn "Password: ", ( $f->password || '0' ), "\n";
427 0           my $v = $f->value;
428 0           warn "Value: ", Data::Dumper::Dumper $v;
429 0           my $iv = $f->init_value;
430 0           warn "InitValue: ", Data::Dumper::Dumper $iv;
431 0           my $i = $f->input;
432 0           warn "Input: ", Data::Dumper::Dumper $i;
433              
434 0 0         if ( $f->can( 'options' ) ) {
435 0           my $o = $f->options;
436 0           warn "Options: " . Data::Dumper::Dumper $o;
437             }
438             }
439              
440              
441              
442              
443              
444              
445             1;
446              
447             __END__