File Coverage

blib/lib/Rose/HTML/Form/Field/Compound.pm
Criterion Covered Total %
statement 139 147 94.5
branch 47 58 81.0
condition 16 22 72.7
subroutine 32 34 94.1
pod 20 24 83.3
total 254 285 89.1


line stmt bran cond sub pod time code
1             package Rose::HTML::Form::Field::Compound;
2              
3 9     9   1290 use strict;
  9         33  
  9         249  
4              
5 9     9   51 use Carp();
  9         32  
  9         170  
6              
7 9     9   503 use Rose::HTML::Object::Errors qw(:field);
  9         22  
  9         263  
8 9     9   75 use Rose::HTML::Object::Messages qw(:field);
  9         22  
  9         68  
9              
10 9     9   67 use base qw(Rose::HTML::Form::Field Rose::HTML::Form::Field::Collection);
  9         27  
  9         3779  
11              
12 9     9   66 use Rose::HTML::Form::Constants qw(FF_SEPARATOR);
  9         31  
  9         12402  
13              
14             our $VERSION = '0.611';
15              
16             # Multiple inheritence never quite works out the way I want it to...
17             Rose::HTML::Form::Field::Collection->import_methods
18             (
19             'hidden_field',
20             'hidden_fields',
21             'html_hidden_field',
22             'xhtml_hidden_field',
23             'html_hidden_fields',
24             'xhtml_hidden_fields',
25             );
26              
27             our $Debug = undef;
28              
29             sub init
30             {
31 84     84 1 237 my($self) = shift;
32 84         283 my(%args) = @_;
33              
34 84 50       228 if(exists $args{'name'})
35             {
36 84         335 $self->name(delete $args{'name'});
37             }
38             else
39             {
40 0         0 Carp::croak __PACKAGE__, "-derived fields require a 'name' parameter in the constructor";
41             }
42              
43 84   50     351 $self->{'fields'} ||= {};
44              
45 84         624 $self->build_field();
46              
47 84         512 local $self->{'in_init'} = 1;
48 84         330 $self->SUPER::init(@_);
49             }
50              
51 0     0 0 0 sub is_flat_group { 0 }
52              
53             sub children
54             {
55 4 50   4 1 27 Carp::croak "Cannot set children() for a pseudo-group ($_[0])" if(@_ > 1);
56 4 100       25 return wantarray ? () : [];
57             }
58              
59 4     4 1 71 sub value { shift->input_value(@_) }
60              
61       1 1   sub build_field { }
62              
63             sub init_fields
64             {
65 1     1 0 6 my($self, %fields) = @_;
66              
67 1         5 foreach my $field_name (keys %fields)
68             {
69 3   33     10 my $field = $self->field($field_name) ||
70             Carp::croak "No such field: $field_name";
71              
72 3 50       29 if($field->isa('Rose::HTML::Form::Field::Group'))
73             {
74 0 0       0 $Debug && warn "$self $field_name(s) = $fields{$field_name}\n";
75 0         0 $field->_set_input_value($fields{$field_name});
76             }
77             else
78             {
79 3 50       13 $Debug && warn "$self $field_name = $fields{$field_name}\n";
80 3         18 $field->_set_input_value($fields{$field_name});
81             }
82             }
83             }
84              
85 2     2 1 12 sub html_field { join('', map { $_->html_field } shift->fields) }
  6         22  
86 2     2 1 9 sub xhtml_field { join('', map { $_->xhtml_field } shift->fields) }
  6         21  
