NAME

Rose::HTML::Form - HTML form base class.

SYNOPSIS

  package PersonForm;

  use Rose::HTML::Form;
  our @ISA = qw(Rose::HTML::Form);

  use Person;

  sub build_form 
  {
    my($self) = shift;

    $self->add_fields
    (
      name  => { type => 'text',  size => 25, required => 1 },
      email => { type => 'email', size => 50, required => 1 },
      phone => { type => 'phone' },
    );
  }

  sub validate
  {
    my($self) = shift;

    # Base class will validate individual fields in isolation,
    # confirming that all required fields are filled in, and that
    # the email address and phone number are formatted correctly.
    my $ok = $self->SUPER::validate(@_);
    return $ok  unless($ok);

    # Inter-field validation goes here
    if($self->field('name')->internal_value ne 'John Doe' &&
       $self->field('phone')->internal_value =~ /^555/)
    {
      $self->error('Only John Doe can have a 555 phone number.');
      return 0;
    }

    return 1;
  }

  sub init_with_person # give a friendlier name to a base-class method
  {
    my($self, $person) = @_;
    $self->init_with_object($person);
  }

  sub person_from_form
  {
    my($self) = shift;

    # Base class method does most of the work
    my $person = $self->object_from_form(class => 'Person');

    # Now fill in the non-obvious details...
    # e.g., set alt phone to be the same as the regular phone
    $person->alt_phone($self->field('phone')->internal_value);

    return $person;
  }

  ...

  #
  # Sample usage in a hypothetical web application
  #

  $form = PersonForm->new;

  if(...)
  {
    # Get query parameters in a hash ref and pass to the form
    my $params = MyWebServer->get_query_params();
    $form->params($params);

    # ...or  initialize form params from a CGI object
    # $form->params_from_cgi($cgi); # $cgi "isa" CGI

    # ...or initialize params from an Apache request object
    # (mod_perl 1 and 2 both supported)
    # $form->params_from_apache($r);

    # Initialize the fields based on params
    $form->init_fields();

    unless($form->validate) 
    {
      return error_page(error => $form->error);
    }

    $person = $form->person_from_form; # $person is a Person object

    do_something_with($person);
    ...
  }
  else
  {
    $person = ...; # Get or create a Person object somehow

    # Initialize the form with the Person object
    $form->init_with_person($person);

    # Pass the initialized form object to the template
    display_page(form => $form);
  }
  ...

DESCRIPTION

Rose::HTML::Form is more than just an object representation of the <form> HTML tag. It is meant to be a base class for custom form classes that can be initialized with and return "rich" values such as objects, or collections of objects.

Building up a reusable library of form classes is extremely helpful when building large web applications with forms that may appear in many different places. Similar forms can inherit from a common subclass, and forms may be nested.

This class inherits from, and follows the conventions of, Rose::HTML::Object. Inherited methods that are not overridden will not be documented a second time here. See the Rose::HTML::Object documentation for more information.

OVERVIEW

Rose::HTML::Form objects are meant to encapsulate an entire HTML form, including all fields within the form. While individual fields may be queried and manipulated, the intended purpose of this class is to treat the form as a "black box" as much as possible.

For example, instead of asking a form object for the values of the "name", "email", and "phone" fields, the user would ask the form object to return a new "Person" object that encapsulates those values.

Form objects should also accept initialization through the same kinds of objects that they return. Subclasses are encouraged to create methods such as (to use the example described above) init_with_person() and person_from_form() in order to do this. The generic methods init_with_object() and object_from_form() are meant to ease the implementation of such custom methods.

Form objects can also take input through a hash. Each hash key correspond to a field (or subfield) name, and each value is either a scalar or a reference to an array of scalars (for multiple-value fields). This hash of parameters can be queried and manipulated before finally calling init_fields() in order to initialize the fields based on the current state of the parameters.

Compound fields (fields consisting of more than one HTML field, such as a month/day/year date field with separate text fields for each element of the date) may be "addressed" by hash arguments using both top-level names (e.g., "birthday") or by subfield names (e.g., "birthday.month", "birthday.day", "birthday.year"). If the top-level name exists in the hash, then subfield names are ignored. See Rose::HTML::Form::Field::Compound for more information on compound fields.

Each form has a list of field objects. Each field object is stored under a name, which may or may not be the same as the field name, which may or may not be the same as the "name" HTML attribute for any of the HTML tags that make up that field.

Forms are validated by calling validate() on each field object. If any individual field does not validate, then the form is invalid. Inter-field validation is the responsibility of the form object.

NESTED FORMS

Each form can have zero or more fields as well as zero or more sub-forms. Since <form> HTML tags cannot be nested, this nesting of form objects appears "flattened" in the external interfaces such as HTML generation or field addressing.

