
__END__
=pod

=head1 NAME

HTML::FormFu::Manual::Models - Interaction with data stores via models

=head1 VERSION

version 0.001

=for stopwords shangov
resultsource
resultset
checkbox
datastore
hashrefs
javascript

=head1 INTRODUCTION

One of the most powerful features of L<HTML::FormFu> is its ability to integrate with various data models and automatically perform operations with the form values, e.g. updating the corresponding database fields. In this chapter we will dissect how L<HTML::FormFu> models work and how you can use them to dramatically reduce the development time for you applications.

=head1 AVAILABLE MODELS

Currently there are two models available for use with L<HTML::FormFu>: L<HTML::FormFu::Model::HashRef>, which ships with the core L<HTML::FormFu> distribution, and L<HTML::FormFu::Model::DBIC>, which is a package which you need to install separately. L<HTML::FormFu::Model::HashRef> allows you to fill in forms from a hashref, or convert form values to a hashref. It can be useful if you are interacting with a datastore that is not supported by L<HTML::FormFu> but can process data stored in hashrefs. L<HTML::FormFu::Model::DBIC> is a much more complicated module which links L<HTML::FormFu> with the powerful L<DBIx::Class> library.

=head1 WORKING WITH MODELS - THE BASICS

Every L<HTML::FormFu> object with a properly configured model has a C<model> method which returns the underlying model object. You can access the functionality that the model provides by invoking methods on that model object. Additionally, you can pass configuration options to the model object by invoking the L<model_config|HTML::FormFu::Element/"model_config"> method of individual form elements.

Let us look first at the functionality of the model object. It has two very important methods: 

=over

=item default_values

This method is similar to the L<default_values|HTML::FormFu/"default_values"> method of the base L<HTML::FormFu> class, but while the C<$form-E<gt>default_values> accepts as its argument a simple hash of field names and their respective values, C<$form-E<gt>model-E<gt>default_values> allows us to fill in a form with default values from arguments that are specific to every model class. For example, L<HTML::FormFu::Model::HashRef> fills in default values from a hashref, while L<HTML::FormFu::Model::DBIC> fills in default values from a C<DBIx::Class::Row> object. Internally, each model class converts the values of its argument into a simple hash and passes its values to L<default_values|HTML::FormFu/"default_values"> in L<HTML::FormFu>.

=item update

The L<update|HTML::FormFu::Model::DBIC/"update"> method updates a foreign object specific to the model class with the values from the submitted form. With L<HTML::FormFu::Model::HashRef> it will create a hashref with the values from the form. With L<HTML::FormFu::Model::DBIC> it will take as an argument to update a C<DBIx::Class::Row> object, and its values in the database will be updated with the ones submitted from the form. Here is an example of how to use L<update|HTML::FormFu::Model::DBIC/"update"> in conjunction with L<default_values|HTML::FormFu::Model::DBIC/"default_values">: 

  # fetch a record from the database
  my $record = $dbic_resultset->find({ id => 5 });

  # load the data from the record into the form
  $form->model->default_values($record);

  # later on in the script ....
  if ($form->submitted_and_valid)
  {
    # take the submitted values, update the record object
    # and save to database
    $form->model->update($record);
  }

=back

=head1 USING HTML::FormFu::Model::DBIC

The rest of this chapter will focus exclusively on L<HTML::FormFu::Model::DBIC>, since this is the  more complex module and the one that you are most likely to need in your applications.

=head2 Loading and configuring the model class

Use the L<model|HTML::FormFu/"model"> method of the L<HTML::FormFu> object to specify which model class you want to load:

  # loads HTML::FormFu::Model::DBIC
  $form->model('DBIC');

Normally your form will work with a particular L<DBIx::Class> schema. You specify the name of that schema by putting a C<schema> entry in the form's stash:

  my $schema = My::Schema::Class->connect( ... );
  $form->stash( schema => $schema );

If you are working with Catalyst, you can just supply the name of a Catalyst model instead:

  $form->stash( schema => 'Model::My::Schema::Class' );

