|
NAMERose::HTML::Form::Field::Compound - Base class for field objects that contain other field objects.SYNOPSISpackage MyFullNameField; use base qw(Rose::HTML::Form::Field::Compound Rose::HTML::Form::Field::Text); sub build_field { my($self) = shift; $self->add_fields ( first => { type => 'text', size => 15, maxlength => 50 }, middle => { type => 'text', size => 15, maxlength => 50 }, last => { type => 'text', size => 20, maxlength => 50 }, ); } sub coalesce_value { my($self) = shift; return join(' ', map { defined($_) ? $_ : '' } map { $self->field($_)->internal_value } qw(first middle last)); } sub decompose_value { my($self, $value) = @_; return undef unless(defined $value); if($value =~ /^(\S+)\s+(\S+)\s+(\S+)$/) { return { first => $1, middle => $2, last => $3, }; } my @parts = split(/\s+/, $value); if(@parts == 2) { return { first => $parts[0], middle => undef, last => $parts[1], }; } return { first => $parts[0], middle => $parts[1], last => join(' ', @parts[2 .. $#parts]), }; } # Override these methods to determine how sub-fields are arranged sub html_field { ... } sub xhtml_field { ... } ... use MyFullNameField; $field = MyFullNameField->new( label => 'Full Name', name => 'name', default => 'John Doe'); print $field->internal_value; # "John Doe" $field->input_value('Steven Paul Jobs'); print $field->field('middle')->internal_value; # "Paul" print $field->html; ... DESCRIPTIONRose::HTML::Form::Field::Compound is a base class for compound fields. A compound field is one that contains other fields. The example in the 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.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 Rose::HTML::Form::Field::Compound. Rose::HTML::Form uses this relationship in order to identify compound fields and handle them correctly. Any compound field that does not inherit from Rose::HTML::Form::Field::Compound will not work correctly with Rose::HTML::Form. This class inherits from, and follows the conventions of, Rose::HTML::Form::Field. Inherited methods that are not overridden will not be documented a second time here. See the Rose::HTML::Form::Field documentation for more information. HIERARCHYA Rose::HTML::Form::Field::Compound-derived object behaves as if it is a single field made up of a group of sibling elements. These siblings are available through the fields method.See the "hierarchy" sections of the "HIERARCHY" in Rose::HTML::Form::Field and "HIERARCHY" in Rose::HTML::Form 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 Rose::HTML::Object. SUBCLASSINGActual compound fields must override the following methods: build_field(), decompose_value(), and coalesce_value(). The required semantics of those methods are described in the "OBJECT METHODS" section below.SUBFIELD ADDRESSINGSubfields 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.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 form that contains the field using the name "date.month". As a consequence of this convention, field names may not contain periods. Subfields are addressed by their "relative" names from the perspective of the caller. For example, the 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. $datetime_field = Rose::HTML::Form::Field::DateTime::Split::MDYHMS->new( name => 'datetime'); ## Get the (compound) sub-field containing the month, day, and year $mdy_field = $datetime_field->field('date'); ## Get the year sub-field of the month/day/year sub-field ## in two different ways: # Fully-qualified sub-field access $year_field = $datetime_field->field('date.year'); # Relative sub-field access $year_field = $datetime_field->field('date')->field('year'); See the Rose::HTML::Form documentation for more information on how forms address and initialize fields based on query parameter names. VALIDATIONIt is not the job of the coalesce_value() or decompose_value() methods to validate input. That's the job of the validate() method in Rose::HTML::Form::Field.But as you'll see when you start to write your own 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 decompose_value() methods have one section for handling valid input, and another that makes a best-effort to handle invalid input. There are several ways to determine whether or not a value passed to decompose_value() is valid. You could actually call validate(), but that is technically a violation of the API since 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. The 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. The recommended solution is to rely on the fact that most overridden inflate_value() methods serve as an alternate form of validation. Really, the decompose_value() method doesn't want to "validate" in the same way that validate() does. Imagine a month/day/year compound field that only accepts dates in the 1990s. As far as validate() is concerned, 12/31/2002 is an invalid value. But as far as decompose_value() is concerned, it's perfectly fine and can be parsed and divided up into sub-field values easily. This is exactly the determination that many overridden inflate_value() methods must also make. For example, that month/day/year compound field may use a DateTime object as its internal value. The inflate_value() method must parse a date string and produce a DateTime value. The decompose_value() method can use that to its advantage. Example: sub decompose_value { my($self, $value) = @_; return undef unless(defined $value); # Use inflate_value() to do the dirty work of # sanity checking the value for us my $date = $self->SUPER::inflate_value($value); # Garbage input: try to do something sensible unless($date) { my($month, $day, $year) = split('/', $value); return { month => $month || '', day => $day || '', year => $year || '', } } # Valid input: divide up appropriately return { month => $date->month, day => $date->day, year => $date->year, }; } This technique is sound because both decompose_value() and inflate_value() work only with the input they are given, and have no reliance on the state of the field object itself (unlike validate()). If the inflate_value() method is not being used, then decompose_value() must sanity check its own input. But this code is not necessarily the same as the code in validate(), so there is no real duplication. OBJECT METHODS
SUPPORTAny Rose::HTML::Objects questions or problems can be posted to the Rose::HTML::Objects mailing list. To subscribe to the list or search the archives, go here:<http://groups.google.com/group/rose-html-objects> 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: <http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rose-HTML-Objects> There's also a wiki and other resources linked from the Rose project home page: <http://rosecode.org> AUTHORJohn C. Siracusa (siracusa@gmail.com)LICENSECopyright (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.
Visit the GSP FreeBSD Man Page Interface. |