Here's a simple example of a nested form made up of a PersonForm and an AddressForm. (Assume PersonForm is constructed as per the synopsis above, and AddressForm is similar, with street, city, state, and zip code fields.)

    package PersonAddressForm;

    use PersonForm;
    use AddressForm;

    sub build_field
    {
      my($self) = shift;

      $self->add_forms
      (
        person  => PersonForm->new,
        address => AddressForm->new,
      );
    }

Each sub-form is given a name. Sub-field addressing incorporates that name in much the same way as compound field addressing, with dots (".") used to delimit the hierarchy. Here are two different ways to get at the person's email field.

    $form = PersonAddressForm->new;

    # These are equivalent
    $email_field = $form->field('person.email');
    $email_field = $form->form('person')->field('email');

Methods on the sub-forms maybe accessed in a similar manner.

    $person = $form->form('person')->person_from_form();

By default, methods are delegated to sub-forms automatically, so this works too.

    $person = $form->person_from_form();

(See the delegate_to_subforms() method to learn how to alter this behavior.)

Nested forms may have their own fields as well, and the nesting may continue to an arbitrary depth. Here's a form that contains a PersonAddressForm as well as two fields of its own.

    package PersonAddressPetsForm;

    use PersonAddressForm;

    sub build_field
    {
      my($self) = shift;

      $self->add_form(pa => PersonAddressForm->new);

      $self->add_fields
      (
        dog => { type => 'text', size => 30 },
        cat => { type => 'text', size => 30 },
      );
    }

Sub-form and field addressing works as expected. Here are several equivalent ways to get at the person's email field.

    $form = PersonAddressPetsForm->new;

    # These are all equivalent
    $email_field = $form->field('pa.person.email');
    $email_field = $form->form('pa.person')->field('email');
    $email_field = $form->form('pa')->form('person')->field('email');

Sub-form method calls and delegation also works as expected.

    # Call method on the PersonForm, two different ways
    $person = $form->form('pa')->form('person')->person_from_form();
    $person = $form->form('pa.person')->person_from_form();

    # Rely on delegation instead
    $person = $form->form('pa')->person_from_form();
    $person = $form->person_from_form();

Nested forms are a great way to build on top of past work. When combined with traditional subclassing, form generation can be entirely cleansed of duplicated code.

HTML ATTRIBUTES

Valid attributes:

    accept
    accept-charset
    accesskey
    action
    class
    dir
    enctype
    id
    lang
    method
    name
    onblur
    onclick
    ondblclick
    onfocus
    onkeydown
    onkeypress
    onkeyup
    onmousedown
    onmousemove
    onmouseout
    onmouseover
    onmouseup
    onreset
    onsubmit
    style
    tabindex
    title
    value
    xml:lang

Required attributes (default values in parentheses):

    action
    enctype (application/x-www-form-urlencoded)
    method  (get)

CLASS METHODS

delegate_to_subforms [SETTING]

Get or set the value that determines how (or if) forms of this class delegate unresolved method calls to sub-forms. If a method is called on a form of this class, and that method does not exist in this class or any other class in its inheritance hierarchy, then the method may optionally be delegated to a sub-forms. Valid values for SETTING are:

"0"

A value of "0" (or undef or any other false value) means that no sub-form delegation will be attempted.

"1"

A value of "1" means the same thing as a value of "runtime" (see below).

"compile"

For each unresolved method call, each sub-form is is considered in the order that they are returned from the forms method until one is found that can handle this method. If one is found, then a new proxy method is added to this class that calls the requested method on the sub-form, passing all arguments unmodified. That proxy method is then called.

Subsequent invocations of this method will no longer trigger the search process. Instead, they will be handled by the newly-compiled proxy method. This is more efficient than repeating the sub-form search each time, but it also means that a change in the list of sub-forms could render the newly compiled method useless (e.g., if the sub-form it delegates to is removed).

If no sub-form can handle the method, then a fatal "unknown method" error occurs.

"runtime"

For each unresolved method call, each sub-form is is considered in the order that they are returned from the forms method until one is found that can handle this method. If one is found, then the method is called on that sub-form, passing all arguments unmodified.

Subsequent invocations of this method will trigger the same search process, again looking for a a sub-form that can handle it. This is less efficient than compiling a new proxy method as described in the documentation for the "compile" setting above, but it does mean that any changes in the list of sub-forms will be handled correctly.

If no sub-form can handle the method, then a fatal "unknown method" error occurs.

The default value for SETTING is compile. See the nested forms section for some examples of sub-form delegation.

CONSTRUCTOR

new PARAMS

