NAME¶
HTML::FormHandler::Manual::Intro - introduction to using FormHandler
VERSION¶
version 0.40013
SYNOPSIS¶
Manual Index
HTML::FormHandler is a form handling package that validates HTML form data and,
for database forms, saves it to the database on validation. It has field
classes that match various data types and HTML form elements, and rendering
roles that can be used to render forms in many different ways, from hand-built
forms to totally automated rendering. It can, of course, be used to validate
data even if you are not interested in the rendering capabilities.
A FormHandler 'form' is a Perl subclass of HTML::FormHandler for non-database
forms, or a subclass of HTML::FormHandler::Model::DBIC for database forms, and
in it you define your fields and validation routines. Because it's a Perl
class written in Moose, you have a lot of flexibility and control.
You can validate with Perl methods or Moose type constraints; you can use your
own validation libraries. You can define your own field classes that perform
specialized validation.
When the form is validated, you can get the validated values back with
"$form->value".
A working example of a Catalyst app using FormHandler forms is available on
github at
https://github.com/gshank/formhandler-example
<
https://github.com/gshank/formhandler-example>.
Basics¶
The most common way of using FormHandler is to create a form package. You must
'use' "HTML::FormHandler::Moose" and 'extend' FormHandler:
package MyApp::Form::Sample;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
Then you add some fields with 'has_field', and a field 'type' (the short name of
the field package). (Fields with no type have type 'Text'.)
has_field 'foo';
has_field 'bar' => ( type => 'Select' );
Basic field types are Text, Select, Checkbox, Submit, Hidden, Reset, Textarea,
Password, Upload. See HTML::FormHandler::Manual::Fields for more information.
You can also create a form class 'dynamically', by creating a 'new'
HTML::FormHandler object. Use a 'field_list' parameter to create the fields
instead of 'has_field'.
my $form = HTML::FormHandler->new( field_list => [
'username' => { type => 'Text' },
'selections' => { type => 'Select' },
]
);
Some features will not be available using this method (like the automatic use of
'validate_<field_name>' methods) and it's not as easy to test, of
course.
The form's 'process' method should be run on each request, passing in the
request parameters:
$form->process( params => $c->request->body_parameters,
action => $action,
);
If the parameters are not empty, then validation will be performed. The
corollary is that you should not pass in extra parameters when the form has
not been posted. A special 'posted' flag can be used if the form consists
entirely of fields like checkboxes that do not include names in params if
unchecked, and also works to prevent validation from being performed if there
are extra params:
$form->process( posted => ( $c->req->method eq 'POST' ),
params => $c->request->parameters, action => $action );
There is an alternative method for processing the form, which is sometimes
preferred for persistent forms. It returns a 'result' object, and clears the
form:
my $result = $form->run( params => $c->request->body_parameters );
You can also set most other FormHandler attributes on the 'process' call., One
useful feature is that you can activate or inactivate fields:
$form->process( params => $params, active => ['field1', 'field2'] );
See also HTML::FormHandler.
A database form inherits from HTML::FormHandler::Model::DBIC instead of
HTML::FormHandler. You must either pass in the DBIC row object or give
FormHandler information to retrieve the row object.
$form->process( item => $row, params => $params );
-- or --
$form->process( item_id => $id, schema => $schema,
item_class => 'MyRow', params => $params );
'item_class' is often set in the form class.
See also HTML::FormHandler::Manual::Database and
HTML::FormHandler::TraitFor::Model::DBIC.
A database form will have saved the data or created a new row, so often no more
processing is necessary. You can get the structured field values from
"$form->value", and do whatever you want with them.
If the validation succeeded, you may want to redirect:
$form->process( params => $params );
return unless $form->validated
$c->res->redirect( .... );
-- or --
return unless $form->process( params => params );
$c->res->redirect;
At its simplest, all you need to do is "$form->render" in a
template.
[% form.render %]
The automatic rendering is powerful and flexible -- you can do almost anything
with the right settings. Or you can render the form with a template.
The form object will give you a hashref of values suitable for filling in the
form with "$form->fif".
By default FormHandler structures fields (and renders thems) in a way that
matches the database. If you want to organize the rendering output in
different ways, you can use blocks to organize your fields.
has_block 'fieldset1' => ( render_list => ['foo', 'bar'] );
For more rendering info, see HTML::FormHandler::Manual::Rendering.
The simplest way to provide defaults is by setting the default attribute in a
field definition:
has_field 'my_foo' => ( default => 'my_foo' );
The database row ('item') that is passed in will provide initial values for the
form, of course. You can also provide default values with an 'init_object',
which acts kind of like a database object:
$form->process( init_object => { foo => '...', bar => '...' } );
There are a number of other flags and methods for providing defaults. See
HTML::FormHandler::Manual::Defaults.
Validation¶
You can validate a field with a method in the form
'validate_<field_name>':
has_field 'foo';
sub validate_foo {
my ( $self, $field ) = @_; # self is the form
unless( $field->value == .... ) {
$field->add_error( .... );
}
}
You can provide a validation coderef that will be a field method:
has_field 'foo' => ( validate_method => \&check_foo );
sub check_foo {
my $self = shift; # self is field
unless( $self->value == ... ) {
$self->add_error( ... );
}
}
You can use 'apply' to use Moose types for validation, from
HTML::FormHandler::Types or another Moose type collection:
use HTML::FormHandler::Types ('NotAllDigits');
...
has_field 'my_field' => ( apply => [NotAllDigits] );
Or create validators with check:
has_field 'quux' => (
apply => [ { check => qr/abc/, message => 'Not a valid quux' } ] );
Or use a validate coderef:
has_field 'foo' => ( validate_method => \&check_foo );
sub check_foo {
my $self = shift;
if ( $self->value =~ s/..../ ) {
$self->add_error('....');
}
}
You can also create custom fields with custom validation, or use an existing
field that does the validation you need.
See HTML::FormHandler::Manual::Validation for more information on validation or
HTML::FormHandler::Manual::Fields for more information on fields.
You can use 'has_field' and 'has_block' in Moose roles:
package MyApp::Form::Role::Address;
use HTML::FormHandler::Moose::Role;
has_field 'foo';
has_block 'bar';
Your forms can inherit from base classes that set common application defaults.
You can override field definitions with '+'.
You can create 'compound' fields and include them in a form:
package MyApp::Form::Field::Complex;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Field::Compound';
has_field 'field1' => ( validate_method => \&validate_field1 );
has_field 'field2' => ( type => 'Select',
options_method => \&options_field2 );
sub validate_field1 { ... }
sub options_field2 { ... }
...
package MyApp::Form::Complex;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
has '+field_name_space' => ( sub => {['MyApp::Form::Field']} );
has_field 'compound1' => ( type => 'Complex' );
has_field 'compound2' => ( type => 'Complex' );
Testing¶
It's much easier to write unit tests for FormHandler forms than for Catalyst
controllers. The 't' directory of the downloaded distribution has lots of
examples. See HTML::FormHandler::Manual::Testing for more information.
Localization¶
FormHandler's built-in errors are added to the form fields with
"$field->add_error", and to the form with
"$form->add_form_error". These methods call a
"$self->_localize" method which is a coderef set from the field's
default_localize sub, the field's 'localize_meth' attribute with
"localize_meth => sub {}", or a form's sub localize_meth. The
default localize uses Locale::Maketext. You can also use duck_type classes for
localization. See the documentation in HTML::FormHandler::TraitFor::I18N and
the tests in xt/locale.t.
If you wish to skip localization for a particular message (such as for system
errors) you can use "$field->push_errors" or
"$form->push_form_errors".
See also HTML::FormHandler::TraitFor::I18N.
FormHandler makes heavy use of Moose, so almost all of FormHandler's profiled
time will actually be in Moose methods, mostly constructing form and field
attributes. Some people prefer to use a persistent form class (in a Moose
attribute) in order to skip the form building step on each call. Other people
don't like that solution because state will remain in the form until the next
process call. The 'clear' method is called at the beginning of each 'process',
but additional Moose attributes in the form, etc, will have to cleared by the
programmer.
If you are loading options from the database and you don't need to have them
refreshed each time, you can set the 'do_not_reload' flag in the
Select/Multiple field. If you're not using the field widget roles, you can set
the 'no_widgets' flag. If you always use 'process' on each call (recommended)
then you can set the 'no_preload' flag in the form to skip building results in
BUILD (new).
AUTHOR¶
FormHandler Contributors - see HTML::FormHandler
COPYRIGHT AND LICENSE¶
This software is copyright (c) 2012 by Gerda Shank.
This is free software; you can redistribute it and/or modify it under the same
terms as the Perl 5 programming language system itself.