NAME

HTML::FormFu::Model::DBIC - Integrate HTML::FormFu with DBIx::Class

SYNOPSIS

Example of typical use in a Catalyst controller:

        sub edit : Chained {
            my ( $self, $c ) = @;
        
            my $form = $c->stash->{form};
            my $book = $c->stash->{book};
        
            if ( $form->submittedand_valid ) {
            
                # update dbic row with submitted values from form
            
                $form->model->update( $book );
            
                $c->response->redirect( $c->uri_for('view', $book->id) );
                return;
            }
            elsif ( !$form->submitted ) {
            
                # use dbic row to set form's default values
            
                $form->model->default_values( $book );
            }
        
            return;
        }

SETUP

For the form object to be able to access your DBIx::Class schema, it needs to be placed on the form stash, with the name "schema".

This is easy if you're using Catalyst-Controller-HTML-FormFu, as you can set this up to happen in your Catalyst app's config file.

For example, if your model is named "MyApp::Model::Corp", you would set this (in Config::General format):

        <Controller::HTML::FormFu>
            <model_stash>
                schema Corp
            </model_stash>
        </Controller::HTML::FormFu>

Or if your app's config file is in YAML format:

        'Controller::HTML::FormFu':
            model_stash:
                schema: Corp

METHODS
default_values
Arguments: $dbic_row, [\%config]

Return Value: $form

$form->model->default_values( $dbic_row );

Set a form's default values from the database, to allow a user to edit them.

update
Arguments: [$dbic_row], [\%config]

Return Value: $dbic_row

$form->model->update( $dbic_row );

Update the database with the submitted form values.

create
Arguments: [\%config]

Return Value: $dbic_row

my $dbic_row = $form->model->create( {resultset => 'Book'} );

Like "update", but doesn't require a $dbic_row argument.

You need to ensure the DBIC schema is available on the form stash - see "SYNOPSIS" for an example config.

The "resultset" must be set either in the method arguments, or the form or block's "model_config".

An example of setting the ResultSet name on a Form:

        ---
        model_config:
          resultset: FooTable
    
        elements:
          # [snip]

options_from_model
Populates a multi-valued field with values from the database.

This method should not be called directly, but is called for you during "$form->process" by fields that inherit from HTML::FormFu::Element::_Group. This includes:

HTML::FormFu::Element::Select
HTML::FormFu::Element::Checkboxgroup HTML::FormFu::Element::Radiogroup
HTML::FormFu::Element::ComboBox

To use you must set the appropriate "resultset" on the element "model_config":

element

BUILDING FORMS
single table
To edit the values in a row with no related rows, the field names simply have to correspond to the database column names.

For the following DBIx::Class schema:

        package MySchema::Book;
        use base 'DBIx::Class';
    
        __PACKAGE__->load_components(qw/ Core /);
    
        __PACKAGE__->table("book");
    
        __PACKAGE__->add_columns(
            id     => { data_type => "INTEGER" },
            title  => { data_type => "TEXT" },
            author => { data_type => "TEXT" },
            blurb  => { data_type => "TEXT" },
        );
    
        __PACKAGE__->set_primary_key("id");
    
        1;

A suitable form for this might be:

elements

might_have and has_one relationships
Set field values from a related row with a "might_have" or "has_one" relationship by placing the fields within a Block (or any element that inherits from Block, such as Fieldset) with its "nested_name" in HTML::FormFu set to the relationship name.

For the following DBIx::Class schemas:

        package MySchema::Book;
        use base 'DBIx::Class';
    
        __PACKAGE__->load_components(qw/ Core /);
    
        __PACKAGE__->table("book");
    
        __PACKAGE__->add_columns(
            id    => { data_type => "INTEGER" },
            title => { data_type => "TEXT" },
        );
    
        __PACKAGE__->set_primary_key("id");
    
        __PACKAGE__->might_have( review => 'MySchema::Review', 'book' );
    
        1;

        package MySchema::Review;
        use base 'DBIx::Class';
    
        __PACKAGE__->load_components(qw/ Core /);
    
        __PACKAGE__->table("review");
    
        __PACKAGE__->add_columns(
            id          => { data_type => "INTEGER" },
            book        => { data_type => "INTEGER", is_nullable => 1 },
            review_text => { data_type => "TEXT" },
        );
    
        __PACKAGE__->set_primary_key("book");
    
        __PACKAGE__->belongs_to( book => 'MySchema::Book' );
    
        1;

A suitable form for this would be:

elements

For "might_have" and "has_one" relationships, you generally shouldn't need to have a field for the related table's primary key, as DBIx::Class will handle retrieving the correct row automatically.

You can also set a "has_one" or "might_have" relationship using a multi value field like Select.

elements

