Why not adopt me?
NAME
Class::DBI::FormBuilder - Class::DBI/CGI::FormBuilder integration
SYNOPSIS
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.
DESCRIPTION
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.
A demonstration app (using Maypole::FormBuilder) can be viewed at
http://beerfb.riverside-cms.co.uk
Customising field construction
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
).
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
.
process_fields
This is a hashref, with keys being field names. Values can be:
- Name of a built-in
-
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.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.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. - Reference to a subroutine, or anonymous coderef
-
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.
- Package name
-
Name of a package with a suitable
field
subroutine. Gets called with the same arguments as the coderef. - Arrayref of the above
-
Applies each processor in order.
Plugins
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->mutator
, rather than relying on $field
to stringify itself, because it will stringify to lc( $field->name
.
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.
Automatic validation setup
If you place a normal CGI::FormBuilder validation spec in $class->form_builder_defaults->{validate}
, that spec will be used to configure validation.
If there is no spec 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 $class->form_builder_defaults->{auto_validate}
.
Basic auto-validation
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
.
MySQL ENUM
or SET
columns will be set up to validate that the submitted value(s) match the allowed values.
Any column listed in $class->form_builder_defaults->{options}
will be set to validate those values.
Advanced auto-validation
The following settings can be placed in $class->form_builder_defaults->{auto_validate}
.
- 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 toCGI::FormBuilder::new()
(i.e. the same as would otherwise go in$class->form_builder_defaults->{validate}
). Settings here override any others. - skip_columns
-
List of columns that will not be validated:
skip_columns => [ qw( secret_stuff internal_data ) ]
- match_columns
-
Use regular expressions matching groups of columns to specify validation:
match_columns => { qr/(^(widget|burger)_size$/ => [ qw( small medium large ) ], qr/^count_.+$/ => 'INT', }
- validate_types
-
Validate according to SQL data types:
validate_types => { date => \&my_date_checker, }
Defaults are taken from the package global
%TypesMap
. - match_types
-
Use a regular expression to map SQL data types to validation types:
match_types => { qr(date) => \&my_date_checker, }
- debug
-
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. - strict
-
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).
Validating relationships
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.
- timestamp
-
The default behaviour is to skip validating
timestamp
columns. A warning will be issued if thedebug
parameter is set to 2. - Failures
-
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 callingas_form
. However, please email me with any failures so the hash can be updated for everyone.
Other features
- Pretty printing
-
If you load the module like so:
use Class::DBI::FormBuilder PrettyPrint => 'ALL';
form output will be indented for easier readability. This option requires HTML::TreeBuilder.
If you say:
use Class::DBI::FormBuilder PrettyPrint => 1;
output will only be indented if you ask for it:
print $form->render( PrettyPrint => 1 );
- Class::DBI::FromForm
-
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
andupdate_from_form
will instead be imported ascreate_from_fb
andupdate_from_fb
.You might want to do this if you have more complex validation requirements than CGI::FormBuilder provides.
METHODS
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.
- new_field_processor( $processor_name, $coderef or package name )
-
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 defaultTIMESTAMP
behaviour (seeform_timestamp
). The new processor must either be a coderef, or the name of a package with a suitablefield
method, or the name of another processor, or an arrayref of any of these.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. - column_meta( $them, $column, $key )
-
Class::DBI::FormBuilder class method.
Returns information about the specified column or columns.
$column
must either be the mutator accessor to the column, or a Class::DBI::Column object. The mutator accessor defaults to the column name, unless your class has amutator_name
method.$column
can also be an arrayref of the above.The following keys are available:
order # ordinal position of the column in the database type # column type # these return '1' and 'yes' for typeless databases (SQLite): nullable # 0 => no, 1 => yes, 2 => unknown is_nullable # no, yes, '' # these return undef for typeless databases (SQLite): default # default value of the column size digits # MySQL: mysql_values mysql_type_name
For typeless databases (SQLite),
type
returns whatever string the type was set to in the schema - so you might see things likeVARCHAR
,varchar
,varchar(255)
orVARCHAR(255)
etc.Otherwise
type
is the uppercase SQL type, i.e.VARCHAR
etc. - column_type( $them, $col )
-
Provides consistent output when using
column_meta
to query a column's type.$column
must either be the mutator accessor to the column, or a Class::DBI::Column object.Returns the type in lower case, with supefluous bits chopped off. So
VARCHAR(255)
is returned asvarchar
.For
has_many
and similar (e.g.might_have
) relationships, returns the type of the column in the related class.
Form generating methods
- form_builder_defaults( %args )
-
Stores default arguments for the call to
CGI::FormBuilder::new()
. - as_form( %args )
-
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()
, and will override any keys inform_builder_defaults
.Note that parameter merging is likely to become more sophisticated in future releases (probably copying the argument merging code from CGI::FormBuilder itself).
- search_form( %args )
-
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, andTEXT
columns are represented astext
fields rather than astextarea
s by default.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
.- search_opt_cmp
-
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'
- search_opt_order_by
-
If true, will generate a widget to select (possibly multiple) columns to order the results by, with an
ASC
andDESC
option for each column.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' ]
-
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 asas_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. -
By default, all related fields are shown in the form. To only expand selected related fields, list them in
show_related
.
-
Form modifiers
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.
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.
has_a
relationships to non-CDBI classes are handled via a plugin mechanism (see below).
-
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. - form_options
-
Identifies column types that should be represented as select, radiobutton or checkbox widgets. Currently only works for MySQL
ENUM
andSET
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. Haven't poked around yet to see how easily aSET
column can be emulated. - form_has_a
-
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 below - Plugins).
- form_has_many
-
Also assumes a single primary column.
- form_might_have
-
Also assumes a single primary column.
- form_timestamp
-
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 theDISABLED
processor, which sets the HTMLdisabled
attribute. This makes the field data un-selectable.If you prefer, you can replace the
TIMESTAMP
processor with one that points toREADONLY
instead. - form_text
-
Makes
TEXT
columns intotextarea
form fields. - form_file
-
Unimplemented - at the moment, you need to set the field type to
file
manually, or in theprocess_fields
argument, set the field processor toFILE
.Figures out if a column contains file data.
This method will probably go away at some point, unless somebody can show me how to automatically detect that a column stores binary data.
- form_process_extras
-
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.
Form handling methods
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!
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 2224:
=over without closing =back