Class::DBI::FormBuilder - Class::DBI/CGI::FormBuilder integration
package Film; use strict; use warnings; use base 'Class::DBI'; use Class::DBI::FormBuilder; # for indented output: # use Class::DBI::FormBuilder PrettyPrint => 'ALL'; # POST all forms to server Film->form_builder_defaults->{method} = 'post'; # customise how some fields are built: # 'actor' is a has_a field, and the # related table has 1000's of rows, so we don't want the default popup widget, # we just want to show the current value Film->form_builder_defaults->{process_fields}->{actor} = 'VALUE'; # 'trailer' stores an mpeg file, but CDBI::FB cannot automatically detect # file upload fields, so need to tell it: Film->form_builder_defaults->{process_fields}->{trailer} = 'FILE'; # has_a fields will be automatically set to 'required'. Additional fields can be specified: Film->form_builder_defaults->{required} = qw( foo bar ); # In a nearby piece of code... my $film = Film->retrieve( $id ); print $film->as_form( params => $q )->render; # or $r if mod_perl # For a search app: my $search_form = Film->search_form; # as_form plus a few tweaks # A fairly complete mini-app: my $form = Film->as_form( params => $q ); # or $r if mod_perl if ( $form->submitted and $form->validate ) { # whatever you need: my $obj = Film->create_from_form( $form ); my $obj = Film->update_from_form( $form ); my $obj = Film->update_or_create_from_form( $form ); my $obj = Film->retrieve_from_form( $form ); my $iter = Film->search_from_form( $form ); my $iter = Film->search_like_from_form( $form ); my $iter = Film->search_where_from_form( $form ); my $obj = Film->find_or_create_from_form( $form ); my $obj = Film->retrieve_or_create_from_form( $form ); print $form->confirm; } else { print $form->render; } # See CGI::FormBuilder docs and website for lots more information.
Errata: use of column name/accessor/mutator is currently broken if your column accessors/mutators are different from the column name. The documentation is also broken w.r.t. this.
This module creates a CGI::FormBuilder form from a CDBI class or object. If from an object, it populates the form fields with the object's values.
Column metadata and CDBI relationships are analyzed and the fields of the form are modified accordingly. For instance, MySQL enum and set columns are configured as select, radiobutton or checkbox widgets as appropriate, and appropriate widgets are built for has_a, has_many and might_have relationships. Further relationships can be added by subclassing. has_a columns are set as 'required' fields in create/update forms.
enum
set
select
radiobutton
checkbox
has_a
has_many
might_have
A demonstration app (using Maypole::FormBuilder) can be viewed at
http://beerfb.riverside-cms.co.uk
Often, the default behaviour will be unsuitable. For instance, a has_a relationship might point to a related table with thousands of records. A popup widget with all these records is probably not useful. Also, it will take a long time to build, so post-processing the form to re-design the field is a poor solution.
Instead, you can pass an extra process_fields argument in the call to as_form (or you can set it in form_builder_defaults).
process_fields
as_form
form_builder_defaults
Many of the internal routines use this mechanism for configuring fields. A manually set '+' (basic) processor will be added to any other automatic processing, whereas a manually set shortcut processor (no '+') will replace all automatic processing.
You can add your own processors to the internal table of processors - see new_field_processor.
new_field_processor
This is a hashref, with keys being field names. Values can be:
basic shortcut ------------------------------------------------------------------------------- +HIDDEN HIDDEN make the field hidden +VALUE VALUE display the current value +READONLY READONLY display the current value - not editable +DISABLED DISABLED display the current value - not editable, not selectable, (not submitted?) +FILE FILE build a file upload widget +OPTIONS_FROM_DB OPTIONS_FROM_DB check if the column is constrained to a few values +REQUIRED make the field required +NULL no-op - useful for debugging +ADD_FIELD add a new field to the form (only necessary if the field is empty) TIMESTAMP used to process TIMESTAMP fields, defaults to DISABLED, but you can easily replace it with a different behaviour +SET_VALUE($value) set the value of the field to $value - DEPRECATED - use +SET_value +SET_$foo($value) SET_$foo($value) set the $foo attribute of the field to $value
The 'basic' versions apply only their own modification. The 'shortcut' version also applies the +VALUE processor.
+VALUE
OPTIONS_FROM_DB currently only supports MySQL ENUM or SET columns. You probably won't need to use this explicitly, as it's already used internally.
OPTIONS_FROM_DB
The +ADD_FIELD processor is only necessary if you need to add a new field to a form, but don't want to use any of the other processors on it.
+ADD_FIELD
The coderef will be passed the Class::DBI::FormBuilder class or subclass, the CDBI class or object, the CGI::FormBuilder form object, and the field name as arguments, and should build the named field.
Name of a package with a suitable field subroutine. Gets called with the same arguments as the coderef.
field
Applies each processor in order.
The key __FINAL__ is reserved for form_final, so don't name any form fields __FINAL__. If a field processor is set in __FINAL__, then it will be applied to all fields, after all other processors have run.
__FINAL__
form_final
render
Class::DBI::FormBuilder replaces CGI::FormBuilder::render() with a hookable version of render(). The hook is a coderef, or the name of a built-in, supplied in the post_process argument (which can be set in the call to as_form, search_form, render, or in form_builder_defaults). The coderef is passed the following arguments:
Class::DBI::FormBuilder
CGI::FormBuilder::render()
render()
post_process
search_form
$class the CDBI::FormBuilder class or subclass $form the CGI::FormBuilder form object $render reference to &CGI::FormBuilder::render $pp_args value of the post_process_args argument, or undef %args the arguments used in the CGI::FormBuilder->new call
The coderef should return HTML markup for the form, probably by calling $render->( $form, %args ).
$render->( $form, %args )
A pretty-printer coderef is available in the hashref of built-in post-processors:
my $pretty = Class::DBI::FormBuilder->post_processors->{PrettyPrint};
So you can turn on pretty printing for a class by setting:
My::Class->form_builder_defaults->{post_process} = Class::DBI::FormBuilder->post_processors->{PrettyPrint};
This post-processor ensures that any fields configured as textareas are converted to a plain text field before rendering.
textarea
text
This might have been used for instance in the Maypole::FormBuilder editable list template, to ensure each form in the table fits neatly into a single row. Except that method is an ugly hack that doesn't support post-processors.
list
has_a relationships can refer to non-CDBI classes. In this case, form_has_a will attempt to load (via require) an appropriate plugin. For instance, for a Time::Piece column, it will attempt to load Class::DBI::FormBuilder::Plugin::Time::Piece. Then it will call the field method in the plugin, passing the CDBI class for whom the form has been constructed, the form, and a Class::DBI::Column object representing the field being processed. The plugin can use this information to modify the form, perhaps adding extra fields, or controlling stringification, or setting up custom validation. Note that the name of the form field should be retrieved from the field object as $field->name, rather than relying on $field to stringify itself, because it will stringify to $field->name_lc.
form_has_a
require
Time::Piece
$field->name
$field
$field->name_lc
If no plugin is found, a fatal exception is thrown. If you have a situation where it would be useful to simply stringify the object instead, let me know and I'll make this configurable.
If you place a normal CGI::FormBuilder validation spec in the validate argument, that spec will be used to configure validation.
validate
If there is no spec in the method call or in $class->form_builder_defaults->{validate}, then validation will be configured automatically. The default configuration is pretty basic, but you can modify it by placing settings in the auto_validate argument, or in $class->form_builder_defaults->{auto_validate}.
$class->form_builder_defaults->{validate}
auto_validate
$class->form_builder_defaults->{auto_validate}
Given no validation options for a column in the auto_validate slot, the settings for most columns will be taken from %Class::DBI::FormBuilder::ValidMap. This maps SQL column types to the CGI::FormBuilder validation settings VALUE, INT, or NUM.
%Class::DBI::FormBuilder::ValidMap
VALUE
INT
NUM
MySQL ENUM or SET columns will be set up to validate that the submitted value(s) match the allowed values.
ENUM
SET
Any column listed in $class->form_builder_defaults->{options} will be set to validate those values.
$class->form_builder_defaults->{options}
The following settings can be placed in the auto_validate argument (or in $class->form_builder_defaults->{auto_validate}).
Specify validate types for specific columns:
validate => { username => [qw(nate jim bob)], first_name => '/^\w+$/', # note the last_name => '/^\w+$/', # single quotes! email => 'EMAIL', password => \&check_password, confirm_password => { javascript => '== form.password.value', perl => 'eq $form->field("password")' }
This option takes the same settings as the validate option to CGI::FormBuilder::new() (i.e. the same as would otherwise go in the validate argument or in $class->form_builder_defaults->{validate}). Settings here override any others.
CGI::FormBuilder::new()
Alias for validate. Don't use both, they're not intended to be merged. Use whichever feels more comfortable. If you're used to using CGI::FormBuilder, it may feel more natural to use validate. If not, it may make more sense to use columns.
columns
List of columns that will not be validated:
skip_columns => [ qw( secret_stuff internal_data ) ]
Use regular expressions matching groups of columns to specify validation:
match_columns => { qr/(^(widget|burger)_size$/ => [ qw( small medium large ) ], qr/^count_.+$/ => 'INT', }
Validate according to SQL data types:
validate_types => { date => \&my_date_checker, }
Defaults are taken from the package global %TypesMap.
%TypesMap
Use a regular expression to map SQL data types to validation types:
match_types => { qr(date) => \&my_date_checker, }
Control how much detail to report (via warn) during setup. Set to 1 for brief info, and 2 for a list of each column's validation setting.
warn
If set to 1, will die if a validation setting cannot be determined for any column. Default is to issue warnings and not validate these column(s).
Although it would be possible to retrieve the IDs of all objects for a related column and use these to set up validation, this would rapidly become unwieldy for larger tables. Default validation will probably be acceptable in most cases, as the column type will usually be some kind of integer.
The default behaviour is to skip validating timestamp columns. A warning will be issued if the debug parameter is set to 2.
timestamp
debug
Note that timestamp columns are rendered as readonly (see form_timestamp).
readonly
form_timestamp
The default mapping of column types to validation types is set in %Class::DBI::FormBulder::ValidMap, and is probably incomplete. If you come across any failures, you can add suitable entries to the hash before calling as_form. However, please email me with any failures so the hash can be updated for everyone.
%Class::DBI::FormBulder::ValidMap
If you want to use this module alongside Class::DBI::FromForm, load the module like so
use Class::DBI::FormBuilder BePoliteToFromForm => 1;
and create_from_form and update_from_form will instead be imported as create_from_fb and update_from_fb.
create_from_form
update_from_form
create_from_fb
update_from_fb
You might want to do this if you have more complex validation requirements than CGI::FormBuilder provides.
Most of the methods described here are exported into the caller's namespace, except for the form modifiers (see below), and a few others as documented.
This method is called on Class::DBI::FormBuilder or a subclass, rather than on a Class::DBI object or subclass.
It installs a new field processor, which can then be referred to by name in process_fields, rather than by passing a coderef. This method could also be used to replace the supplied built-in field processors, for example to alter the default TIMESTAMP behaviour (see form_timestamp). The new processor must either be a coderef, or the name of a package with a suitable field method, or the name of another processor, or an arrayref of any of these.
TIMESTAMP
The code ref will be passed these arguments:
position argument -------------------- 0 name of the calling class (i.e. Class::DBI::FormBuilder or a subclass) 1 Class::DBI object or class name 2 CGI::FormBuilder form object 3 name of the current field 4 Class::DBI::Column object for the current field
The name of the current field is the name used on the form object, and is also the mutator accessor for the column on the CDBI object (which defaults to the name in the database, but can be different).
The column object is useful if the processor needs access to the value in the CDBI object, but the mutator name is different from the column accessor e.g. see the +VALUE processor.
Class::DBI::FormBuilder class method.
Returns a Class::DBI::FormBuilder::Meta::Table object.
Stores default arguments.
Builds a CGI::FormBuilder form representing the class or object.
Takes default arguments from form_builder_defaults.
The optional hash of arguments is the same as for CGI::FormBuilder::new(), with a few extras, and will override any keys in form_builder_defaults.
The extra keys are documented in various places in this file - I'll gather them together here over time. Extra keys include:
A hashref, keyed by field name, with values being coderefs that will be used to sort the list of options generated for a has_a, has_many, or might_have field.
The coderef will be passed pairs of options arrayrefs, and should return the standard Perl sort codes (i.e. -1, 0, or 1). The first item in each arrayref is the value of the option, the second is the label.
Note that the coderef should be prototyped ($$):
# sort by label, alphabetically $field_name => sub ($$) { $_[0]->[1] cmp $_[1]->[1] } # sort by value, numerically $field_name => sub ($$) { $_[0]->[0] <=> $_[1]->[0] }
Note that parameter merging is likely to become more sophisticated in future releases (probably copying the argument merging code from CGI::FormBuilder itself).
Build a form with inputs that can be fed to search methods (e.g. search_where_from_form). For instance, all selects are multiple, fields that normally would be required are not, and TEXT columns are represented as text fields rather than as textareas by default.
search_where_from_form
TEXT
Automatic configuration of validation settings is not carried out on search forms. You can still configure validation settings using the standard CGI::FormBuilder settings.
In many cases, you will want to design your own search form, perhaps only searching on a subset of the available columns. Note that you can acheive that by specifying
fields => [ qw( only these fields ) ]
in the args.
The following search options are available. They are only relevant if processing via search_where_from_form.
Allow the user to select a comparison operator by passing an arrayref:
search_opt_cmp => [ ( '=', '!=', '<', '<=', '>', '>=', 'LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP', 'REGEXP BINARY', 'NOT REGEXP BINARY', ) ]
Or, transparently set the search operator in a hidden field:
search_opt_cmp => 'LIKE'
If true, will generate a widget to select (possibly multiple) columns to order the results by, with an ASC and DESC option for each column.
ASC
DESC
If set to an arrayref, will use that to build the widget.
# order by any columns search_opt_order_by => 1 # or just offer a few search_opt_order_by => [ 'foo', 'foo DESC', 'bar' ]
This method supports adding multiple related items to an object in a related class. Call this method on the class at the 'many' end of a has_many relationship. Instead of building a form with fields
foo bar baz
it builds a form with fields
R1__foo R1__bar R1__baz R2__foo R2__bar R2__baz etc.
Specify the number of duplicates in the how_many required argument.
how_many
Use create_from_multiform to process a form submission.
create_from_multiform
See Maypole::FormBuilder::Model::addmany() and the addmany template for example usage.
Maypole::FormBuilder::Model::addmany()
addmany
DEPRECATED.
This method is NOT WORKING, and will be removed from a future version. The plan is to replace as_form with this code, when it's working properly.
Builds a form with fields from the target CDBI class/object, plus fields from the related objects.
Accepts the same arguments as as_form, with these additions:
A hashref of $field_name => $as_form_args_hashref settings. Each $as_form_args_hashref can take all the same settings as as_form. These are used for generating the fields of the class or object(s) referred to by that field. For instance, you could use this to only display a subset of the fields of the related class.
$field_name => $as_form_args_hashref
$as_form_args_hashref
By default, all related fields are shown in the form. To only expand selected related fields, list them in show_related.
show_related
These methods use CDBI's knowledge about its columns and table relationships to tweak the form to better represent a CDBI object or class. They can be overridden if you have better knowledge than CDBI does. For instance, form_options only knows how to figure out select-type columns for MySQL databases.
form_options
You can handle new relationship types by subclassing, and writing suitable form_* methods (e.g. form_many_many). Your custom methods will be automatically called on the relevant fields.
form_*
form_many_many)
has_a relationships to non-CDBI classes are handled via a plugin mechanism (see above).
Deprecated. Renamed form_pks.
form_pks
Ensures primary column fields are included in the form (even if they were not included in the fields list), and hides them. Only forms representing objects will have primary column fields added.
fields
Identifies column types that should be represented as select, radiobutton or checkbox widgets. Currently only works for MySQL ENUM and SET columns.
Patches are welcome for similar column types in other RDBMS's.
Note that you can easily emulate a MySQL ENUM column at the application level by setting the validation for the column to an arrayref of values. Emulate a SET column by additionally setting the multiple option to 1.
multiple
1
Populates a select-type widget with entries representing related objects. Makes the field required.
Note that this list will be very long if there are lots of rows in the related table. You may need to override this behaviour by setting up a pre-processor for your has_a fields. See 'Customising field construction'.
This method assumes the primary key is a single column - patches welcome.
Retrieves every row and creates an object for it - not good for large tables.
If the relationship is to a non-CDBI class, loads a plugin to handle the field (see 'Plugins').
Also assumes a single primary column.
Makes timestamp columns read only, since they will be set by the database.
The default is to use the TIMESTAMP processor, which in turn points to the READONLY processor, which sets the HTML readonly attribute.
READONLY
If you prefer, you can replace the TIMESTAMP processor with one that points to DISABLED instead.
DISABLED
Makes TEXT columns into textarea form fields.
Unimplemented - at the moment, you need to set the field type to file manually, or in the process_fields argument, set the field processor to FILE.
file
FILE
Figures out if a column contains file data.
If somebody can show me how to automatically detect that a column stores binary data, then this method could actually do something useful.
If you are in the habit of using a naming convention that allows you to identify file columns, then you could subclass Class::DBI::FormBuilder and override this method:
# use a naming convention to configure file columns sub form_file { my ( $me, $them, $form, $pre_process ) = @_; foreach my $field ( $them->columns( 'All' ) ) { next unless $field->name =~ /^file_\w+$/; my $process = $me->_add_processors( $field, $pre_process, 'FILE' ); $me->_process_field( $them, $form, $field, $process ); } }
This processor adds any fields in the process_fields setup that do not yet exist on the form. This is a useful method for adding custom fields (i.e. fields that do not represent anything about the CDBI object) to a form.
You can skip this stage by setting process_fields->{__SKIP_PROCESS_EXTRAS__} to a true value. For instance, in Maypole::FormBuilder::Model::setup_form_mode(), this prevents any fields already present in process_fields (e.g. because they were specified in form_builder_defaults) from being added to the button form.
process_fields->{__SKIP_PROCESS_EXTRAS__}
Maypole::FormBuilder::Model::setup_form_mode()
After running all previous field processors (including form_process_extras), this gives the chance to run code to modify all fields in the completed form. Use this by setting a field processor in the special __FINAL__ slot of process_fields.
form_process_extras
And avoid naming any of your normal columns or fields __FINAL__.
All these methods check the form like this
return unless $fb->submitted && $fb->validate;
which allows you to say things like
print Film->update_from_form( $form ) ? $form->confirm : $form->render;
That's pretty concise!
Creates and returns a new object.
Creates multiple new objects from a as_multiform form submission.
as_multiform
Updates an existing CDBI object.
If called on an object, will update that object.
If called on a class, will first retrieve the relevant object (via retrieve_from_form).
retrieve_from_form
Class method.
Attempts to look up an object (using primary key data submitted in the form) and update it.
If none exists (or if no values for primary keys are supplied), a new object is created.
Note that search methods (except for retrieve_from_form) will return a CDBI iterator in scalar context, and a (possibly empty) list of objects in list context.
All the search methods except retrieve_from_form require that the submitted form should be built using search_form (not as_form). Otherwise the form may fail validation checks because of missing required fields specified by as_form (search_form does not automatically configure any fields as required).
Use primary key data in a form to retrieve a single object.
Lookup by column values.
Allows wildcard searches (% or _).
Note that the submitted form should be built using search_form, not as_form.
Class::DBI::AbstractSearch must be loaded in your CDBI class for this to work.
If no search terms are specified, then the search
WHERE 1 = 1
is executed (returns all rows), no matter what search operator may have been selected.
Does a find_or_create using submitted form data.
find_or_create
Attempts to look up an object. If none exists, a new object is created.
This is similar to update_or_create_from_form, except that this method will not update pre-existing objects.
update_or_create_from_form
has_many fields are not currently being validated (the code to set up the validation config was choking on has_many columns, so for now, they're ignored).
Use the proper column accessors (i.e. $column->name for form field names, $column->accessor for 'get', and $column->mutator foe 'set' operations).
Add support for local plugins - i.e. specify a custom namespace to search for plugins, before searching the CDBI::FB::Plugin namespace.
Better merging of attributes. For instance, it'd be nice to set some field attributes (e.g. size or type) in form_builder_defaults, and not lose them when the fields list is generated and added to %args.
%args
Regex and column type entries for process_fields, analogous to validation settings.
Use preprocessors in form_has_a, form_has_many and form_might_have.
Transaction support - see http://search.cpan.org/~tmtm/Class-DBI-0.96/lib/Class/DBI.pm#TRANSACTIONS and http://wiki.class-dbi.com/index.cgi?AtomicUpdates
Wrap the call to $form_modify in an eval, and provide a better diagnostic if the call fails because it's trying to handle a relationship that has not yet been coded - e.g. is_a
$form_modify
Store CDBI errors somewhere on the form. For instance, if update_from_form fails because no object could be retrieved using the form data.
Detect binary data and build a file upload widget.
is_a relationships.
is_a
enum and set equivalent column types in other dbs.
Figure out how to build a form for a related column when starting from a class, not an object (pointed out by Peter Speltz). E.g.
my $related = $object->some_col; print $related->as_form->render;
will not work if $object is a class. Have a look at Maypole::Model::CDBI::related_class.
Integrate fields from a related class object into the same form (e.g. show address fields in a person form, where person has_a address). UPDATE: fairly well along in 0.32 (as_form_with_related). UPDATE: as_form_with_related() is deprecated (and still not working) Once it works properly, it will be merged into as_form.
as_form_with_related
_splice_form needs to handle custom setup for more relationship types.
_splice_form
David Baird, <cpan@riverside-cms.co.uk>
<cpan@riverside-cms.co.uk>
If no fields are explicitly required, then *all* fields will become required automatically, because CGI::FormBuilder by default makes any field with validation become required, unless there is at least 1 field specified as required.
Please report any bugs or feature requests to bug-class-dbi-plugin-formbuilder@rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Class-DBI-FormBuilder. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-class-dbi-plugin-formbuilder@rt.cpan.org
Looking at the code (0.32), I suspect updates to has_many accessors are not implemented, since the update methods only fetch data for columns( 'All' ), which doesn't include has_many accessors/mutators.
The following people have provided useful discussions, bug reports, and patches:
Dave Howorth, James Tolley, Ron McClain, David Kamholz.
Copyright 2005 David Baird, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Class::DBI::FormBuilder, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Class::DBI::FormBuilder
CPAN shell
perl -MCPAN -e shell install Class::DBI::FormBuilder
For more information on module installation, please visit the detailed CPAN module installation guide.