Constructs a new Rose::HTML::Form object based on PARAMS, where PARAMS are name/value pairs. Any object method is a valid parameter name.

OBJECT METHODS

add_field ARGS

Convenience alias for add_fields().

add_fields ARGS

Add the fields specified by ARGS to the list of fields contained in this form. Valid formats for elements of ARGS are:

Field objects

If an argument is "isa" Rose::HTML::Form::Field, then it is added to the list of fields, stored under the name returned by the field's name method.

Field name/type pairs

A pair of simple scalars is taken as a field name and type. The class that corresponds to the specified field type is determined by calling the field_type_class method. Then a new object of that class is constructed and added to the form.

Field name/hashref pairs

A simple scalar followed by a reference to a hash it taken as a field name and a collection of object attributes. The referenced hash must contain a value for the type key. The field class that corresponds to the specified field type is determined by calling the field_type_class method. Then a new object of that class is constructed, with the remaining key/value pairs in the hash are passed to the constructor. The completed field object is then added to the form.

Field name/object pairs

A simple scalar followed by an object that "isa" Rose::HTML::Form::Field is stored as-is, under the specified name.

Each field's parent_form is set to the form object. If the field's rank is undefined, it's set to the value of the form's field_rank_counter attribute and the rank counter is incremented.

Examples:

    # Name/hashref pairs
    $form->add_fields(name  => { type => 'text',  size => 20 },
                      email => { type => 'email', size => 30 });

    # Name/type pairs
    $form->add_fields(name  => 'text',
                      email => 'email');

    $name_field = 
      Rose::HTML::Form::Field::Text->new(name => 'name',
                                         size => 25);

    $email_field = 
      Rose::HTML::Form::Field::Text->new(name => 'email',
                                         size => 50);

    # Object arguments
    $form->add_fields($name_field, $email_field);

    # Name/object pairs
    $form->add_fields(name  => $name_field, 
                      email => $email_field);

    # Mixed
    $form->add_fields($name_field, 
                      email => $email_field,
                      nick  => { type => 'text', size => 15 },
                      age   => 'text');
add_form ARGS

This is an alias for the add_forms() method.

add_forms ARGS

Add the forms specified by ARGS to the list of sub-forms contained in this form. See the nested forms section for more information.

Valid formats for elements of ARGS are:

Form objects

If an argument is "isa" Rose::HTML::Form, then it is added to the list of forms, stored under the name returned by the form's form_name method.

Form name/object pairs

A simple scalar followed by an object that "isa" Rose::HTML::Form has its form_name set to the specified name and then is stored under that name.

If the name contains any dots (".") it will be taken as a hierarchical name and the form will be added to the specified sub-form under an unqualified name consisting of the final part of the name. (See examples below.)

Each form's parent_form is set to the form object it was added to. If the form's rank is undefined, it's set to the value of the form's form_rank_counter attribute and the rank counter is incremented.

Examples:

    $a_form = Rose::HTML::Form->new(...);
    $b_form = Rose::HTML::Form->new(...);

    # Object arguments
    $form->add_forms($a_form, $b_form);

    # Name/object pairs
    $form->add_forms(a => $a_form, b => $b_form);

    # Mixed
    $form->add_forms($a_form, b => $b_form);

    # Set nested form from the top-level
    $w_form = Rose::HTML::Form->new(...);
    $x_form = Rose::HTML::Form->new(...);
    $y_form = Rose::HTML::Form->new(...);
    $z_form = Rose::HTML::Form->new(...);

    $w_form->add_form('x' => $x_form);
    $x_form->add_form('y' => $y_form);

    # Add $z_form to $w_form->form('x')->form('y') under the name 'z'
    $w_form->add_form('x.y.z' => $z_form);
add_param_value NAME, VALUE

Add VALUE to the parameter named NAME. Example:

    $form->param(a => 1);
    print $form->param('a'); # 1

    $form->add_param_value(a => 2);

    print join(',', $form->param('a')); # 1,2
build_on_init [BOOL]

Get or set a boolean flag that indicates whether or not build_form() should be called from within the init() method. See build_form() for more information.

build_form

This default implementation of this method is a no-op. It is meant to be overridden by subclasses. It is called at the end of the init() method if build_on_init() is true. (Remember that this class inherits from Rose::HTML::Object, which inherits from Rose::Object, which defines the init() method, which is called from the constructor. See the Rose::Object documentation for more information.)

If build_on_init() is false, then you must remember to call build_form() manually.

Subclasses should populate the field list in their overridden versions of build_form(). Example:

  sub build_form 
  {
    my($self) = shift;

    $self->add_fields
    (
      name  => { type => 'text',  size => 25, required => 1 },
      email => { type => 'email', size => 50, required => 1 },
      phone => { type => 'phone' },
    );
  }