This will load all reviews into the select field. If you select a review from that list, a current relationship to a review is removed and the new one is added. This requires that the primary key of the "Review" table and the foreign key do not match.

has_many and many_to_many relationships The general principle is the same as for "might_have" and "has_one" above, except you should use a Repeatable element instead of a Block, and it needs to contain a Hidden field corresponding to the foreign key.

The Repeatable block's nested_name must be set to the name of the relationship.

The Repeable block's increment_field_names must be true (which is the default value).

The Repeable block's counter_name must be set to the name of a Hidden field, which is placed outside of the Repeatable block. This field is used to store a count of the number of repetitions of the Repeatable block were created. When the form is submitted, this value is used during "$form->process" to ensure the form is rebuilt with the correct number of repetitions.

For the following DBIx::Class schemas:

        package MySchema::Book;
        use base 'DBIx::Class';
    
        __PACKAGE__->load_components(qw/ Core /);
    
        __PACKAGE__->table("book");
    
        __PACKAGE__->add_columns(
            id    => { data_type => "INTEGER" },
            title => { data_type => "TEXT" },
        );
    
        __PACKAGE__->set_primary_key("id");
    
        __PACKAGE__->has_many( review => 'MySchema::Review', 'book' );
    
        1;

        package MySchema::Review;
        use base 'DBIx::Class';
    
        __PACKAGE__->load_components(qw/ Core /);
    
        __PACKAGE__->table("review");
    
        __PACKAGE__->add_columns(
            book        => { data_type => "INTEGER" },
            review_text => { data_type => "TEXT" },
        );
    
        __PACKAGE__->set_primary_key("book");
    
        __PACKAGE__->belongs_to( book => 'MySchema::Book' );
    
        1;

A suitable form for this would be:

elements

many_to_many selection
To select / deselect rows from a "many_to_many" relationship, you must use a multi-valued element, such as a Checkboxgroup or a Select with multiple set.

The field's name must be set to the name of the "many_to_many" relationship.

default_column
If you want to search / associate the related table by a column other it's primary key, set "$field->model_config->{default_column}".

        ---
        element:
            - type: Checkboxgroup
              name: authors
              model_config:
                default_column: foo

link_values
If you want to set columns on the link table you can do so if you add a "link_values" attribute to "model_config":

        ---
        element:
            - type: Checkboxgroup
              name: authors
              model_config:
                link_values:
                  foo: bar

additive
The default implementation will first remove all related objects and set the new ones (see
<http://search.cpan.org/perldoc?DBIx::Class::Relationship::Base#set_$rel>). If you want to add the selected objects to the current set of objects set "additive" in the "model_config".

        ---
        element:
            - type: Checkboxgroup
              name: authors
              model_config:
                additive: 1
                options_from_model: 0

"options_from_model" is set to 0 because it will try to fetch all objects from the result class "Authors" if "model_config" is specified without a "resultset" attribute.)

COMMON ARGUMENTS

The following items are supported in the optional "config" hash-ref argument to the methods default_values, update and create.

base

        If you want the method to process a particular Block element, rather
        than the whole form, you can pass the element as a "base" argument.

            $form->default_values(
                $row,
                {
                    base => $formfu_element,
                },
            );

nested_base

        If you want the method to process a particular Block element by
        name, you can pass the name as an argument.

            $form->default_values(
                $row,
                {
                    nested_base => 'foo',
                }'
            );

CONFIGURATION
Config options for fields
The following items are supported as "model_config" options on form fields.

accessor

        If set, "accessor" will be used as a method-name accessor on the
        "DBIx::Class" row object, instead of using the field name.

delete_if_empty

        Useful for editing a "might_have" related row containing only one
        field.

        If the submitted value is blank, the related row is deleted.

        For the following DBIx::Class schemas:

            package MySchema::Book;
            use base 'DBIx::Class';
    
            __PACKAGE__->load_components(qw/ Core /);
    
            __PACKAGE__->table("book");
    
            __PACKAGE__->add_columns(
                id    => { data_type => "INTEGER" },
                title => { data_type => "TEXT" },
            );
    
            __PACKAGE__->set_primary_key("id");
    
            __PACKAGE__->might_have( review => 'MySchema::Review', 'book' );
    
            1;

            package MySchema::Review;
            use base 'DBIx::Class';
    
            __PACKAGE__->load_components(qw/ Core /);
    
            __PACKAGE__->table("review");
    
            __PACKAGE__->add_columns(
                book        => { data_type => "INTEGER" },
                review_text => { data_type => "TEXT" },
            );
    
            __PACKAGE__->set_primary_key("book");
    
            __PACKAGE__->belongs_to( book => 'MySchema::Book' );
    
            1;

        A suitable form for this would be:

            elements:
              - type: Text
                name: title
      
              - type: Block
                nested_name: review
                elements:
                  - type: Text
                    name: review_text
                    model_config:
                      delete_if_empty: 1