Although a form is in practice associated with a particular L<DBIx::Class::ResultSource>, you do not normally have to specify which class that is. Instead, you pass an object of that class as the argument to L<default_values|HTML::FormFu::Model::DBIC/"default_values"> or L<update|HTML::FormFu::Model::DBIC/"update">. L<HTML::FormFu> will work happily as long as you have given it an object which has columns and relationships corresponding to the ones you have specified in the form definition.

Most of the model configuration happens via the L<model_config|HTML::FormFu/"model_config"> method of individual form elements. We will describe some of the most important options below.

=head2 Populating select fields

Before we move on to displaying and updating data from the database, we will discuss a very important topic - loading options for select fields from the database.

We have a C<Books> schema for a database containing information about books. One of the tables in the database - C<genre>, contains a list of genres that can be associated with books. Here is the result class for the C<genre> table:

  ### Books/Result/Genre.pm ###

  package Books::Result::Genre;

  use DBIx::Class::Candy;
  
  table 'genre';
  
  column 'id' => {
    data_type         => 'int',
    is_auto_increment => 1,
  };
    
  column 'name' => {
    data_type => 'varchar',
    size      => 256,
  };
  
  primary_key 'id';

  1;

And here is the list of predefined genres that the C<genre> table contains:

  id  name
  --  -----------------
  1   Children's
  2   Fantasy
  3   Horror
  4   Mystery
  5   Romance
  6   Science Fiction
  7   Short Fiction
  8   Thriller/Suspense

When creating or editing a book record, we want to be able to choose from that list of genres. Normally we would do that by using either a select field or a group of radio buttons. We will create a script that builds that form and prints it out to STDOUT:

  use strict;
  use warnings;

  use HTML::FormFu;
  use Books;
  
  my $form = HTML::FormFu->new;
  
  # load configuration file
  $form->load_config_file("books.conf");
  
  # setup model and schema
  $form->model('DBIC');
  my $schema = Books->connect( ... );
  $form->stash( schema => $schema );

  $form->process;
  
  print $form->render;

We will start with the following configuration file (named C<books.conf>, in L<Config::General> format):

  <element>
    name name
    type Text
  </element>
  
  <element>
    name genre
    type Select
  </element>
  
  <element>
    type Submit
  </element>

Nothing surprising here, here is the output that we get when we render the form:

  <form action="" method="post">
    <div class="text">
      <input name="name" type="text" />
    </div>
    <div class="select">
      <select name="genre">
      </select>
    </div>
    <div class="button">
      <input type="submit" />
    </div>
  </form>

But if we change the definition of the C<genre> field as follows:

  <element>
    name genre
    type Select
    <model_config>
      resultset Genre
    </model_config>
  </element>

we get all the options for the select field populated from the database:

  <form action="" method="post">
    <div class="text">
      <input name="name" type="text" />
    </div>
    <div class="select">
      <select name="genre">
        <option value="1">Children&#39;s</option>
        <option value="2">Fantasy</option>
        <option value="3">Horror</option>
        <option value="4">Mystery</option>
        <option value="5">Romance</option>
        <option value="6">Science Fiction</option>
        <option value="7">Short Fiction</option>
        <option value="8">Thriller/Suspense</option>
      </select>
    </div>
    <div class="button">
      <input type="submit" />
    </div>
  </form>

What happened here? As we said earlier, all options specific to the particular model we are using are specified in a C<model_config> hashref. In order for L<HTML::FormFu::Model::DBIC> to populate our select fields, several conditions need to be in place:

=over

=item *

The form element must inherit from L<HTML::FormFu::Element::_Group>, i.e. one of L<HTML::FormFu::Element::ComboBox>, L<HTML::FormFu::Element::Radiogroup>, L<HTML::FormFu::Element::Checkboxgroup> or L<HTML::FormFu::Element::Select>.

=item * 

The C<resultset> option must be passed to L<model_config|HTML::FormFu/"model_config">, so that L<HTML::FormFu::Model::DBIC> knows which result class to use to fetch the values. If C<resultset> does not contain any column (C<:>) characters, it will be expanded into a result class belonging to the loaded schema (i.e. C<Genre> will become C<Books::Result::Genre>). Otherwise it will be used as is.