clear

Call clear() on each field object and set error() to undef.

clear_fields

Call clear() on each field object.

coalesce_hidden_fields [BOOL]

Get or set the boolean flag that controls how compound field values are encoded in hidden fields. If this flag is true, then each compound field is encoded as a single hidden field. If the flag is false (the default), then each subfield of a compound field will have its own hidden field.

coalesce_query_string_params [BOOL]

Get or set the boolean flag that controls how compound field values are encoded in the query string. If this flag is true (the default), then compound fields are represented by a single query parameter. Otherwise, the subfields of each compound field appear as separate query parameters.

compare_fields [FIELD1, FIELD2]

Compare two fields, returning 1 if FIELD1 should come before FIELD2, -1 if FIELD2 should come before FIELD1, or 0 if neither field should come before the other. This method is called from within the field_names method to determine the order of the fields in this form.

The default implementation performs a string comparison on the names of the fields.

compare_forms [FORM1, FORM2]

Compare two forms, returning 1 if FORM1 should come before FORM2, -1 if FORM2 should come before FORM1, or 0 if neither form should come before the other. This method is called from within the form_names method to determine the order of the sub-forms nested within this form.

The default implementation compares the rank of the forms in numeric context.

delete_field NAME

Delete the form stored under the name NAME. If NAME "isa" Rose::HTML::Form::Field, then the name method is called on it and the return value is used as NAME.

delete_fields

Delete all fields, leaving the list of fields empty. The field_rank_counter is also reset to 1.

delete_field_type_class TYPE

Delete the type/class mapping entry for the field type TYPE.

delete_form NAME

Delete the form stored under the name NAME. If NAME "isa" Rose::HTML::Form, then the form_name method is called on it and the return value is used as NAME.

delete_forms

Delete all sub-forms, leaving the list of sub-forms empty. The form_rank_counter is also reset to 1.

delete_param NAME [, VALUES]

If just the NAME argument is passed, the parameter named NAME is deleted.

If VALUES are also passed, then VALUES are deleted from the set of values held by the parameter name NAME. If only one value remains, then it is the new value for the NAME parameter (i.e., the value is no longer an array reference, but a scalar instead). If every value is deleted, then the NAME parameter is deleted as well. Example:

    $form->param(a => [ 1, 2, 3, 4 ]);

    $form->delete_param(a => 1);
    $vals = $form->param('a'); # [ 2, 3, 4 ]

    $form->delete_param(a => [ 2, 3 ]);
    $vals = $form->param('a'); # 4

    $form->delete_param(a => 4);
    $vals = $form->param('a'); # undef
    $form->param_exists('a');  # false
delete_params

Delete all parameters.

end_html

Returns the HTML required to end the form.

end_xhtml

Returns the XHTML required to end the form.

end_multipart_html

Returns the HTML required to end a multipart form.

end_multipart_xhtml

Returns the XHTML required to end a multipart form.

field NAME [, VALUE]

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.

If both NAME and VALUE arguments are passed, then the VALUE must be a Rose::HTML::Form::Field or a reference to a hash whose contents are as described in the documentation for the add_fields method.

fields

Returns an ordered list of this form's field objects in list context, or a reference to this list in scalar context. The order of the fields matches the order of the field names returned by the field_names method.

field_names

Returns an ordered list of field names in list context, or a reference to this list in scalar context. The order is determined by the compare_fields method by default.

You can override the compare_fields method in your subclass to provide a custom sort order, or you can override the field_names method itself to provide an arbitrary order, ignoring the compare_fields method entirely.

field_rank_counter [INT]

Get or set the value of the counter used to set the rank of fields as they're added to the form. The counter starts at 1 by default.

field_type_class TYPE [, CLASS]

Given the field type string TYPE, return the name of the Rose::HTML::Form::Field-derived class mapped to that name. If a CLASS is passed, the field type TYPE is mapped to CLASS. In both cases, the TYPE argument is automatically converted to lowercase.

field_type_classes [MAP]

Get or set the hash that maps field type strings to the names of the Rose::HTML::Form::Field-derived classes.

This hash is class data. If you want to modify it, I suggest making your own subclass of Rose::HTML::Form and then calling this method on your derived class.

If passed MAP (a list of type/class pairs or a reference to a hash of the same) then MAP replaces the current field type mapping. Returns a list of type/class pairs (in list context) or a reference to the hash of type/class mappings (in scalar context).

