The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

HTML::FormFu::Manual::ConfigurationFiles - Building a form from configuration files

VERSION

version 0.002

INTRODUCTION

HTML::FormFu has been designed to work with form definitions stored primarily in configuration files. This may be a feature or a drawback, depending on your preferences. HTML::FormHandler is an alternative module which provides similar functionality, but forms are defined via Moose-based attributes, and constraints are Moose subtypes.

HOW CONFIGURATION INSTRUCTIONS ARE PROCESSED

Hash keys as methods

Before we start looking into actual configuration files, let us examine the way HTML::FormFu processes that data structure that is passed to populate. Let us have a look at the following configuration hash (if the meaning of some of the options is unclear to you don't worry, we will explain them further on in the tutorial):

  my $definition = {
    action       => 'process_form.cgi'
    indicator    => 'submit',
    elements     => [
      {
        type        => 'Text',
        name        => 'user',
        constraints => ['Required'],
      },
      {
        type        => 'Password',
        name        => 'pass',
        constraints => ['Required'],
      }
      {
        type => 'Submit'
        name => 'submit'
      }
    ],
    constraints => ['SingleValue']
  };

  $form->populate($definition);

When we invoke populate on the above definition, what happens is that populate basically calls each key of the hash as a method of the form object. Thus, the following achieves identical results as above (the order of execution will not be the same - populate has its own algorithm to determine which methods to call in what order):

  $form->action('process_form.cgi');
  $form->indicator('submit');
  $form->elements([
    {
      type        => 'Text',
      name        => 'user',
      constraints => ['Required'],
    },
    {
      type        => 'Password',
      name        => 'pass',
      constraints => ['Required'],
    }
    {
      type => 'Submit'
      name => 'submit'
    }
  ]);
  $form->constraints(['SingleValue']);

The same applies to nested hashes as well. For example, when HTML::FormFu creates a form element, it knows first to create an instance of the specified elements, and then to call the respective methods on it. Thus, when you want to create an element with the following definition:

  {
    type        => 'Text',
    name        => 'user',
    constraints => ['Required'],
  }

HTML::FormFu internally does the following:

  my $element = HTML::FormFu::Element::Text->new;
  $element->name('user');
  $element->constraints(['Required']);

Aliases

Note that many methods in HTML::FormFu have aliases in the plural and singular. Thus element does the same as elements, constraint does the same as constraints, etc. Also, these methods may take as their arguments either a hashref with the definition of a single item, or an arrayref of hashrefs with definitions of multiple items. As we will see later this is convenient when creating configuration files in different formats. It also means we can rewrite the element definitions in the above form as follows:

  $form->element({
    type        => 'Text',
    name        => 'user',
    constraints => ['Required'],
  });
  
  $form->element({
    type        => 'Password',
    name        => 'pass',
    constraints => ['Required'],
  });

  $form->element({
    type => 'Submit'
    name => 'submit'
  });

Accessing the element object

The elements method returns a list of element objects. This gives us the opportunity to work directly with it if we wish to. Here is yet another way to configure the elements specified above:

  my ($user_el, $pass_el, $submit_el) = $form->elements([
    {
      type        => 'Text',
      name        => 'user',
    },
    {
      type        => 'Password',
      name        => 'pass',
    },
    {
      type => 'Submit'
      name => 'submit'
    },
  ]);

  $user_el->constraints(['Required']);
  $pass_el->constraints(['Required']);

We can also use the get_element method of the form object to get hold of an element object:

  $form->element({
    type        => 'Text',
    name        => 'user',
  });

  my $user_el = $form->get_element({ name => 'user' });
  $user_el->constraints(['Required']);

See "INTROSPECTION" in HTML::FormFu for a list of all methods available for fetching individual objects from the form (including constraints, filters, etc.). You can then further modify these element objects by directly invoking methods on them (see the docs for each element for its interface).

Other methods to modify the form

And finally, HTML::FormFu provides several methods to manipulate the form directly: insert_before, insert_after and remove_element. These methods allow you to perform additional processing on a form after it has been populated from a configuration file:

  my $definition = {
    elements     => [
      {
        type        => 'Text',
        name        => 'user',
        constraints => ['Required'],
      },
      {
        type        => 'Password',
        name        => 'pass',
        constraints => ['Required'],
      },
      {
        type => 'Checkbox',
        name => 'remember_me',
      }
      {
        type => 'Reset',
        name => 'reset',
      }
    ],
  };

  $form->populate($definition);

  # remove the "remember me" option
  my $reset_el = $form->get_element({ name => 'remember_me' });
  $form->remove_element($reset_el);

  # create a submit button and put it at the end of the form,
  # i.e. after the reset button
  my $submit_el = $form->element({ type => 'Submit', name => 'submit' });
  
  # move the submit button before the reset button
  my $reset_el = $form->get_element({ name => 'reset' });
  $form->insert_before($submit_el, $reset_el);

USING CONFIGURATION FILES

So far we have only used hashrefs to define our forms. Normally, your form definitions will be stored in configuration files that you will parse into a hashref and pass to populate. HTML::FormFu provides a convenient method for this, load_config_file. It takes care of loading a configuration file in any of the formats supported by Config::Any and populating the form from it. For example:

  # in login_form.yaml

  ---
  action: /login
  indicator: submit

  elements:
    - type: Text
      name: user
      constraints:
        - Required

    - type: Password
      name: pass
      constraints:
        - Required

    - type: Submit
      name: submit

  constraints:
    - SingleValue

  # in your code
  
  my $form = HTML::FormFu->new;
  $form->load_config_file('login_form.yaml');

Most of the examples in the HTML::FormFu documentation and test suite are in the YAML, but it is not difficult to translate them to other formats. If we are using Config::General format the form will look like that (it is more appropriate to use element instead of elements here):

  # in login_form.conf

  action /login
  indicator submit

  <element>
    type Text
    name user
    constraints [Required]
  </element>

 <element> 
    type Password
    name pass
    constraints [Required]
  </element>

 <element> 
    type Submit
    name submit
 </element> 

  constraints [SingleValue]

  # in your code
  
  my $form = HTML::FormFu->new;
  $form->load_config_file('login_form.conf');

PREPROCESSING CONFIGURATION FILES

Earlier we saw that by using methods such as insert_before, insert_after and remove_element we can manipulate the form object after it has been initially populated (from a configuration file or otherwise). Another way to modify the form definition stored in file is to preprocess the file before it is passed to populate.

  # in login_form.yaml

  ---
  elements:
    - type: Text
      name: user
 
    - type: Password
      name: pass

    - type: Submit
      name: submit

  # in your code

  # add a 'Required' constraint to the 'user' and 'pass' elements
  $form->config_callback({
    hash => sub {
        if ( defined $_->{name} and $_->{name} =~ /^user|pass$/ ) {
            $_->{constraints} = ['Required'];
        }
    }
  });

  $form->load_config_file('login_form.yaml');

The argument to config_callback is a hashref in a format compliant with "CALLBACKS" in Data::Visitor::Callback. The keys are the type of data that you want to process, and the value is the coderef that will be executed. Inside the coderef, the $_ variable will be set to the data that is currently being processed.

AVAILABLE CONFIGURATION OPTIONS

This is an overview of places to look for documentation on the options you can use in your configuration file.

HTML::FormFu

HTML::FormFu is the base form class. As a general rule, any method that HTML::FormFu provides can be used as a key in your configuration hash. Below is a list of the main types of methods that you can invoke via a configuration file. We are not providing detailed documentation for the individual methods here, please consult the respective module for details:

Attributes of the form element

The HTML::FormFu class roughly corresponds to the html <form> tag of that form. Therefore, like all other elements in the HTML::FormFu, it has an attributes method that you can use to set custom attributes of the <form> tag. There are special methods for some of the more important form attributes, namely id, action, enctype and method.

Other options that apply to the form as a whole

A number of other methods configure various aspects of the form behavior and output, but are not related to the html <form> tag, e.g. indicator, auto_fieldset, and javascript.

Form elements

The element and elements methods, as we saw above, are the means to add elements to the form.

Default validation options

The base HTML::FormFu class also supports all methods to create filters, constraints, inflators and validators, which individual element classes have as well. These make no sense in the context of the main form object, but you can associate them with individual form elements via the names option, or with all form elements when no list of names is specified. This is useful when you want to set default validation rules for multiple elements at once.

Default attributes

In a somewhat similar vein, default_args is an option to supply default values to any type of element, constraint, etc.

Configuration options

All the methods related to the loading of configuration files, as well as the stash, are available in the base HTML::FormFu class and in all other elements and validators. This allows you to load a configuration file from within a configuration file, or to load the contents of specific sub-section of the form from a separate configuration file. These methods are load_config_file, config_callback, config_file_path, and stash.

The model and model_config options are available to both HTML::FormFu and to all elements. The actual description of arguments that model_config takes depend on the model used, and are to be found in the documentation of the specific model class (e.g. HTML::FormFu::Model::DBIC).

Methods that make no sense in a configuration file

Some of the methods in HTML::FormFu make no sense in a configuration file, since they require something to be done with their return value. These are for example methods that introspect the state of the form (submitted, valid, param), methods that introspect the structure of the form (get_element, get_filter, the constructor (new), etc.

This is not meant to be a comprehensive listing of all methods available in HTML::FormFu, please refer to the docs for complete information.

Element classes

When configuring an individual element, the main place to look for configuration options is, of course, the documentation for that element class. But besides that various properties may be documented in the parent classes of that element. For example, let us say that you want to use a combo box field. The inheritance hierarchy of HTML::FormFu::Element::ComboBox is as follows:

  +---------------------------------+
  | HTML::FormFu::Element::ComboBox |
  +---------------------------------+
                   |
                   V
  +---------------------------------+
  |  HTML::FormFu::Element::Multi   |
  +---------------------------------+
                   |
                   V
  +---------------------------------+
  |  HTML::FormFu::Element::_Field  |
  +---------------------------------+
                   |
                   V
  +---------------------------------+
  |      HTML::FormFu::Element      |
  +---------------------------------+

This means that for a complete list of options for a combo box you will have to consult the docs for each of these classes. This can indeed be daunting at the start, but you will soon find that most elements share a large number of common attributes, and most of the differences are documented in the top level element classes. You will normally find information about the parents of each class in the beginning of its documentation.

A similar logic applies to the documentation for the various types of classes involved in the validation process. For example, the docs for HTML::FormFu::Constraint::Bool state that it inherits from HTML::FormFu::Constraint::Regex and HTML::FormFu::Constraint, which are the other two classes whose documentation you should consult.

Model options

And last but not least, a lot of important options pertaining to the specific model class you are using will be found in the docs for that class, specifically the options that can be passed to model_config for the individual form elements.

AUTHOR

Peter Shangov <pshangov@yahoo.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by Peter Shangov.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.