If no resultset is specified, but L<model_config|HTML::FormFu/"model_config"> is present, L<HTML::FormFu::Model::DBIC> will attempt to guess the result class from the name of the element. So, the following two element definitions are equivalent:

  <element>
    name something
    type Select
    <model_config />
  </element>

  # is the same as:

  <element>
    name something
    type Select
    <model_config>
      resultset Something
    </model_config>
  </element>

=item *

And last, we may need to specify which column to use as the value for each option, and which column to use as the label. By default L<HTML::FormFu::Model::DBIC> uses the column holding the primary key as the value, and the first text column in the table as the label. You can override this behaviour with the C<id_column> and C<label_column> options respectively. The following definition of the select element achieves the same result as above, but is explicit about which columns to use for option values and labels:

  <element>
    name genre
    type Select
    <model_config>
      resultset Genre
      id_column id
      label_column name
    </model_config>
  </element>

=back

Let us say that at some point later a new requirement comes up that you must add non-fiction genres to the database, and you must be able to distinguish them from the fiction genres. We will add a boolean column to specify whether a genre is fiction or not. The new C<genre> table will look like that:

  id  name                     fiction
  --  -----------------------  -------
  1   Children's               1
  2   Fantasy                  1
  3   Horror                   1
  4   Mystery                  1
  5   Romance                  1
  6   Science Fiction          1
  7   Short Fiction            1
  8   Thriller/Suspense        1
  9   Essay                    0
  10  Journal                  0
  11  History                  0
  12  Scientific Paper         0
  13  Biography                0
  14  Textbook                 0
  15  Travel Book              0
  16  Technical Documentation  0

And of course we add the new column in our C<Books::Result::Genre> class as well:

  package Books::Result::Genre

  ...

  column 'fiction' => {
    data_type => 'int',
    size      => 1,
  };

  ...

Now if we are required to create a form for editing non-fiction books, we may request that our select field be populated with only a subset of the rows in the C<genre> table. We change the definition of the select element as follows:

  <element>
    name genre
    type Select
    <model_config>
      resultset Genre
      <condition>
        fiction 0
      </condition>
    </model_config>
  </element>

This will produce the following form:

  <form action="" method="post">
    <div class="text">
      <input name="name" type="text" />
    </div>
    <div class="select">
      <select name="genre">
        <option value="9">Essay</option>
        <option value="10">Journal</option>
        <option value="11">History</option>
        <option value="12">Scientific Paper</option>
        <option value="13">Biography</option>
        <option value="14">Textbook</option>
        <option value="15">Travel Book</option>
        <option value="16">Technical Documentation</option>
      </select>
    </div>
    <div class="button">
      <input type="submit" />
    </div>
  </form>

L<HTML::FormFu::Model::DBIC> has two complementary options that affect how rows are selected: C<condition> and C<attributes>. They are passed as the first and second argument to L<DBIx::Class::ResultSet::search> respectively. That is, if you have the following L<model_config|HTML::FormFu/"model_config"> specification for an element:

  <model_config>
    resultset SomeResultSource
    <condition>
      ...
    </condition>
    <attributes>
      ...
    </attributes>
  </model_config>

Assuming that the above definition is parsed into a C<$model_config> hashref, L<HTML::FormFu::Model::DBIC> will internally do something like this to fetch the rows containing the requested options:

  $schema->resultset( $model_config->resultset )->search( 
    $model_config->condition, 
    $model_config->attributes,
  );

=head2 Displaying and updating table fields

Now let us look at the most important part of working with models - automatically retrieving, displaying and updating data from the data store. The key link between fields in the database and fields in the form is the L<name|HTML::FormFu::Element/"name"> attribute. Let us start with a simple book table. Here is the definition of the L<ResultSource|DBIx::Class::ResultSource> class:

  ### Books/Result/Book.pm ###

  package Books::Result::Book;
  
  use DBIx::Class::Candy;
  
  table 'book';

  column 'id' => {
    data_type         => 'int',
    is_auto_increment => 1,
  };

  column 'title' => {
    data_type => 'varchar',
    size      => 1000,
  };

  column 'author' => {
    data_type => 'varchar',
    size      => 1000,
  };

  primary_key 'id';

  1;

The configuration file for a form to edit a book record may look like this:

  <element>
    name title
    type Text
    label "Title"
  </element>
  
  <element>
    name author
    type Text
    label "Author"
  </element>

  <element>
    type Submit
  </element>

