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

NAME

HTML::FormFu::Manual::Stages - Stages in form processing

VERSION

version 0.002

INTRODUCTION

To really be able to use all the power that HTML::FormFu provides one must understand how it approaches form processing. Modules such as Catalyst::Controller::HTML::FormFu hide the complexity of HTML::FormFu's workflow, but also make it difficult to figure out what happens in the background.

FORM PROCESSING STAGES

Create

First, we have to create a form object:

  use HTML::FormFu;
  my $form = HTML::FormFu->new;

This creates a new form object. Note that initially this is a pretty useless form object - it has no form elements, no validation rules, nothing. Basically, we start from zero and will be making our object more powerful as we build our form.

Populate

Once we have an empty form object to work on, we need to tell it about the form we want to create. We need to tell it about the fields we want our form to have, and what validation rules to attach to each field. Let us say that we want to create a form with a single input field and a submit button, and we want the input field to be mandatory. The final markup will look like that:

  <form>
    <input type="text" name="greeting" />
    <input type="submit" />
  </form>

Our form object will need to consist of a HTML::FormFu::Element::Text object, with a HTML::FormFu::Constraint::Required attached, and a HTML::FormFu::Element::Submit object. But HTML::FormFu does not expect us to create these object by hand. Instead, we pass to the form object a hashref that contains information about the form definition, and HTML::FormFu takes care of inflating this definition into the proper objects. Thus, for the above form, a configuration hashref might look like this:

  my $definition = {
    elements => [
      {
        type => 'Text',
        name => 'greeting',
        constraints => [ 'Required' ],
      },
      {
        type => 'Submit',
        name => 'submit'
        value => 'Submit my greeting!',
      },
    ]
  };

We will look in more detail into the structure of the configuration hash in the next chapter, but even now you can see how this hash maps to the definition of the form we want to create. In order to feed it to our form, we can do the following:

  $form->populate($definition);

Now our form object is loaded with information about the form we want to work with. Internally, it has converted the data structure we passed it into a list of HTML::FormFu::* objects that are now ready to work with actual data.

Load

Supplying default values

Once we have our form definition in place, we can start loading data into it. There are several ways we can do that. If we are displaying the form to the user for the first time, we may want to load some default values into it. This is how we do that:

  $form->default_values( { greeting => 'Hello world!' } );

Now when we display the form to the user, she will see the string Hello world! in the input field, and she may change it it she wants to. The "default_values" in HTML::FormFu method of our form object takes as a parameter a single hashref whose keys are the names of form fields we want to supply default values for.

You will often want to use this functionality when you create forms to edit existing database data. You normally want to get the field values from the database record, supply them as default values to the form, and let the user edit them. Imagine that the form below was use to edit greeting messages stored in a database. Your greetings table is very simple, with only two columns: a greeting id and the greeting text. Assuming that you have a DBIx::Class schema for that database, you may do something like this to supply default values for your form:

  # table 'greeting' has two colums: 'id' and 'greeting'
  my $result = $schema->resultset('Greeting')->find({ id => 1 });
  $form->model->default_values($result);

Here we use the default_values method of the model associated by the form, because potentially the result object can be a very complex data structure, and the model's "default_values" in HTML::FormFu::Model::DBIC method takes care of flattening this data structure to a simple hashref appropriate for the basic "default_values" in HTML::FormFu method. You will learn how to use models later in Chapter V: HTML::FormFu::Manual::Models.

Processing query parameters

If a form has already been submitted, we want to supply to it the values entered by the user. This is done by using the "query" in HTML::FormFu method.

  my $submitted_values = {
    greeting => 'Howdy!',
  };

  $from->query($submitted_values);

The "query" in HTML::FormFu method can be passed either a hashref of keys and values, a CGI-compatible query object, or a Catalyst-compatible query object. See the docs for HTML::FormFu::QueryType::* for more details.

Note also that to HTML::FormFu it doesn't matter if you invoke query or default_values before populate or vice versa. These two methods simply load data into the form object, but they do nothing with it until the process stage (see below), so it doesn't really matter if you have loaded data before you have supplied the form definition.

Process

The process stage is where HTML::FormFu compares the supplied form data with the form definition, performs any necessary validation and generates errors if the data is not OK. You process the form simply by invoking the process method:

  $form->process;

Now you can check if the form generated any errors:

  if ( $form->has_errors )  {
    my @errors = $form->get_errors;
  }

If there were validation errors, @errors will contain a list of HTML::FormFu::Exception objects that you can query about the details for each error. HTML::FormFu also provides a submitted method that you can use to tell if the form was actually submitted or not (see "indicator" in HTML::FormFu for details). And submitted_and_valid is a shortcut for $form->submitted and !$form->has_errors. Thus, it is a common idiom to write something like that:

  if ( $form->submitted_and_valid ) {
    # do something with the values
  } else {
    # display the form
  }

Render

After we have processed a form, we can invoke the render method on it to obtain its current representation as html.

  my $html = $form->render;

Thus, if the form has not been submitted and has not been supplied default values, the resulting html will look simply like this:

  <form>
    <input type="text" name="greeting" />
    <input type="submit" name="submit" value="Submit my greeting!" />
  </form>

If, on the other hand, we have supplied a default value of Hello world! for greeting, the html will reflect it:

  <form>
    <input type="text" name="greeting" value="Hello, world!" />
    <input type="submit" name="submit" value="Submit my greeting!" />
  </form>

If the form has been submitted but the greeting field is blank, thus violating the Required constraint, an error message will be added:

  <form action="" method="post">
    <div class="text error error_constraint_required">
      <span class="error_message error_constraint_required">This field is required</span>
      <input name="greeting" type="text" />
    </div>
    <div class="submit">
      <input name="submit" type="submit" value="Submit my greeting!" />
    </div>
  </form>

If the form has been submitted and valid there will be no need to display it again to the user. If you call render on a validly submitted form it will display the same code as if the query values were passed as default_values to the form.

Update

The update stage exists only if you are using a model with HTML::FormFu. In a way it is an alternative to the render stage - this is what you will normally call if the form has been submitted and is valid. Note that update is a method of the model class:

  # this updates record with id = 1 from the database 
  # with the values from the submitted form
  my $result = $schema->resultset('Greeting')->find({ id => 1 });
  $form->model->update($result);

SUMMARY

This is a simple flowchart that summarizes HTML::FormFu's workflow:

             +----------------+
             |     create     |
             +----------------+
                      |
             +----------------+
             |    populate    |
             +----------------+
                      |
  +----------------+     +----------------+ 
  | default_values | OR  |     query      | 
  +----------------+     +----------------+ 
                      |
             +----------------+  
             |    process     |  
             +----------------+  
                      |
  +----------------+     +----------------+ 
  |     render     | OR  |     update     | 
  +----------------+     +----------------+ 

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.