87              
88             sub resync_name
89             {
90 399     399 0 731 my($self) = shift;
91              
92 399         1139 $self->SUPER::resync_name();
93 399         1357 $self->resync_field_names;
94             }
95              
96             sub name
97             {
98 1813     1813 1 3656 my($self) = shift;
99              
100 1813 100       3806 if(@_)
101             {
102 171         589 $self->local_name(shift);
103 171         675 $self->resync_field_names;
104 171         557 return $self->fq_name;
105             }
106              
107 1642         3742 return $self->fq_name;
108             }
109              
110             sub clear
111             {
112 275     275 1 504 my $self = shift;
113              
114 275         810 $self->_set_input_value(undef);
115 275         1027 $self->clear_fields();
116 275         1915 $self->error(undef);
117 275         710 $self->SUPER::clear();
118             }
119              
120             sub reset
121             {
122 12     12 1 33 my($self) = shift;
123              
124 12         74 $self->reset_fields();
125 12         65 $self->SUPER::reset();
126 12         72 $self->is_cleared(0);
127             }
128              
129 4     4 1 14 sub decompose_value { {} }
130              
131             # Evil hash grab for efficiency. May change to shift->input_value()
132             # if it becomes a problem someday...
133 3     3 1 8 sub coalesce_value { shift->{'input_value'} }
134              
135             sub distribute_value
136             {
137 711     711 0 1485 my($self, $value, $type) = @_;
138              
139             #$type ||= 'input_value';
140              
141 711 100 66     2699 my $method = ((!$type || $type eq 'input_value')) ? '_set_input_value' : $type;
142              
143 711 100       2219 if(my $split = $self->decompose_value($value))
144             {
145 83         472 while(my($name, $val) = each(%$split))
146             {
147             #$self->field($name)->$type($val);
148 238         756 $self->field($name)->$method($val);
149             }
150             }
151             }
152              
153             sub default_value
154             {
155 1265     1265 1 2060 my($self) = shift;
156              
157 1265 100       2439 if(@_)
158             {
159 7         55 my $value = $self->SUPER::default_value(@_);
160 7         32 $self->distribute_value($value, 'default_value');
161             }
162              
163 1265         2859 return $self->SUPER::default_value;
164             }
165              
166             *auto_invalidate_parents = \&Rose::HTML::Form::Field::auto_invalidate_parents;
167              
168             sub invalidate_value
169             {
170 89     89 1 171 my($self) = shift;
171              
172 89         282 $self->SUPER::invalidate_value();
173              
174 89 100       222 if($self->_is_full)
175             {
176 19         99 $self->_set_input_value($self->coalesce_value);
177             }
178             else
179             {
180 70 100       225 if($self->is_empty)
181             {
182 18         61 $self->has_partial_value(0);
183             }
184             else
185             {
186 52         267 $self->has_partial_value(1);
187             }
188              
189 70         416 $self->_set_input_value(undef);
190             }
191              
192 89         329 my $parent = $self->parent_field;
193              
194 89 100       264 if($parent)
195             {
196 27         77 $parent->invalidate_value();
197             }
198              
199 89         183 return;
200             }
201              
202             sub subfield_input_value
203             {
204 4     4 1 10 my($self, $name) = (shift, shift);
205 4 50       14 my $field = $self->field($name) or Carp::croak "No such subfield '$name'";
206 4         16 $field->_set_input_value(@_);
207             }
208              
209             sub input_value
210             {
211 1153     1153 1 3725 my($self) = shift;
212              
213 1153 100       2368 if(@_)
214             {
215 704         1707 my $value = $self->SUPER::input_value(@_);
216              
217 704 50 66     1614 if((my $parent = $self->parent_field) && $self->auto_invalidate_parent)
218             {
219 0         0 $parent->invalidate_value;
220             }
221              
222 704         1664 $self->distribute_value($value, 'input_value');
223             }
224              
225 1153         2913 my $ret = $self->SUPER::input_value;
226              
227 1153 100 100     3810 if(defined $ret || $self->is_empty || $self->has_partial_value)
      100        
228             {
229 1123         3539 return $ret;
230             }
231              
232 30         275 return $self->coalesce_value;
233             }
234              
235             sub is_empty
236             {
237 1397     1397 1 2299 my($self) = shift;
238              
239 1397         3166 foreach my $field ($self->fields)
240             {
241 4165 100       22378 return 0 unless($field->is_empty);
242             }
243              
244 1223         9580 return 1;
245             }
246              
247             sub is_full
248             {
249 72     72 1 108 my($self) = shift;
250              
251 72         166 foreach my $field ($self->fields)
252             {
253 148 100       1224 return 0 if($field->is_empty);
254             }
255              
256 37         732 return 1;
257             }
258              
259             sub validate
260             {
261 23     23 1 49 my($self) = shift;
262              
263 23 100       102 if($self->required)
264             {
265 5         27 my @missing;
266              
267 5         20 foreach my $field ($self->fields)
268             {
269 9     9   76 no warnings 'uninitialized';
  9         43  
  9         2419  
270 15 100       47 unless(length $field->input_value_filtered)
271             {
272 11 100   22   67 push(@missing, sub { $field->error_label || $field->local_name });
  22         64  
273             }
274             }
275              
276 5 50       30 if(@missing)
277             {
278 5 100       33 if(@missing == $self->num_fields)
279             {
280 2         7 return $self->SUPER::validate(@_);
281             }
282              
283 3         33 $self->error_id(FIELD_REQUIRED, { missing => \@missing });
284 3         15 return 0;
285             }
286             }
287              
288 18         208 return $self->SUPER::validate(@_);
289             }
290              
291             sub disabled
292             {
293 0     0 1 0 my($self) = shift;
294              
295 0         0 foreach my $field ($self->fields)
296             {
297 0 0       0 $field->disabled(@_) if($field->can('disabled'));
298             }
299             }
300              
301             sub message_for_error_id
302             {
303 11     11 1 56 my($self, %args) = @_;
304              
305 11         37 my $error_id = $args{'error_id'};
306 11         33 my $msg_class = $args{'msg_class'};
307 11   100     57 my $args = $args{'args'} || [];
308              
309 9     9   77 no warnings 'uninitialized';
  9         33  
  9         2001  
310 11 100       37 if($error_id == FIELD_REQUIRED)
311             {
312 5         26 my $msg = $msg_class->new(args => $args);
313              
314 5 100 66     49 if(ref $args eq 'HASH' && keys %$args)
315             {
316 4 100       12 if($args->{'missing'})
317             {
318 3 100       14 if(@{$args->{'missing'}} > 1)
  3         13  
319             {
320 2         11 $msg->id(FIELD_REQUIRED_SUBFIELDS);
321             }
322             else
323             {
324 1         7 $msg->id(FIELD_REQUIRED_SUBFIELD);
325             }
326             }
327             else
328             {
329 1         5 $msg->id(FIELD_REQUIRED_LABELLED);
330             }
331             }
332             else
333             {
334 1         7 $msg->id(FIELD_REQUIRED_GENERIC);
335             }
336              
337 5         22 return $msg;
338             }
339              
340 6         26 return undef;
341             }
342              
343             if(__PACKAGE__->localizer->auto_load_messages)
344             {
345             __PACKAGE__->localizer->load_all_messages;
346             }
347              
348 9     9   81 use utf8; # The __DATA__ section contains UTF-8 text
  9         19  
  9         75  