The default mapping of type names to class names is:

  'text'               => Rose::HTML::Form::Field::Text
  'scalar'             => Rose::HTML::Form::Field::Text
  'char'               => Rose::HTML::Form::Field::Text
  'character'          => Rose::HTML::Form::Field::Text
  'varchar'            => Rose::HTML::Form::Field::Text
  'string'             => Rose::HTML::Form::Field::Text

  'text area'          => Rose::HTML::Form::Field::TextArea
  'textarea'           => Rose::HTML::Form::Field::TextArea
  'blob'               => Rose::HTML::Form::Field::TextArea

  'checkbox'           => Rose::HTML::Form::Field::Checkbox
  'check'              => Rose::HTML::Form::Field::Checkbox

  'radio button'       => Rose::HTML::Form::Field::RadioButton
  'radio'              => Rose::HTML::Form::Field::RadioButton

  'checkboxes'         => Rose::HTML::Form::Field::CheckboxGroup
  'checks'             => Rose::HTML::Form::Field::CheckboxGroup
  'checkbox group'     => Rose::HTML::Form::Field::CheckboxGroup
  'check group'        => Rose::HTML::Form::Field::CheckboxGroup

  'radio buttons'      => Rose::HTML::Form::Field::RadioButton
  'radios'             => Rose::HTML::Form::Field::RadioButtonGroup
  'radio button group' => Rose::HTML::Form::Field::RadioButtonGroup
  'radio group'        => Rose::HTML::Form::Field::RadioButtonGroup

  'pop-up menu'        => Rose::HTML::Form::Field::PopUpMenu
  'popup menu'         => Rose::HTML::Form::Field::PopUpMenu
  'menu'               => Rose::HTML::Form::Field::PopUpMenu

  'select box'         => Rose::HTML::Form::Field::SelectBox
  'selectbox'          => Rose::HTML::Form::Field::SelectBox
  'select'             => Rose::HTML::Form::Field::SelectBox

  'submit'             => Rose::HTML::Form::Field::Submit
  'submit button'      => Rose::HTML::Form::Field::Submit

  'reset'              => Rose::HTML::Form::Field::Reset
  'reset button'       => Rose::HTML::Form::Field::Reset

  'file'               => Rose::HTML::Form::Field::File
  'upload'             => Rose::HTML::Form::Field::File

  'password'           => Rose::HTML::Form::Field::Password

  'hidden'             => Rose::HTML::Form::Field::Hidden

  'email'              => Rose::HTML::Form::Field::Email

  'phone'              => Rose::HTML::Form::Field::PhoneNumber::US
  'phone us'           => Rose::HTML::Form::Field::PhoneNumber::US

  'phone us split' =>
    Rose::HTML::Form::Field::PhoneNumber::US::Split

  'set'  => Rose::HTML::Form::Field::Set

  'time' => Rose::HTML::Form::Field::Time

  'time split hms' => 
    Rose::HTML::Form::Field::Time::Split::HourMinuteSecond

  'time hours'       => Rose::HTML::Form::Field::Time::Hours
  'time minutes'     => Rose::HTML::Form::Field::Time::Minutes
  'time seconds'     => Rose::HTML::Form::Field::Time::Seconds

  'date'             => Rose::HTML::Form::Field::Date
  'datetime'         => Rose::HTML::Form::Field::DateTime

  'datetime range'   => Rose::HTML::Form::Field::DateTime::Range

  'datetime start'   => Rose::HTML::Form::Field::DateTime::StartDate
  'datetime end'     => Rose::HTML::Form::Field::DateTime::EndDate

  'datetime split mdy' => 
    Rose::HTML::Form::Field::DateTime::Split::MonthDayYear

  'datetime split mdyhms' => 
    Rose::HTML::Form::Field::DateTime::Split::MDYHMS
form NAME [, OBJECT]

Get or set the sub-form named NAME. If just NAME is passed, the specified sub-form object is returned. If no such sub-form exists, undef is returnend.

If both NAME and OBJECT are passed, a new sub-form is added under NAME.

NAME is a fully-qualified sub-form name. Components of the hierarchy are separated by dots ("."). OBJECT must be an object that inherits from Rose::HTML::Form.

forms

Returns an ordered list of this form's sub-form objects (if any) in list context, or a reference to this list in scalar context. The order of the form matches the order of the form names returned by the form_names method.

See the nested forms section to learn more about nested forms.

form_name [NAME]

Get or set the name of this form. This name may or may not have any connection with the value of the "name" HTML attribute on the <form> tag. See the documentation for the name method for details.

form_names

Returns an ordered list of form names in list context, or a reference to this list in scalar context. The order is determined by the compare_forms method by default.

You can override the compare_forms method in your subclass to provide a custom sort order, or you can override the form_names method itself to provide an arbitrary order, ignoring the compare_forms method entirely.