Now if we display the form and the user enters some values, we would need to do something like that to enter a new record in the database:

  ...
  if ($form->submitted_and_valid) {
    my $result = $schema->resultset('Book')->new_result({});
    $form->model->update($result);
  }

This creates a new empty record, and passes it to L<update|HTML::FormFu::Model::DBIC/"update">, which takes care of updating the record with the submitted values and saving it into the database. Here is how to go about editing an existing record:

  my $result = $schema->resultset('Book')->find({ id => $id });
  $form->model->default_values($result);

The form will be displayed with data from that record filled-in. After the form is submitted, updating the result object is as simple as:

  if ($form->submitted_and_valid) {
    $form->model->update($result);
  }

=head2 Displaying and updating fields from related tables

So far so good, but things become more complicated when a result object involves relationships between different tables. Let us expand on the topic of loading options from the database, and add updating to the mix. We will update our C<Books::Result::Book> class as follows, and the C<Books::Result::Genre> class will be identical to the one we used above:

  ### Books/Result/Book.pm ###

  package Books::Result::Book;
  
  use DBIx::Class::Candy;
    
  table 'book';

  column 'id' => {
    data_type => 'int',
    is_auto_increment => 1,
  };

  column 'title' => {
    data_type => 'varchar',
    size      => 1000,
  };

  column 'genre_id' => {
    data_type      => 'int',
    is_foreign_key => 1,
  };

  primary_key 'id';

  belongs_to 'genre' => ( 'Books::Result::Genre', 'genre_id' );

  1;

We will add a select field to our form definition to select a genre.

  ...
  <element>
    name genre
    type Select
    label Genre
    <model_config>
      resultset Genre
    </model_config>
  </element>
  ...

You can use either C<genre>, or C<genre_id> as field name here. In the former case C<HTML::FormFu> will figure out that you want to update the C<genre> relationship and will know that it can do that by setting C<genre_id> in the C<book> table to the desired id. In the latter case it will just update C<genre_id> directly - in both cases the result will be the same. It is generally cleaner to use the name of the relationship as the L<name|HTML::FormFu::Element/"name"> attribute. For this to work, of course, we will have to use a form element that is based on L<HTML::FormFu::Element::_Group> and allows setting of a single option only, i.e. L<HTML::FormFu::Element::Radiogroup> or L<HTML::FormFu::Element::Select> without the multiple attribute.

This becomes even more clear if we consider L<many_to_many|DBIx::Class::Relationship/"many_to_many"> relationships. Let us say that some time after we have implemented our database, a new requirement comes up that more than one genre may be specified for each book. To achieve that, we will need to add an intermediary table to keep track of the links between books and genres. We will have the following three result source classes:

  ### Books/Result/Book.pm ###

  package Books::Result::Book;
  
  use DBIx::Class::Candy;
  
  table 'book';

  column 'id' => {
    data_type => 'int',
    is_auto_increment => 1,
  };

  column 'title' => {
    data_type => 'varchar',
    size      => 1000,
  };

  primary_key 'id';

  has_many 'book_genres' => ( 'Books::Result::BookGenre', 'book_id' );
  many_to_many 'genres' => ( 'book_genres', 'genre' );

  1;
  

  ### Books/Result/Genre.pm ###

  package Books::Result::Genre;

  use DBIx::Class::Candy;
  
  table 'genre';
  
  column 'id' => {
    data_type         => 'int',
    is_auto_increment => 1,
  };
  
  column 'name' => {
    data_type => 'varchar',
    size      => 256,
  };
  
  column 'fiction' => {
    data_type => 'boolean',
  };

  primary_key 'id';
  
  has_many 'book_genres' => ( 'Books::Result::BookGenre', 'genre_id' );
  many_to_many 'books' => ( 'book_genres', 'book' );

  1;


  ### Books/Result/BookGenre.pm ###

  package Books::Result::BookGenre;

  use DBIx::Class::Candy;
  
  table 'book_genre';
  
  column 'book_id' => {
    data_type      => 'int',
    is_foreign_key => 1,
  };
  
  column 'genre_id' => {
    data_type      => 'int',
    is_foreign_key => 1,
  };
  
  primary_key 'book_id', 'genre_id';
  
  belongs_to 'book' => ( 'Books::Result::Book', 'book_id' );
  belongs_to 'genre' => ( 'Books::Result::Genre', 'genre_id' );

  1;