349              
350             1;
351              
352             __DATA__
353              
354             [% LOCALE en %]
355              
356             FIELD_REQUIRED_SUBFIELD = "Missing [@missing]."
357             FIELD_REQUIRED_SUBFIELDS = "Missing [@missing]."
358              
359             [% LOCALE de %]
360              
361             FIELD_REQUIRED_SUBFIELD = "[@missing] fehlt."
362             FIELD_REQUIRED_SUBFIELDS = "[@missing] fehlen."
363              
364             [% LOCALE fr %]
365              
366             FIELD_REQUIRED_SUBFIELD = "Le champ [@missing] manque."
367             FIELD_REQUIRED_SUBFIELDS = "Les champs [@missing] manquent."
368              
369             [% LOCALE bg %]
370              
371             FIELD_REQUIRED_SUBFIELD = "Непопълнени поле [@missing]."
372             FIELD_REQUIRED_SUBFIELDS = "Непопълнени полета [@missing]."
373              
374             __END__
375              
376             =head1 NAME
377              
378             Rose::HTML::Form::Field::Compound - Base class for field objects that contain other field objects.
379              
380             =head1 SYNOPSIS
381              
382             package MyFullNameField;
383              
384             use base qw(Rose::HTML::Form::Field::Compound
385             Rose::HTML::Form::Field::Text);
386              
387             sub build_field
388             {
389             my($self) = shift;
390              
391             $self->add_fields
392             (
393             first => { type => 'text', size => 15, maxlength => 50 },
394             middle => { type => 'text', size => 15, maxlength => 50 },
395             last => { type => 'text', size => 20, maxlength => 50 },
396             );
397             }
398              
399             sub coalesce_value
400             {
401             my($self) = shift;
402             return join(' ', map { defined($_) ? $_ : '' }
403             map { $self->field($_)->internal_value }
404             qw(first middle last));
405             }
406              
407             sub decompose_value
408             {
409             my($self, $value) = @_;
410              
411             return undef unless(defined $value);
412              
413             if($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/)
414             {
415             return
416             {
417             first => $1,
418             middle => $2,
419             last => $3,
420             };
421             }
422              
423             my @parts = split(/\s+/, $value);
424              
425             if(@parts == 2)
426             {
427             return
428             {
429             first => $parts[0],
430             middle => undef,
431             last => $parts[1],
432             };
433             }
434              
435             return
436             {
437             first => $parts[0],
438             middle => $parts[1],
439             last => join(' ', @parts[2 .. $#parts]),
440             };
441             }
442              
443             # Override these methods to determine how sub-fields are arranged
444             sub html_field { ... }
445             sub xhtml_field { ... }
446             ...
447              
448              
449             use MyFullNameField;
450              
451             $field =
452             MyFullNameField->new(
453             label => 'Full Name',
454             name => 'name',
455             default => 'John Doe');
456              
457             print $field->internal_value; # "John Doe"
458              
459             $field->input_value('Steven Paul Jobs');
460              
461             print $field->field('middle')->internal_value; # "Paul"
462              
463             print $field->html;
464             ...
465              
466             =head1 DESCRIPTION
467              
468             L<Rose::HTML::Form::Field::Compound> is a base class for compound fields. A compound field is one that contains other fields. The example in the L<SYNOPSIS> is a full name field made up of three separate text fields, one each for first, middle, and last name. Compound fields can also contain other compound fields.
469              
470             Externally, a compound field must field look and behave as if it is a single, simple field. Although this can be done in many ways, it is important for all compound fields to actually inherit from L<Rose::HTML::Form::Field::Compound>. L<Rose::HTML::Form> uses this relationship in order to identify compound fields and handle them correctly. Any compound field that does not inherit from L<Rose::HTML::Form::Field::Compound> will not work correctly with L<Rose::HTML::Form>.
471              
472             This class inherits from, and follows the conventions of, L<Rose::HTML::Form::Field>. Inherited methods that are not overridden will not be documented a second time here. See the L<Rose::HTML::Form::Field> documentation for more information.
473              
474             =head1 HIERARCHY
475              
476             A L<Rose::HTML::Form::Field::Compound>-derived object behaves as if it is a single L<field|Rose::HTML::Form::Field> made up of a group of sibling elements. These siblings are available through the L<fields|/fields> method.
477              
478             See the "hierarchy" sections of the L<Rose::HTML::Form::Field/HIERARCHY> and L<Rose::HTML::Form/HIERARCHY> documentation for more information about how field objects that are really "groups of siblings" behave with respect to the the child-related methods inherited from L<Rose::HTML::Object>.
479              
480             =head1 SUBCLASSING
481              
482             Actual compound fields must override the following methods: L<build_field()|/build_field>, L<decompose_value()|/decompose_value>, and L<coalesce_value()|/coalesce_value>. The required semantics of those methods are described in the L<OBJECT METHODS> section below.
483              
484             =head1 SUBFIELD ADDRESSING
485              
486             Subfields are fields that are contained within another field. A field that has sub-fields is called a compound field. It is important to HTML form initialization that sub-fields be addressable from the top level. Since fields can be arbitrarily nested, some form of hierarchy must also exist in the field addressing scheme.
487              
488             To that end, compound fields use the "." character to partition the namespace. For example, the "month" sub-field of a compound field named "date" could be addressed from the L<form|Rose::HTML::Form> that contains the field using the name "date.month". As a consequence of this convention, I<field names may not contain periods>.
489              
490             Subfields are addressed by their "relative" names from the perspective of the caller. For example, the L<Rose::HTML::Form::Field::DateTime::Split::MDYHMS> custom field class contains a two compound fields: one for the time (split into hours, minutes, seconds, and AM/PM) and one for the date (split into month, day, and year). Here are a few ways to address the various sub-fields.
491              
492             $datetime_field =
493             Rose::HTML::Form::Field::DateTime::Split::MDYHMS->new(
494             name => 'datetime');
495              
496             ## Get the (compound) sub-field containing the month, day, and year
497             $mdy_field = $datetime_field->field('date');
498              
499              
500             ## Get the year sub-field of the month/day/year sub-field
501             ## in two different ways:
502              
503             # Fully-qualified sub-field access
504             $year_field = $datetime_field->field('date.year');
505              
506             # Relative sub-field access
507             $year_field = $datetime_field->field('date')->field('year');
508              
509             See the L<Rose::HTML::Form> documentation for more information on how forms address and initialize fields based on query parameter names.
510              
511             =head1 VALIDATION
512              
513             It is not the job of the L<coalesce_value()|/coalesce_value> or L<decompose_value()|/decompose_value> methods to validate input. That's the job of the L<validate()|Rose::HTML::Form::Field/validate> method in L<Rose::HTML::Form::Field>.
514              
515             But as you'll see when you start to write your own L<decompose_value()|/decompose_value> methods, it's often nice to know whether the input is valid before you try to decompose it into sub-field values. Valid input can usually be divided up very easily, whereas invalid input requires some hard decisions to be made. Consequently, most L<decompose_value()|/decompose_value> methods have one section for handling valid input, and another that makes a best-effort to handle invalid input.
516              
517             There are several ways to determine whether or not a value passed to L<decompose_value()|/decompose_value> is valid. You could actually call L<validate()|Rose::HTML::Form::Field/validate>, but that is technically a violation of the API since L<decompose_value()|/decompose_value> only knows that it's supposed to divvy up the value that it is passed. It is merely assuming that this value is also the current value of the field. In short, don't do that.
518              
519             The L<decompose_value()|/decompose_value> method could try to validate the input directly, of course. But that seems like a duplication of code. It might work, but it is more effort.
520              
521             The recommended solution is to rely on the fact that most overridden L<inflate_value()|Rose::HTML::Form::Field/inflate_value> methods serve as an alternate form of validation. Really, the L<decompose_value()|/decompose_value> method doesn't I<want> to "validate" in the same way that L<validate()|Rose::HTML::Form::Field/validate> does. Imagine a month/day/year compound field that only accepts dates in the 1990s. As far as L<validate()|Rose::HTML::Form::Field/validate> is concerned, 12/31/2002 is an invalid value. But as far as L<decompose_value()|/decompose_value> is concerned, it's perfectly fine and can be parsed and divided up into sub-field values easily.
522              
523             This is exactly the determination that many overridden L<inflate_value()|Rose::HTML::Form::Field/inflate_value> methods must also make. For example, that month/day/year compound field may use a L<DateTime> object as its internal value. The L<inflate_value()|Rose::HTML::Form::Field/inflate_value> method must parse a date string and produce a L<DateTime> value. The L<decompose_value()|/decompose_value> method can use that to its advantage. Example:
524              
525             sub decompose_value
526             {
527             my($self, $value) = @_;
528              
529             return undef unless(defined $value);
530              
531             # Use inflate_value() to do the dirty work of
532             # sanity checking the value for us
533             my $date = $self->SUPER::inflate_value($value);
534              
535             # Garbage input: try to do something sensible
536             unless($date)
537             {
538             my($month, $day, $year) = split('/', $value);
539              
540             return
541             {
542             month => $month || '',
543             day => $day || '',
544             year => $year || '',
545             }
546             }
547              
548             # Valid input: divide up appropriately
549             return
550             {
551             month => $date->month,
552             day => $date->day,
553             year => $date->year,
554             };
555             }
556              
557             This technique is sound because both L<decompose_value()|/decompose_value> and L<inflate_value()|Rose::HTML::Form::Field/inflate_value> work only with the input they are given, and have no reliance on the state of the field object itself (unlike L<validate()|Rose::HTML::Form::Field/validate>).
558              
559             If the L<inflate_value()|Rose::HTML::Form::Field/inflate_value> method is not being used, then L<decompose_value()|/decompose_value> must sanity check its own input. But this code is not necessarily the same as the code in L<validate()|Rose::HTML::Form::Field/validate>, so there is no real duplication.
560              
561             =head1 OBJECT METHODS
562              
563             =over 4
564              
565             =item B<add_field ARGS>
566              
567             Convenience alias for L<add_fields()|/add_fields>.
568              
569             =item B<add_fields ARGS>
570              
571             Add the fields specified by ARGS to the list of sub-fields in this compound field.
572              
573             If an argument is "isa" L<Rose::HTML::Form::Field>, then it is added to the list of fields, stored under the name returned by the field's L<name()|Rose::HTML::Form::Field/name> method.
574              
575             If an argument is anything else, it is used as the field name, and the next argument is used as the field object to store under that name. If the next argument is not an object derived from L<Rose::HTML::Form::Field>, then a fatal error occurs.
576              
577             The field object's L<name()|Rose::HTML::Form::Field/name> is set to the name that it is stored under, and its L<parent_field()|Rose::HTML::Form::Field/parent_field> is set to the form object.
578              
579             Returns the full list of field objects, sorted by field name, in list context, or a reference to a list of the same in scalar context.
580              
581             Examples:
582              
583             $name_field =
584             Rose::HTML::Form::Field::Text->new(name => 'name',
585             size => 25);
586              
587             $email_field =
588             Rose::HTML::Form::Field::Text->new(name => 'email',
589             size => 50);
590              
591             # Field arguments
592             $compound_field->add_fields($name_field, $email_field);
593              
594             # Name/field pairs
595             $compound_field2->add_fields(name => $name_field,
596             email => $email_field);
597              
598             # Mixed
599             $compound_field3->add_fields($name_field,
600             email => $email_field);
601              
602             =item B<auto_invalidate_parents [BOOL]>
603              
604             Get or set a boolean value that indicates whether or not the internal value of any parent fields are automatically invalidated when the input value of this field is set. The default is true.
605              
606             =item B<build_field>
607              
608             This method must be overridden by subclasses. Its job is to build the compound field by creating and then adding the sub-fields. Example:
609              
610             sub build_field
611             {
612             my($self) = shift;
613              
614             $self->add_fields
615             (
616             first => { type => 'text', size => 15, maxlength => 50 },
617             middle => { type => 'text', size => 15, maxlength => 50 },
618             last => { type => 'text', size => 20, maxlength => 50 },
619             );
620             }
621              
622             See the documentation for L<add_fields()|/add_fields> for a full description of the arguments it accepts.
623              
624             =item B<coalesce_value>
625              
626             This method must be overridden by subclasses. It is responsible for combining the values of the sub-fields into a single value. Example:
627              
628             sub coalesce_value
629             {
630             my($self) = shift;
631             return join(' ', map { defined($_) ? $_ : '' }
632             map { $self->field($_)->internal_value }
633             qw(first middle last));
634             }
635              
636             The value returned must be suitable as an input value. See the L<Rose::HTML::Form::Field> documentation for more information on input values.
637              
638             =item B<decompose_value VALUE>
639              
640             This method must be overridden by subclasses. It is responsible for distributing the input value VALUE amongst the various sub-fields. This is harder than you might expect, given the possibility of invalid input. Nevertheless, subclasses must try to divvy up even garbage values such that they eventually produce output values that are equivalent to the original input value when fed back through the system.
641              
642             The method should return a reference to a hash of sub-field-name/value pairs.
643              
644             In the example below, the method's job is to decompose a full name into first, middle, and last names. It is not very heroic in its efforts to parse the name, but it at least tries to ensure that every significant piece of the value ends up back in one of the sub-fields.
645              
646             sub decompose_value
647             {
648             my($self, $value) = @_;
649              
650             return undef unless(defined $value);
651              
652             # First, middle, and last names all present
653             if($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/)
654             {
655             return
656             {
657             first => $1,
658             middle => $2,
659             last => $3,
660             };
661             }
662              
663             my @parts = split(/\s+/, $value);
664              
665             # First and last?
666             if(@parts == 2)
667             {
668             return
669             {
670             first => $parts[0],
671             middle => undef,
672             last => $parts[1],
673             };
674             }
675              
676             # Oh well, at least try to make sure all the non-whitespace
677             # characters get fed back into the field
678             return
679             {
680             first => $parts[0],
681             middle => $parts[1],
682             last => join(' ', @parts[2 .. $#parts]),
683             };
684             }
685              
686             =item B<disabled [BOOL]>
687              
688             This method calls the C<disabled()> method on all L<fields|/fields> that possess such a method, passing all arguments. Set to true to disable all eligible sub-fields, false to enable them.
689              
690             =item B<field NAME [, VALUE]>
691              
692             Get or set the field specified by NAME. If only a NAME argument is passed, then the field stored under the name NAME is returned. If no field exists under that name exists, then undef is returned.
693              
694             If both NAME and VALUE arguments are passed, then the field VALUE is stored under the name NAME. If VALUE is not an object derived from L<Rose::HTML::Form::Field>, a fatal error occurs.
695              
696             =item B<fields>
697              
698             Returns the full list of field objects, sorted by field name, in list context, or a reference to a list of the same in scalar context.
699              
700             =item B<field_value NAME>
701              
702             Returns the L<internal_value|Rose::HTML::Form::Field/internal_value> of the sub-field named NAME. In other words, this:
703              
704             $val = $field->field_value('zip_code');
705              
706             is just a shorter way to write this:
707              
708             $val = $field->field('zip_code')->internal_value;
709              
710             =item B<html_field>
711              
712             Returns the HTML serialization of the field. The default implementation calls L<html_field|Rose::HTML::Form::Field/html_field> on each of the L<fields|/fields> and then concatenates and the results. Override this method in your compound field subclass to lay out your sub-fields as desired.
713              
714             =item B<invalidate_value>
715              
716             Invalidates the field's value, and the value of all of its parent fields, and so on. This will cause the field's values to be recreated the next time they are retrieved.
717              
718             =item B<is_empty>
719              
720             Returns true if all of the sub-fields are empty, false otherwise.
721              
722             =item B<is_full>
723              
724             Returns false if any of the sub-fields are empty, true otherwise. Subclasses can override this method to indicate that a valid value does not require all sub-fields to be non-empty.
725              
726             For example, consider a compound time field with sub-fields for hours, minutes, seconds, and AM/PM. It may only require the hour and AM/PM sub-fields to be filled in. It could then assume values of zero for all of the empty sub-fields.
727              
728             Note that this behavior is different than making "00" the default values of the minutes and seconds sub-fields. Default values are shown in the HTML serializations of fields, so the minutes and seconds fields would be pre-filled with "00" (unless the field is cleared--see L<Rose::HTML::Form::Field>'s L<reset|Rose::HTML::Form::Field/reset> and L<clear|Rose::HTML::Form::Field/clear> methods for more information).
729              
730             If a subclass does override the C<is_full> method in order to allow one or more empty sub-fields while still considering the field "full," the subclass must also be sure that its L<coalesce_value|/coalesce_value> method accounts for and handles the possibility of empty fields.
731              
732             See the L<Rose::HTML::Form::Field::Time::Split::HourMinuteSecond> source code for an actual implementation of the behavior described above. In particular, look at the implementation of the C<is_full> and C<coalesce_value> methods.
733              
734             =item B<subfield_input_value NAME [, VALUE]>
735              
736             Get or set the input value of the sub-field named NAME. If there is no sub-field by that name, a fatal error will occur.
737              
738             This method has the same effect as fetching the sub-field using the L<field|/field> method and then calling L<input_value|Rose::HTML::Form::Field/input_value> directly on it, but with one important exception. Setting a sub-field input value using the L<subfield_input_value|/subfield_input_value> method will B<not> invalidate the value of the parent field.
739              
740             This method is therefore essential for implementing compound fields that need to set their sub-field values directly. Without it, any attempt to do so would cause the compound field to invalidate itself.
741              
742             See the source code for L<Rose::HTML::Form::Field::DateTime::Range>'s L<inflate_value|Rose::HTML::Form::Field::DateTime::Range/inflate_value> method for a real-world usage example of the L<subfield_input_value|/subfield_input_value> method.
743              
744             =item B<xhtml_field>
745              
746             Returns the XHTML serialization of the field. The default implementation calls L<xhtml_field|Rose::HTML::Form::Field/xhtml_field> on each of the L<fields|/fields> and then concatenates and the results. Override this method in your compound field subclass to lay out your sub-fields as desired.
747              
748             =back
749              
750             =head1 SUPPORT
751              
752             Any L<Rose::HTML::Objects> questions or problems can be posted to the L<Rose::HTML::Objects> mailing list. To subscribe to the list or search the archives, go here:
753              
754             L<http://groups.google.com/group/rose-html-objects>
755              
756             Although the mailing list is the preferred support mechanism, you can also email the author (see below) or file bugs using the CPAN bug tracking system:
757              
758             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rose-HTML-Objects>
759              
760             There's also a wiki and other resources linked from the Rose project home page:
761              
762             L<http://rosecode.org>
763              
764             =head1 AUTHOR
765              
766             John C. Siracusa (siracusa@gmail.com)
767              
768             =head1 LICENSE
769              
770             Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.