form_rank_counter [INT]

Get or set the value of the counter used to set the rank of sub-forms as they're added to the form. The counter starts at 1 by default.

hidden_fields

Returns one or more Rose::HTML::Form::Field::Hidden objects that represent the hidden fields needed to encode all of the field values in this form.

If coalesce_hidden_fields() is true, then each compound field is encoded as a single hidden field. Otherwise, each subfield of a compound field will be have its own hidden field.

html_hidden_fields

Returns the HTML serialization of the fields returned by hidden_fields(), joined by newlines.

init_fields [ARGS]

Initialize the fields based on params(). In general, this works as you'd expect, but the details are a bit complicated.

The intention of init_fields() is to set field values based solely and entirely on params(). That means that default values for fields should not be considered unless they are explicitly part of params().

In general, default values for fields exist for the purpose of displaying the HTML form with certain items pre-selected or filled in. In a typical usage scenario, those default values will end up in the web browser form submission and, eventually, as as an explicit part of part params(), so they are not really ignored.

But to preserve the intended functionality of init_fields(), the first thing this method does is clear() the form. If a no_clear parameter with a true value is passed as part of ARGS, then this step is skipped.

If a parameter name exactly matches a field's name (note: the field's name, which is not necessarily the the same as the name that the field is stored under in the form), then the (list context) value of that parameter is passed as the input_value() for that field.

If a field "isa" Rose::HTML::Form::Field::Compound, and if no parameter exactly matches the name of the compound field, then each subfield may be initialized by a parameter name that matches the subfield's name.

If a field is an "on/off" type of field (e.g., a radio button or checkbox), then the field is turned "on" only if the value of the parameter that matches the field's name exactly matches (string comparison) the "value" HTML attribute of the field. If not, and if params_exist(), then the field is set to "off". Otherwise, the field is not modified at all.

Examples:

    package RegistrationForm;
    ...
    sub build_form 
    {
      my($self) = shift;

      $self->add_fields
      (
        name => { type => 'text', size => 25 },

        gender => 
        {
          type    => 'radio group',
          choices => { 'm' => 'Male', 'f' => 'Female' },
          default => 'm'
        },

        hobbies =>
        {
          type    => 'checkbox group',
          name    => 'hobbies',
          choices => [ 'Chess', 'Checkers', 'Knitting' ],
          default => 'Chess'
        },

        bday = => { type => 'date split mdy' }
      );
    }

    ...

    $form = RegistrationForm->new();

    $form->params(name    => 'John', 
                  gender  => 'm',
                  hobbies => undef,
                  bday    => '1/24/1984');

    # John, Male, no hobbies, 1/24/1984
    $form->init_fields;

    $form->reset;
    $form->params(name  => 'John', 
                  bday  => '1/24/1984');

    # No name, Male, Chess, 1/24/1984
    $form->init_fields(no_clear => 1);

    $form->reset;
    # Set using subfield names for "bday" compound field
    $form->params('name'       => 'John',
                  'bday.month' => 1,
                  'bday.day'   => 24,
                  'bday.year'  => 1984);

    # John, Male, no hobbies, 1/24/1984
    $form->init_fields();

    $form->reset;
    $form->params('bday'       => '1/24/1984',
                  'bday.month' => 12,
                  'bday.day'   => 25,
                  'bday.year'  => 1975);

    # No name, no gender, no hobbies, but 1/24/1984 because
    # the "bday" param trumps any and all subfield params.
    $form->init_fields();

    $form->reset;

    # Explicitly set hobbies field to Knitting...
    $form->field('hobbies')->input_value('Knitting');

    # ...but then provide a hobbies param with no value
    $form->params('hobbies' => undef);

    # Fields are not cleared, but the existence of the hobbies
    # param with an empty value causes the hobbies list to be
    # empty, instead of the default Chess.  Thus:
    #
    # No name, Male, no hobbies, no birthday
    $form->init_fields(no_clear => 1);
init_fields_with_cgi CGI [, ARGS]

This method is a shortcut for initializing the form's params with a CGI object and then calling init_fields. The CGI argument is passed to the params_from_cgi method and ARGS are passed to the init_fields method.

For example, this:

    $form->init_fields_with_cgi($cgi, no_clear => 1);

Is equivalent to this:

    $form->params_from_cgi($cgi);
    $form->init_fields(no_clear => 1);

See the documentation for the params_from_cgi and init_fields methods for more information.

init_fields_with_apache APR [, ARGS]

This method is a shortcut for initializing the form's params with an apache request object and then calling init_fields. The APR argument is passed to the params_from_apache method and ARGS are passed to the init_fields method.