The only thing we need to do to make the new relationship work is to change the type of the form element to one that can accept multiple values (i.e. L<HTML::FormFu::Element::Checkboxgroup> or L<HTML::FormFu::Element::Select> with the multiple attribute set):

  ...
  <element>
    name genre
    type Select
    label Genre
    <attributes>
      multiple 1
    </attributes>
    <model_config>
      resultset Genre
    </model_config>
  </element>
  ...

Now updating the result object will correctly set C<genre_id> and C<book_id> in table C<book_genre>.

=head2 Directly editing fields in related tables

In the above examples we used lists of predefined options to set data related to other tables. Sometimes, however, we need to be able to edit directly data that is in a different table. The way this works in L<HTML::FormFu::Model::DBIC> is again very straightforward - to edit fields from a different table, you need to place those fields in a L<block|HTML::FormFu::Element::Block> which has a L<nested_name|HTML::FormFu::Element::Block/"nested_name"> property that corresponds to the respective relationship name. L<HTML::FormFu::Model::DBIC> will recognize that these fields belong to the related table and will update them accordingly.

Let us look at some examples now. Imagine that we have an C<author> table in our database with information about books, and we have a separate table C<address> that holds the address of each author. Our schema classes will look like this:

  ### Books/Result/Author.pm ###

  package Books::Result::Author;
  
  use DBIx::Class::Candy;
  
  table 'author';

  column 'id' => {
    data_type => 'int',
    is_auto_increment => 1,
  };
  
  column 'name' => {
    data_type => 'varchar',
    size      => 256,
  };

  column 'address_id' => {
    data_type      => 'int',
    is_foreign_key => 1,
    is_nullable    => 1, 
  };

  primary_key 'id';
  
  belongs_to 'address' => ( 'Books::Result::Address', 'address_id' );

  1;


  ### Books/Result/Address.pm ###

  package Books::Result::Address;
  
  use DBIx::Class::Candy;
  
  table 'address';

  column 'id' => {
    data_type         => 'int',
    is_auto_increment => 1,
  };
  
  column 'address' => {
    data_type   => 'text',
  };

  primary_key 'id';

  has_one 'author' => ( 'Books::Result::Author', 'address_id' );

 1;

When displaying the form to edit an author, we want to be able to edit the author's address too. Here is what our configuration file should look like:

  <element>
    name name
    type Text
    label Name
  </element>
  
  <element>
    type Block
    nested_name address

    <element>
      name address
      type Textarea
      label Address
    </element>

  </element>

  <element>
    type Submit
  </element>

When you use L<nested_name|HTML::FormFu::Element::Block/"nested_name"> on a block, the value of L<nested_name|HTML::FormFu::Element::Block/"nested_name"> will be prepended to the name of each field within that block. This allows L<HTML::FormFu::Model::DBIC> to identify the fields that belong to foreign tables and update them accordingly. The above form will be rendered as follows:

  <form action="" method="post">
    <div class="text label">
      <label>Name</label>
      <input name="name" type="text" />
    </div>
    <div>
      <div class="textarea label">
        <label>Address</label>
        <textarea name="address.address" cols="40" rows="20"></textarea>
      </div>
    </div>
    <div class="submit">
      <input type="submit" />
    </div>
  </form>

The last and most complicated example that we will look into involves L<has_many|DBIx::Class::Relationship/"has_many"> relationships, where we need to work with multiple rows from the related table at once. If we elaborate on the above scenario, imagine that we must modify our database to allow multiple addresses to be specified for each author. The new classes will have the following structure:

  ### Books/Result/Author.pm ###

  package Books::Result::Author;
  
  use DBIx::Class::Candy;
  
  table 'author';

  column 'id' => {
    data_type => 'int',
    is_auto_increment => 1,
  };
  
  column 'name' => {
    data_type => 'varchar',
    size      => 256,
  };

  primary_key 'id';

  has_many 'addresses' => ( 'Books::Result::Address', 'author_id' );

  1;


  ### Books/Result/Address.pm ###

  package Books::Result::Address;
  
  use DBIx::Class::Candy;
  
  table 'address';

  column 'id' => {
    data_type         => 'int',
    is_auto_increment => 1,
  };
  
  column 'address' => {
    data_type   => 'text',
  };

  column 'author_id' => {
    data_type      => 'int',
    is_foreign_key => 1,
  };

  primary_key 'id';

  belongs_to 'author' => ( 'Books::Result::Author', 'author_id' );

  1;

