NAME
Form::Processor - validate and process form data
SYNOPSIS
In an application you might want a controller to handle creating and updating a "User" record. And not want to write much code. Here's using Catalyst as an example:
package MyApplication::Controller::User;
use strict;
use MyApplication::Form::User;
sub edit : Local {
my ( $self, $c, $id ) = @_;
# Create the form object
my $form = MyApplication::Form::User->new( $id );
# Update or create the user record if form posted and form validates
$form->update_from_from( $c->request->parameters )
if $c->form_posted;
$c->stash->{form} = $form;
}
The above form class might then look like this:
package MyApplication::Form::User;
use strict;
use base 'Form::Processor::Model::CDBI';
sub object_class { 'DB::User' }
sub profile {
my $self = shift;
return {
required => {
name => 'Text',
age => 'PosInteger',
sex => 'Select',
birthdate => 'DateTimeDMYHM',
},
optional => {
hobbies => 'Multiple',
address => 'Text',
city => 'Text',
state => 'Select',
email => 'Email',
},
dependency => [
[qw/ address city state /],
],
};
}
sub options_sex {
return (
m => 'Male',
f => 'Female',
);
}
sub validate_age {
my ( $self, $field ) = @_;
$field->add_error('Sorry, you must be 18')
if $field->value < 18;
}
Or when you need a quick, small form do this in a controller:
my @fields = qw/ first_name last_name email /;
$c->stash->{form} = Form::Processor->new(
profile => {
required => {
map { $_ => 'Text' } qw/ first_name last_name email /,
},
},
);
DESCRIPTION
[Docs under construction -- editors welcome...]
This is a class for working with forms. A form acts as a layer between your internal data representation (such as a database) and the outside world (such as a web form). Moving data between these areas often requires validation and encoding or expanding of the data. For example, a date might be a timestamp internally but externally is a collection of year, month, day, hour, minute input fields.
A form is made up of a collection of fields of possibly different types (e.g. Text, Email, Integer, Date), where the fields require validation before being accepted into their internal format. The validation process is really made up of a number of steps, where each step can be overridden to customize the process.
Forms are (typically) defined by creating a separate Perl module that includes methods for defining the fields that make up the form, plus any special and additional validation checks on the fields.
Form::Processor does not generate any HTML. HTML should be generated in a "view" (and often using templates). And besides, HTML forms are trivial to create and in real life almost always needs customization. The use of a good template system makes this nearly painless.
Likewise, there is also no method to spit out an entire web form with a single method. Having a single method to generate a complete HTML form is often only useful for the most simple web forms.
This module is not restricted to use in a web environment, although that is the typical application. It was designed for use with Catalyst, Class::DBI, Template-Toolkit, and HTML::FillInForm. But, those are not required.
The design of this class is based a lot on the design of Rose::HTML::Objects, but, as mentioned, HTML widget generation is not part of the class. This class focuses more on moving data between the data store to the form that from the form to html. It's recommended that you look over Rose::HTML::Objects if not already done so.
The Form
As shown above in the synopsis, a "form" class is where a collection of "fields" are defined via a profile (that looks a lot like a Data::FormValidator profile). In general, the fields know how to validate input data, but the form class can also include additional validation methods for each field and can also cross-validate fields. The form class is what is used in your application code.
Fields
A form's "fields" are really small individual classes and they are often subclassed to make more specific classes with additional constraints. For example, an Integer field might be a subclass of the basic Text field that limits input values to digits. And a year field might be a subclass of an Integer field that limits the range of integer values.
It's recommended that you create new field classes for each specific type of data you have. That is, create a "DeptNumber" field that knows what a department number will look like instead of using a generic "Text" field and then validating that in your form. Save field validation in the form for validation that can't be done in a generic way (like validating that the department number actually exists by doing a database lookup).
Unlike Rose::HTML::Objects, this class does not generate (x)html. I prefer to leave that up to the view (templates). But there is a plan to add that ability via a plugin system for those that want it. I just find anything to do with HTML is better in the templates where it can be easily tweaked.
A method is provided to generate a hash of current values. This makes populating forms via HTML::FillInForm very easy. HTML::FillInForm is one of those modules that people either love or hate. I love it because it makes writing HTML forms in a very clean way (i.e. no extra code needed to populate the form widgets). It also makes it easy to populate forms in a number of different ways in your application, which an be handy.
Compound Fields
Rose::HTML::Objects is really nice (you should take a look), and one of its features is it handles compound fields -- fields that are made up of other fields such as a collection of fields that are used to specify a date and time. This class doesn't have compound fields, but there's nothing stopping you from defining a field that is made up of a form that includes multiple fields. See Form::Processor::Field::DateTimeDMYHM for an example of this. After all, a field's job is to take input from something and create an internal value. So, its input can be another form made up of multiple fields.
To help with this there's a "name_prefix" form setting that can be used to help with nested forms.
A form's model class
The base class for your forms is Form::Processor, and Form::Processor can be used on its own. But, the fun is when used with a "form model class" -- a class that knows how to work with your data objects.
For example, the SYNOPSIS uses Form::Processor::Model::CDBI for working with CDBI objects. When Form::Processor::Model::CDBI is used then valid options for a field are automatically pulled from the database by looking at the relationships set up in the CDBI classes. When working with an field that "has_a" relationship with another table, then possible options can be fetched from the other table. These options can then be displayed in a HTML select list. And when validating input, the field can check that the input matches one of the available options.
As shown in the SYNOPSIS above, when using a form model class complete controllers can be written in two lines of code. Here's the first line:
my $form = MyApplication::Form::User->new( $id );
That creates a form object. If $id is defined then the $id is fetched from the database for pre-populating the form. The fetched data object is stored in $form->item. A hash suitable for HTML::FillInForm is available in $form->fif (which can be used in a WRAPPER in Template-Toolkit or in the end() sub in Catalyst).
Then, the next line:
$form->update_from_from( $c->request->parameters )
if $c->form_posted;
If a form was posted then call $form->update_from_form. That method validates the parameters and then updates (or creates) the object. Link tables are also updated (e.g. a user "has_many" roles using a mapping/link table).
In the template the fields can be fetched with form.field('name'). Fields have an error method to return the error(s) found during validation. Methods on the form object can be used to tell if validation has run or if an object was updated or created. See Methods below.
More on fields
Each form field is associated with a general type. The type name is used to load a module by that name:
my $form = {
name => 'Text',
};
Type "Text" loads the Form::Processor::Field::Text module. The most basic type is "Text" which takes a single scalar value. A "Select" class is similar, but its value must be a valid choice from a list of options. A "Multiple" type is like "Select" but it allows selecting more than one value at a time.
Each field has a "value" method, which is the field's internal value. This is the value your database object would have (e.g. scalar, boolean 0 or 1, DateTime object). A field's internal value is converted to the external value by use of the field's format_value method. This method returns a hash which allows a single internal value to be made up of multiple fields externally. For example, a DateTime object internally might be formatted as a day, month, and year externally.
There's a form method called fif, that generates a hash of all the field's external values. This is quite useful for populating a form using HTML::FillInForm.
When data is passed in to validate the form, it is trimmed of leading and trailing whitespace by default and placed in the field's "input" attribute. Each field has a validate method that validates the input data and then moves it to the internal representation in the "value" attribute. Depending on the model, it's this internal value that is stored or used by your application.
By default, the validation is simply to copy the data from the "input" to the "value" field attribute, but you might have a field that must be converted from a text representation to an object (e.g. month, day, year to DateTIme).
METHODS
These are the methods that can be called on a form object. See Form::Processor::Field for methods called on individual fields within a form.
- name
-
Gets or set the form's name. This can be used to set the form's name when using multiple forms on the same page.
It's also prefixed to fields when asked for the field's id.
The default is form + a one to three digit random number.
sub name { 'useform' }
- profile
-
Returns the profile as a hashref as shown in the SYNOPSIS. This is the one method that you *must* override in your form class. This is what describes your form, after all.
The profile provides a concise and easy way to define the fields in your form. Fields can also be added individually to a form, but using a profile is the recommended and common approach.
Possible profile keys
- required
-
This points to a hash reference of field names as the keys and field types as the values. The field types are suffixes of the name space Form::Processor::Field:: and will be require()ed automatically. For example:
sub profile { return { required => { first_name => 'Text', roles => 'Multiple', }, }; }
causes Form::Processor::Field::Text and Form::Processor::Field::Multiple to be loaded and calls their new() method. See Form::Processor::Field for more information on the field types.
Each of these fields have their "required" attribute set true.
- optional
-
Like above, but listed fields are not set as required.
sub profile { return { required => { first_name => 'Text', roles => 'Multiple', }, optional => { age => 'Integer', } }; }
- auto_optional auto_required
-
This just make the above a bit easier.
This list an array of field names. The field types will try and be determined by various means (by calling $form->guess_field_type). For example, with Form::Processor::Model::CDBI it will look at the meta_info() to guess the field type.
auto_required => [qw/ name age sex birthdate /], auto_optional => [qw/ hobbies address city state /],
With CDBI, if it has a has_many relationship with another CDBI object it will be a Select (pick one from a set of options), where a has_many relationship would be a Multiple select.
Other methods might be used such as asking the DBI layer for the column type information, or maybe via a method in your object classes that returns the type for each column.
The hope is that the Form::Processor::Model:: classes can get smart about determining the field type.
- auto_all
-
*this method is not implemented*
If this is set then the value represents the method used to fetch all the field names from the object class.
auto_all => 'columns', # for cdbi objects
This is not implemented yet, but something like:
map { $_ => 'Auto' } $form->object_class->columns;
- dependency
-
This is an array of arrays of field names. During validation if any of the fields in a given group are found to contain the pattern /\S/ then they are considered non-blank and then *all* of the fields in group are set to required. This should work like DFV's dependency_groups profile entry.
sub profile { my @address_group = qw/ address city state zip /; my @credit_card_group = qw/ cc_no cc_expires /; return { required => { name => 'Text', age => 'Integer', date => 'DateTimeDMYHM', }, optional => { comment => 'Text', ... }, dependency => [ \@address_group, \@credit_card_group, ], }; }
This class doesn't have DFV's "dependencies" option at this time.
- unique
-
This is an array ref field names that should be unique in the data base. This feature depends on the model class being used.
- new PARAMS
-
New creates a new form object. The constructor takes name/value pairs:
MyForm->new( item => $item, item_id => $item->id, verbose => 1 );
Or, as is commonly done, only an item or item_id needs to be passed to the constructor. In this case a single parameter may be supplied:
MyForm->new( $id );
or
MyForm->new( $item );
If the value passed in is a reference then it is assumed to have and "id" method. So:
MyForm->new( $item_object );
is the same as:
MyForm->new( item => $item_object, item_id => $item_object->id, );
The constructor can accept the following parameters:
- item_id - the id of the object
-
The id (primary key) of the item (object) that the form is updating or has just created. The form's model class (e.g. Form::Processor::Model::CDBI) should have an init_item method that can fetch the object from the object_class for this id.
- item - the object itself
-
An existing object (i.e. the object that id points to). This can be passed in to the new constructor, but typically it's loaded by the form's model class by its init_item method.
- name
-
Name of the form. See the name method above.
- name_prefix
-
Prefix used for all field names listed in profile when creating each field. This is useful for creating compound form fields where a single field is made up of a collection of fields. The collection of fields can be a complete form. An example might be a field that represents a DateTime object, but is made up of separate day, month, and year fields.
- object_class
-
This defines the object class of the item (used by the form's model class to load, create, and update the object.
Typically, this would be defined as the "object_class" method in your form class, but can be specified in the constructor, for example, for small forms that do not use a form class (and specify the profile directly in the constructor -- see profile below).
- profile
-
This is useful for very short forms where you do not wish to define a subclass for your form.
my $form = = Form::Processor::Model::CDBI->new( item => $item, item_id => $id, object_class => $class, profile => { required => { name => 'Text', active => 'Boolean', }, }, );
- init_object
-
If init_object is supplied then it will be used instead of item to pre-populate the values in the form when init_from_object is called.
This can be useful when populating a form from default values stored in a similar but different object than the one the form is creating.
See init_from_object below.
The new() method will return false if the init() method returns false. Typically this would happen if passed in an invalid $id. You may override the init() method in your form class, but make sure you call
return unless $self->SUPER::init(@_);
from your method.
- clear
-
Clears out state information on the form. Normally this does not need to be called by external code. An exception might be if the form stays in memory between uses -- but that's not the idea quite yet
- init
-
This is called when the form object is first created. Parameters are passed unchanged from the new() call. This can be overridden in your form subclass if you can think of a reason to do so and are careful not to break everything.
Returning false causes new() to return false.
As mentioned in new() above, if a single option is passed then it's considered as a "item" parameter if it's a reference, otherwise it's considered an "item_id".
If an "item_id" is passed in (either as a single parameter or as a named parameter) the init method will return false if the item method returns false. (Calling the item method when item is undefined automatically calls the init_item method.) The init_item method is typically defined in the form's model class and should know how to translate an item_id into an item object. See "init_item" below.
So, the idea is you can pass in an item_id into the constructor and have the init_item method validate the item_id.
MyApp::Form->new( $id ) or return 'Invalid id supplied';
The init method calls the build_form method which reads the profile and creates the field objects. See that method for its magic.
The method init_from_object is called. This is typically specific to the type of form model used (e.g. CDBI) and is used to load each field's internal value from the object (which can then be used to populate the HTML form with $form->fif). init_from_object does nothing if no item_id (or item) is available. This would be the case when filling in a new blank form.
If an "init_object" is passed into the constructor then init_from_object will use this obeject (instead of "item") to load the initial field values. This is useful when initializing a form with values from another object.
Finally, the load_options method is called to load options for each field value used on multiple-choice fields. Typically, the form's model class will know how to load the options for each field by looking at the form's class relationships. See load_options below.
Again, this method will return false if an item_id is supplied and an item cannot be loaded from that id.
- build_form
-
This parses the form profile and creates the individual field objects. It calls the make_field() method for each field. See the profile() method above for details on the profile format.
For "Auto" field types it calls the guess_field_type() method with the field name as a parameter. Form model classes will override guess_field_type(), or you can override in your own form class. You might do that if your field names are labeled with their type -- "event_time" "age_int", etc. Although that would be an odd thing to do.
The above can also return an array reference.
- load_options
-
For all fields, if the field is a "Select" or "Multiple" (i.e. has an "options" method) then will call "options_$field_nane" if that method exists, otherwise will call the "lookup_options" method.
This should be called after $self->item is loaded because existing values may be needed in setting the valid options.
In general, "options_$field_name" would be defined in your form class, where "lookup_options" would be defined in the model form class and handle the more general case of looking up the available options in the database.
Here's an example of a method defined in your form's class to populate the "fruit" field with possible options:
sub options_fruit { return ( 1 => 'Apple', 2 => 'Grape', 3 => 'Cherry', ); }
- dump_fields
-
Dumps the fields of the form. For debugging.
- DESTROY
-
A form has a list of fields, but fields also have a reference to the parent form, so that circular linkage need to be removed before the form can be removed.
- make_field
-
Maps the field type to a field class, and returns the field by calling new() on that field class.
The fields are assumed to be in the Form::Processor::Field name space. If you want to explicitly list the field's package prefix it with a plus sign:
required => { name => 'Text', # Form::Processor::Field::Text foo => '+My::Field::Foo', },
- init_from_object
-
This method populates each field's value ($field->value) with either a scalar or an array ref from the object stored in $form->item. It does this by calling init_value() passing in the field object and $form->item. init_value() must return the value(s).
init_value() should be overridden in the form model subclass. For example, in ::Model::CDBI objects are expanded to primary keys for object methods that return a list of objects (e.g. has_many relationships).
If a method "init_value_$name" is found then that method is called instead. This allows overriding specific fields in your form class.
- params
-
Returns a hash of parameters. The parameters are initialized from the item (see init_params() below), or are the last set of parameters passed to the validate() function.
See also the fif() method.
- init_params
-
Calls each field's format_value() method to populate a parameters hash from each field's internal value. This is used to build a hash of all values in the form for use in populating the HTML form (using HTML::FillInForm). That has is returned by this method.
This method is called automatically when $form->params and params are not defiend. You may need to call this method directly if $form->item changes while the form object is in memory to force a refresh of params.
- clear
-
Clears the internal and external values of the form
- fif -- "fill in form"
-
Returns a hash of values suitable for use with HTML::FillInForm. It's a copy of $self->params with any passowrd fields removed.
- field NAME
-
Searches for field named "NAME". dies on not found. Useful for entering the wrong field.
my $field = $form->field('first_name');
Pass a second true value to not die on errors.
- exists
-
Returns true (the field) if the field exists
- validate
-
Validates the form from the CGI parameters passed in. The parameters must be a hash ref with multiple values as array refs.
Returns false if validation fails.
Note that this returns the cached validated result if $form->ran_validation is true. So to force a re-validation call $form->clear. This should only happen if the $form object stays in memory between requests.
For each field:
1) hash parameters are trimmed (override in field class) and saved to each field's "input" attribute. 2) dependency fields are set by setting fields to required if needed 3) validate_field is called for each field. This tests that required fields are not blank, and that only fields marked as multiple can include multiple values. For Selects and Multiple type fields the values must match existing options. If the above tests pass then the fields "validate" method is called. The validate method tests the input value (or values) and sets the field's input value based on the input data. The default validate method simply copies the input attribute to the value attribute: $field->value( $field->input ); 4) The form's validate_$fieldname is called, if the method exists AND if there's a value in the field. Use cross_validate if you need to validate fields that may be blank (such as setting defaults). 5) The models validation method is called, if exists. For example, this is used to check that a value is unique in the database.
Finally, after all fields have been processed:
6) The form's cross_validate is called. This allows access to all inflated values. This is called even if not all fields validated. This just makes it easier to do bulk validation where fields may be in common.
If you override validate() make sure you set the flag fields like the validate here does.
- cross_validate
-
This item can be overridden in the base class for the form. It's useful for cross checking *values* after they have been saved as their final validated value.
This method is called even if some fields did not validate.
- has_error
-
Returns true if validate has been called and the form did not validate.
- error_fields
-
Returns list of field with errors.
- error_field_name
-
Returns the names of the fields with errors.
- required_text
-
Returns either "required" or "optional" for the specified field.
Something like:
<div class="[% field.required_text %]">
- value
-
Short cut for:
$form->field($name)->value;
Can pass a second true value to avoid die on not found.
- value_changed
-
Returns true if the value in the item has changed from what is currently in the field's value.
This only does a string compare (arrays are sorted and joined). And note that:
'foo' != ['foo']
which is probably incorrect.
- uuid
-
Generates a hidden html field with a unique ID which the model class can use to check for duplicate form postings.
CREATING A MODEL CLASS
Form model classes are used to moved form data between a database and the form, typically via an object relational mapping tool (ORM).
See Form::Processor::Model for details.
THINGS TO WONDER ABOUT
The CGI parameters passed in are stored in Form::Processor instead of in each field object.
When a field is entered and then changed to a different format, what format should be displayed? That is, a form with a date is updated. The text "tomorrow" is entered. If the form doesn't validate what should display? The actual formatted date for tomorrow, or still the text "tomorrow"?
Currently, if the form doesn't validate "tomorrow" is displayed. But if the form validates (and is updated by the model class) then the form will display the formatted date for tomorrow. That still may be different from what the date might look like next time it's fetched from the database (due to timezone settings). Another way to go would be to re-load from the database object to make the date look like it will next time it's fetched on a fresh form.
Init from object happens in Form::Processor, too. It would be nice to have each field know how to initalize from the source object. But, that doesn't work well with overriding Form::Processor with the Model class.
AUTHOR
Bill Moseley - with *much* help from John Siracusa
LICENSE
This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself.
2 POD Errors
The following errors were encountered while parsing the POD:
- Around line 354:
You forgot a '=back' before '=head2'
- Around line 473:
'=item' outside of any '=over'