/lib/HTML/FormHandler/Manual/Intro.pod
http://github.com/gshank/html-formhandler · Unknown · 289 lines · 208 code · 81 blank · 0 comment · 0 complexity · 48e1bb3e678aa9e0055662fba0804680 MD5 · raw file
- package HTML::FormHandler::Manual::Intro;
- # ABSTRACT: introduction to using FormHandler
- =head1 SYNOPSIS
- L<Manual Index|HTML::FormHandler::Manual>
- 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 L<HTML::FormHandler> for non-database forms,
- or a subclass of L<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
- C<< $form->value >>.
- A working example of a Catalyst app using FormHandler forms is available
- on github at L<https://github.com/gshank/formhandler-example>.
- =head1 Basics
- =head2 Create a form class
- 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 L<HTML::FormHandler::Manual::Fields> for
- more information.
- =head2 Or create a form class dynamically
- 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.
- =head2 Process the form
- 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 L<HTML::FormHandler>.
- =head2 Or process a database form
- A database form inherits from L<HTML::FormHandler::Model::DBIC> instead of
- L<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 L<HTML::FormHandler::Manual::Database> and
- L<HTML::FormHandler::TraitFor::Model::DBIC>.
- =head2 After processing the form
- 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
- C<< $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;
- =head2 Rendering the form
- At its simplest, all you need to do is C<< $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 C<< $form->fif >>.
- By default FormHandler structures fields (and renders them) 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 L<HTML::FormHandler::Manual::Rendering>.
- =head2 Defaults for form fields
- 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 L<HTML::FormHandler::Manual::Defaults>.
- =head2 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 L<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 L<HTML::FormHandler::Manual::Validation> for more information on
- validation or L<HTML::FormHandler::Manual::Fields> for more information
- on fields.
- =head2 Organizing your form code
- 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' => ( default => 'MyApp::Form::Field' );
- has_field 'compound1' => ( type => 'Complex' );
- has_field 'compound2' => ( type => 'Complex' );
- =head2 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 L<HTML::FormHandler::Manual::Testing> for more
- information.
- =head1 Localization
- FormHandler's built-in errors are added to the form fields with
- C<< $field->add_error >>, and to the form with C<< $form->add_form_error >>.
- These methods call a C<< $self->_localize >> method which is a coderef set from
- the field's default_localize sub, the field's 'localize_meth' attribute with
- C<< 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 L<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 C<< $field->push_errors >> or C<< $form->push_form_errors >>.
- See also L<HTML::FormHandler::TraitFor::I18N>.
- =head1 Performance
- 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).
- =cut