For example, this:

    $form->init_fields_with_apache($r, no_clear => 1);

Is equivalent to this:

    $form->params_from_apache($r);
    $form->init_fields(no_clear => 1);

See the documentation for the params_from_apache and init_fields methods for more information.

init_with_object OBJECT

Initialize the form based on OBJECT. First, the form is clear()ed. Next, for each field name(), if the object has a method with the same name, then the return value of that method (called in scalar context) is passed as the input_value() for the form field of the same name.

The actual code for the init_with_object() method may be more clear than the description above. Essentially, it does this:

    sub init_with_object
    {
      my($self, $object) = @_;

      $self->clear();

      foreach my $field ($self->fields)
      {
        my $name = $field->local_name;

        if($object->can($name))
        {
          $field->input_value(scalar $object->$name());
        }
      }
    }

Use this method as a "helper" when writing your own methods such as init_with_person(), as described in the example in the overview. init_with_object() should be called in the code for subclasses of Rose::HTML::Form, but never by an end-user of such classes.

The convention for naming such methods is "init_with_foo", where "foo" is a (lowercase, underscore-separated, please) description of the object (or objects) used to initialize the form. You are free to accept and handle any kind or number of arguments in your "init_with_foo()"-style methods (all which you'll carefully document, of course).

The field names may not match up exactly with the object method names. In such cases, you can use init_with_object() to handle all the fields that do match up with method names, and then handle the others manually. Example:

    sub init_with_person 
    {
      my($self, $person) = @_;

      # Handle field names that match method names
      $self->init_with_object($person); 

      # Manually set the non-matching or other fields
      $self->field('phone2')->input_value($person->alt_phone);
      $self->field('is_new')->input_value(1);
      ...
    }
local_field NAME [, VALUE]

Get or set a field that is an immediate child of the current form. That is, it does not belong to a nested form. If the field specified by NAME does not meet these criteria, then undef is returned. In all other respects, this method behaves like the field method.

Note that NAME should be the name as seen from the perspective of the form object upon which this method is called. So a nested form can always address its local fields using their "short" (unqualified) names even if the form is actually nested within another form.

local_form NAME [, OBJECT]

Get or set a form that is an immediate child of the current form. That is, it does not belong to a nested form. If the form specified by NAME does not meet these criteria, then undef is returned. In all other respects, this method behaves like the form method.

Note that NAME should be the name as seen from the perspective of the form object upon which this method is called. So a nested form can always address its local sub-forms using their "short" (unqualified) names even if the parent form itself is actually nested within another form.

name [NAME]

If passed a NAME argument, then the "name" HTML attribute is set to NAME.

If called without any arguments, and if the "name" HTML attribute is empty, then the "name" HTML attribute is set to the form_name.

Returns the value of the "name" HTML attribute.

object_from_form OBJECT | CLASS | PARAMS

Returns an object built based on the contents of the form.

For each field name(), if the object has a method with the same name, then the internal_value() of the field is passed to the object method of that name. The actual code is just about as concise as my description:

  foreach my $field ($self->fields)
  {
    my $name = $field->local_name;

    if($object->can($name))
    {
      $object->$name($field->internal_value);
    }
  }

To do this, the method needs an object. If passed an OBJECT argument, then that's the object that's used. If passed a CLASS name, then a new object is constructed by calling new() on that class. OBJECT or CLASS may alternately be passed as a name/value pair in PARAMS.

Use this method as a "helper" when writing your own methods such as person_from_form(), as described in the example in the overview. object_from_form() should be called in the code for subclasses of Rose::HTML::Form, but never by an end-user of such classes.

The convention for naming such methods is "foo_from_form", where "foo" is a (lowercase, underscore-separated, please) description of the object constructed based on the values in the form's fields.

The field names may not match up exactly with the object method names. In such cases, you can use object_from_form() to handle all the fields that do match up with method names, and then handle the others manually. Example:

  sub person_from_form
  {
    my($self) = shift;

    my $person = $self->object_from_form(class => 'Person');

    $person->alt_phone($self->field('phone2')->internal_value);
    ...
    return $person;
  }

It is the caller's responsibility to ensure that the object class (Person in the example above) is loaded prior to calling this method.

param NAME [, VALUE]

Get or set the value of a named parameter. If just NAME is passed, then the value of the parameter of that name is returned. If VALUE is also passed, then the parameter value is set and then returned.

If a parameter has multiple values, the values are returned as a reference to an array in scalar context, or as a list in list context. Multiple values are set by passing a VALUE that is a reference to an array of scalars.

Failure to pass at least a NAME argument results in a fatal error.

params [PARAMS]

Get or set all parameters at once.

PARAMS can be a reference to a hash or a list of name/value pairs. If a parameter has multiple values, those values should be provided in the form of a reference to an array of scalar values. If the list of name/value pairs has an odd number of items, a fatal error occurs.

If PARAMS is a reference to a hash, then it is accepted as-is. That is, no copying of values is done; the actual hash references is stored. If PARAMS is a list of name/value pairs, then a deep copy is made during assignment.

Regardless of the arguments, this method returns the complete set of parameters in the form of a hash (in list context) or a reference to a hash (in scalar context).

In scalar context, the hash reference returned is a reference to the actual hash used to store parameter names and values in the object. It should be treated as read-only.

The hash returned in list context is a deep copy of the actual hash used to store parameter names and values in the object. It may be treated as read/write.

params_exist

Returns true if any parameters exist, false otherwise.

param_exists NAME

Returns true if a parameter named NAME exists, false otherwise.

params_from_apache APR

Set params by extracting parameter names and values from an apache request object. Calling this method entirely replaces the previous params.

If running under mod_perl 1.x, the APR argument may be:

If running under mod_perl 2.x, the APR may be:

In all cases, APR may be an object that has a param() method that behaves in the following way:

  • When called in list context with no arguments, it returns a list of parameter names.

  • When called in list context with a single parameter name argument, it returns a list of values for that parameter.

params_from_cgi CGI

Set params by extracting parameter names and values from a CGI object. Calling this method entirely replaces the previous params. The CGI argument must be either a CGI object or must have a param() method that behaves in the following way:

  • When called in list context with no arguments, it returns a list of parameter names.

  • When called in list context with a single parameter name argument, it returns a list of values for that parameter.

param_value_exists NAME, VALUE

Determines if a parameter of a particular name exists and has a particular value. This method returns true if the parameter named NAME exists and also has a value that is equal to (string comparison) VALUE. Otherwise, it returns false.

A fatal error occurs unless both NAME and VALUE arguments are passed.

parent_form [FORM]

Get or set the parent form, if any. The reference to the parent form is "weakened" using Scalar::Util::weaken() in order to avoid memory leaks caused by circular references.

query_string

Returns a URI-escaped (but not HTML-escaped) query string that corresponds to the current state of the form. If coalesce_query_string_params() is true (which is the default), then compound fields are represented by a single query parameter. Otherwise, the subfields of each compound field appear as separate query parameters.

rank [INT]

Get or set the form's rank. This value can be used for any purpose that suits you, but by default it's used by the compare_forms() method to sort sub-forms.

reset

Call reset() on each field object and set error() to undef.

reset_fields

Call reset() on each field object.

self_uri

Returns a Rose::URI object corresponding to the current state of the form. If uri_base() is set, then it is included in front of what would otherwise be the start of the URI (i.e., the value of the form's "action" HTML attribute).

start_html

Returns the HTML that will begin the form tag.

start_xhtml

Returns the XHTML that will begin the form tag.

start_multipart_html

Sets the "enctype" HTML attribute to "multipart/form-data", then returns the HTML that will begin the form tag.

start_multipart_xhtml

Sets the "enctype" HTML attribute to "multipart/form-data", then returns the XHTML that will begin the form tag.

uri_base [STRING]

Get or set the URI of the form, minus the value of the "action" HTML attribute. Although the form action can be a relative URI, I suggest that it be an absolute path at the very least, leaving the uri_base() to be the initial part of the full URI returned by self_uri(). Example:

    $form->action('/foo/bar');
    $form->uri_base('http://www.foo.com');

    # http://www.foo.com/foo/bar
    $uri = $form->self_uri;
uri_separator [CHAR]

Get or set the character used to separate parameter name/value pairs in the return value of query_string() (which is in turn used to construct the return value of self_uri()). The default is "&".

validate

Validate the form by calling validate() on each field. If any field returns false from its validate() call, then this method returns false. Otherwise, it returns true.

If this method returns false and an error is not defined, then the error attribute is set to a generic error message.

validate_field_html_attrs [BOOL]

Get or set a boolean flag that indicates whether or not the fields of this form will validate their HTML attributes. If a BOOL argument is passed, then it is passed as the argument to a call to validate_html_attrs() on each field. In either case, the current value of this flag is returned.

xhtml_hidden_fields

Returns the XHTML serialization of the fields returned by hidden_fields(), joined by newlines.

SUPPORT

Any Rose::HTML::Objects questions or problems can be posted to the Rose::HTML::Objects mailing list. To subscribe to the list or view the archives, go here:

http://lists.sourceforge.net/lists/listinfo/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

AUTHOR

John C. Siracusa (siracusa@mindspring.com)

COPYRIGHT

Copyright (c) 2006 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.