label

To use a column value for a form field's label.

Config options for fields within a Repeatable block delete_if_true

Intended for use on a Checkbox field.

        If the checkbox is checked, the following occurs: for a has-many
        relationship, the related row is deleted; for a many-to-many
        relationship, the relationship link is removed.

        An example of use might be:

            elements:
              - type: Text
                name: title
      
              - type: Hidden
                name: review_count
      
              - type: Repeatable
                nested_name: review
                counter_name: review_count
                elements:
                  - type: Hidden
                    name: book
          
                  - type: Textarea
                    name: review_text
          
                  - type: Checkbox
                    name: delete_review
                    label: 'Delete Review?'
                    model_config:
                      delete_if_true: 1

        Note: make sure the name of this field does not clash with one of
        your DBIx::Class::Row method names (e.g. "delete") - see "CAVEATS".

Config options for Repeatable blocks
empty_rows

        For a Repeatable block corresponding to a has-many or many-to-many
        relationship, to allow the user to insert new rows, set "empty_rows"
        to the number of extra repetitions you wish added to the end of the
        Repeatable block.

new_rows_max

        Set to the maximum number of new rows that a Repeatable block is
        allowed to add.

        If not set, it will fallback to the value of "empty_rows".

Config options for options_from_model The column used for the element values is set with the "model_config" value "id_column" - or if not set, the table's primary column is used.

element

The column used for the element labels is set with the "model_config" value "label_column" - or if not set, the first text/varchar column found in the table is used - or if one is not found, the "id_column" is used instead.

element

To pass the database label values via the form's localization object, set "localize_label"

element

You can set a "condition", which will be passed as the 1st argument to "search" in DBIx::Class::ResultSet.

element

You can set a "condition_from_stash", which will be passed as the 1st argument to "search" in DBIx::Class::ResultSet.

"key" is the column-name to be passed to search, and "stash_key" is the name of a key on the form stash from which the value to be passed to search is found.

element

Is comparable to:

        $form->element({
            type => 'Select',
            name => 'foo',
            model_config => {
                resultset => 'TableClass',
                condition => {
                    key => $form->stash->{stash_key}
                }
            }
        })

You can set "attributes", which will be passed as the 2nd argument to "search" in DBIx::Class::ResultSet.

FAQ
Add extra values not in the form
To update values to the database which weren't submitted to the form, you can first add them to the form with add_valid.

my $passwd = generate_passwd();

$form->add_valid( passwd => $passwd );

$form->model->update( $row );

"add_valid" works for fieldnames that don't exist in the form.

Set a field read only
You can make a field read only. The value of such fields cannot be changed by the user even if they submit a value for it.

$field->model_config->{read_only} = 1;

See HTML::FormFu::Element::Label.

CAVEATS

To ensure your column's inflators and deflators are called, we have to get / set values using their named methods, and not with "get_column" / "set_column".

Because of this, beware of having column names which clash with DBIx::Class built-in method-names, such as "delete". - It will have obviously undesirable results!

REMOVED METHODS
new_empty_row
See "empty_rows" in "Config options for Repeatable blocks" instead.

new_empty_row_multi
See "new_rows_max" in "Config options for Repeatable blocks" instead.

Range constraint
See "empty_rows" in "Config options for Repeatable blocks" instead.

SUPPORT

Project Page:

<http://code.google.com/p/html-formfu/>

Mailing list:

<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/html-formfu>

Mailing list archives:

<http://lists.scsys.co.uk/pipermail/html-formfu/>

BUGS

Please submit bugs / feature requests to <http://code.google.com/p/html-formfu/issues/list> (preferred) or <http://rt.perl.org>.

SUBVERSION REPOSITORY

The publicly viewable subversion code repository is at <http://html-formfu.googlecode.com/svn/trunk/HTML-FormFu-Model-DBIC>.

If you wish to contribute, you'll need a GMAIL email address. Then just ask on the mailing list for commit access.

If you wish to contribute but for some reason really don't want to sign up for a GMAIL account, please post patches to the mailing list (although you'll have to wait for someone to commit them).

If you have commit permissions, use the HTTPS repository url: <https://html-formfu.googlecode.com/svn/trunk/HTML-FormFu-Model-DBIC>

SEE ALSO

HTML::FormFu, DBIx::Class, Catalyst::Controller::HTML::FormFu

AUTHOR

Carl Franks

CONTRIBUTORS

Based on the code of "DBIx::Class::HTML::FormFu", which was contributed to by:

Adam Herzog

Daisuke Maki

Mario Minati

COPYRIGHT AND LICENSE

Copyright (C) 2007 by Carl Franks

Based on the original source code of DBIx::Class::HTMLWidget, copyright Thomas Klausner.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.