Why not adopt me?
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->submitted_and_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:
- type: Select
name: foo
model_config:
resultset: TableClass
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:
- type: Text
name: title
- type: Text
name: author
- type: Textarea
name: blurb
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:
- type: Text
name: title
- type: Block
nested_name: review
elements:
- type: Textarea
name: review_text
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:
- type: Text
name: title
- type: Select
nested: review
model_config:
resultset: Review
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:
- 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
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 theDBIx::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:
- type: Select
name: foo
model_config:
resultset: TableClass
id_column: pk_col
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:
- type: Select
name: foo
model_config:
resultset: TableClass
label_column: label_col
To pass the database label values via the form's localization object, set localize_label
element:
- type: Select
name: foo
model_config:
localize_label: 1
You can set a condition
, which will be passed as the 1st argument to "search" in DBIx::Class::ResultSet.
element:
- type: Select
name: foo
model_config:
resultset: TableClass
condition:
type: is_foo
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:
- type: Select
name: foo
model_config:
resultset: TableClass
condition_from_stash:
key: stash_key
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;
- Name: 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.