The following is required in order to get this to work:

=over

=item * 

All the fields from the related table must be within a L<HTML::FormFu::Element::Repeatable> block.

=item * 

As above, the L<nested_name|HTML::FormFu::Element::Repeatable/"nested_name"> option of the L<Repeatable|HTML::FormFu::Element::Repeatable> block must be set to the name of the respective relationship (C<addresses> in our case).

=item *

When you list the fields from the related table in the L<Repeatable|HTML::FormFu::Element::Repeatable> block you must include that table's primary key as a Hidden field. Since we are working with multiple rows this is necessary to identify rows by id when updating the form.

=item * 

The L<Repeatable|HTML::FormFu::Element::Repeatable> block's L<increment_field_names|HTML::FormFu::Element::Repeatable/"increment_field_names"> must be set to true (it is true by default). We will look into the effects of this option shortly.

=item *

And last but not least, you must include a Hidden field specifying the number of rows from the related table that the form will contain, i.e. how many times the Repeatable block will be repeated. This field must be placed outside the Repeatable block, and be referenced from within the Repeatable block via the L<counter_name|HTML::FormFu::Element::Repeatable/"counter_name"> option. For more information, check the documentation on L<HTML::FormFu::Element::Repeatable>.

=back

Here is an example configuration file for the new form:

  <element>
    name name
    type Text
    label Name
  </element>
  
  <element>
    name address_counter
    type Hidden
  </element>

  <element>
    type Repeatable
    nested_name addresses
    counter_name address_counter

    <element>
      name id
      type Hidden
    </element>

    <element>
      name address
      type Textarea
      label Address
    </element>

  </element>

  <element>
    type Submit
  </element>

This is how this form will render:

  <form method="post" action="">
    <div class="text label">
      <label>Name:</label>
      <input type="text" name="name">
    </div>
    <input type="hidden" name="address_counter">
    <div>
      <input type="hidden" name="addresses_1.id">
      <div class="textarea label">
        <label>Address:</label>
        <textarea rows="20" cols="40" name="addresses_1.address"></textarea>
      </div>
    </div>
    <div class="submit">
      <input type="submit">
    </div>
  </form>

Notice how the use of the L<increment_field_names|HTML::FormFu::Element::Repeatable/"increment_field_names"> option makes each field from the related table numbered:

  name="addresses_1.address"

This means that this is the C<address> field from the first row from the table corresponding to the C<addresses> relationship. This C<address> field belongs to the row whose primary key is the value of the C<addresses_1.id> field - currently none since this is an empty form to create a new author. If we have a form with more than one addresses the subsequent fields will be named C<addresses_2.address>, C<addresses_3.address>, etc.

If you want to add to the C<has_many> relationship (i.e. add a new address row for this author), you can use the C<empty_rows> option of the C<model_config> section of the L<Repeatable|HTML::FormFu::Element::Repeatable> block to display the form with the specified number of additional empty rows at the end of the block. Alternatively you can use javascript to add dynamically a new element, e.g. by copying the last element in the L<Repeatable|HTML::FormFu::Element::Repeatable> block and incrementing its counter. And in order to delete an existing element you can add a checkbox with a C<delete_if_true> option of its C<model_config> section set to C<1>. Those addresses with this checkbox checked will be deleted upon form submission. Alternatively you can use javascript to remove this field from the form and decrement the counters of the other elements respectively.

=head1 EXAMPLE

This manual comes with a bundled Catalyst application that shows most of the above examples in action. You can find it in the the distribution's C<example> directory.

=head1 AUTHOR

Peter Shangov <pshangov@yahoo.com>

=head1 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.

=cut

