Skip to content
Browse files

has_field and documentation updates

  • Loading branch information...
1 parent 7cd4631 commit 8896fd411a311aab13c22bc6fcff0030911c1762 @gshank gshank committed
View
2 META.yml
@@ -31,4 +31,4 @@ requires:
perl: 5.8.0
resources:
license: http://dev.perl.org/licenses/
-version: 0.08
+version: 0.09
View
171 lib/HTML/FormHandler.pm
@@ -18,16 +18,16 @@ HTML::FormHandler - form handler written in Moose
=head1 SYNOPSIS
-This package should currently be considered unstable since I am actively making
-changes and improvements.
+This package is currently unstable since I am actively making changes and
+improvements.
HTML::FormHandler is based on L<Form::Processor>. The original goal was just
to make a Moose version of Form::Processor, but there were issues in maintaining
compatibility between the non-Moose and Moose versions. Although very similar to
L<Form::Processor>, FormHandler does not intend to be compatible. A substantial
number of methods and attributes have been renamed for internal
-consistency and consistency with Moose usage, and some refactoring has
-been done.
+consistency and consistency with Moose usage, the code has been refactored,
+and features have been added.
HTML::FormHandler allows you to define HTML form fields and validators, and will
automatically update or create rows in a database, although it can also be
@@ -71,28 +71,24 @@ An example of a form class:
package MyApp::Form::User;
- use Moose;
+ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';
has '+item_class' => ( default => 'User' );
- sub profile {
- return {
- fields => [
- name => 'Text',
- age => 'PosInteger',
- birthdate => 'DateTime',
- hobbies => 'Multiple',
- address => 'Text',
- city => 'Text',
- state => 'Select',
- email => 'Email',
- ],
- dependency => [
- ['address', 'city', 'state'],
- ],
- ];
- }
+ has_field 'name' => ( type => 'Text' );
+ has_field 'age' => ( type => 'PosInteger' );
+ has_field 'birthdate' => ( type => 'DateTime' );
+ has_field 'hobbies' => ( type => 'Multiple' );
+ has_field 'address' => ( type => 'Text' );
+ has_field 'city' => ( type => 'Text' );
+ has_field 'state' => ( type => 'Select' );
+ has_field 'email' => ( type => 'Email' );
+
+ has '+dependency' => ( default => sub {
+ [ ['address', 'city', 'state'], ]
+ }
+ );
sub validate_age {
my ( $self, $field ) = @_;
@@ -100,13 +96,15 @@ An example of a form class:
if $field->value < 18;
}
+ no HTML::FormHandler::Moose;
1;
-A dynamic form may be created in a controller:
+A dynamic form may be created in a controller using the field_list
+attribute to set fields:
- $c->stash->{form} = HTML::FormHandler->new(
+ my $form = HTML::FormHandler->new(
item => $user,
- profile => {
+ field_list => {
fields => {
first_name => 'Text',
last_name => 'Text'
@@ -138,22 +136,67 @@ L<HTML::FormHandler::Manual>.
=head1 ATTRIBUTES
-=head2 profile
+=head2 has_field
+
+This is not actually a Moose attribute. It is just sugar to allow the
+declarative specification of fields. It will not create accessors for the
+fields. The 'type' is not a Moose type, but an L<HTML::FormHandler::Field>
+type. To use this sugar, you must do
+
+ use HTML::FormHandler::Moose;
+
+instead of C< use Moose; >. Don't forget C< no HTML::FormHandler::Moose; > at
+the end of the package. Use the syntax:
+
+ has_field 'title' => ( type => 'Text', required => 1 );
+ has_field 'authors' => ( type => 'Select' );
+
+instead of:
+
+ has '+field_list' => ( default => sub { {
+ fields => {
+ title => {
+ type => 'Text',
+ required => 1,
+ },
+ authors => 'Select',
+ }
+ }
+ }
+ );
+
+or:
+
+ sub field_list {
+ return {
+ fields => {
+ title => {
+ type => 'Text',
+ required => 1,
+ },
+ authors => 'Select',
+ }
+ }
+ }
+
+Fields specified in a field_list will overwrite fields specified with 'has_field',
+
+
+=head2 field_list
A hashref of field definitions.
-The possible keys in the profile hashref are:
+The possible keys in the field_list hashref are:
required
optional
fields
auto_required
auto_optional
- dependency
-Example of a profile hashref:
+Example of a field_list hashref:
- my $profile => {
+ my $field_list => {
fields => [
field_one => {
type => 'Text',
@@ -163,25 +206,17 @@ Example of a profile hashref:
],
};
-For the "auto" profile keys, provide a list of field names.
+For the "auto" field_list keys, provide a list of field names.
The field types will be determined by calling 'guess_field_type'
in the model.
auto_required => ['name', 'age', 'sex', 'birthdate'],
auto_optional => ['hobbies', 'address', 'city', 'state'],
-The "dependency" profile key is an arrayref of arrayrefs that contain a
-list of fields where if one is entered, all fields are required.
-
- dependency => [
- ['address', 'city', 'state', 'zip'],
- ['cc_no', 'cc_expires'],
- ]
-
=cut
-has 'profile' => ( isa => 'HashRef', is => 'rw', default => sub { {} } );
+has 'field_list' => ( isa => 'HashRef', is => 'rw', default => sub { {} } );
=head2 name
@@ -203,7 +238,7 @@ has 'name' => (
=head2 name_prefix
-Prefix used for all field names listed in profile when creating
+Prefix used for all field names 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
@@ -310,7 +345,7 @@ Place to store application context
=cut
-has 'ctx' => ( is => 'rw' );
+has 'ctx' => ( is => 'rw', weak_ref => 1 );
=head2 language_handle, build_language_handle
@@ -406,7 +441,7 @@ has 'params' => (
=head2 fields
-The field definitions as built from the profile. This is a
+The field definitions as built from the field_list. This is a
MooseX::AttributeHelpers::Collection::Array, and provides
clear_fields, add_field, remove_last_field, num_fields,
has_fields, and set_field_at methods.
@@ -431,7 +466,7 @@ has 'fields' => (
=head2 required
-Array of fields that are required
+Array of fields that are required. Used for internal processing.
=cut
@@ -447,6 +482,20 @@ has 'required' => (
}
);
+=head2 dependency
+
+Arrayref of arrayrefs of fields. If one of a group of fields has a
+value, then all of the group are set to 'required'.
+
+ has '+dependency' => ( default => sub { [
+ ['street', 'city', 'state', 'zip' ],] }
+ );
+
+
+=cut
+
+has 'dependency' => ( isa => 'ArrayRef', is => 'rw' );
+
=head2 parent_field
This value can be used to link a sub-form to the parent field.
@@ -485,10 +534,10 @@ The common attributes to be passed in to the constructor are:
item_id
item
- name
- name_prefix
- item_class
- profile
+ schema
+ item_class (often set in the form class)
+ dependency
+ field_list
init_object
Creating a form object:
@@ -497,7 +546,7 @@ Creating a form object:
item_id => $id,
item_class => 'User',
schema => $schema,
- profile => {
+ field_list => {
required => {
name => 'Text',
active => 'Boolean',
@@ -512,7 +561,7 @@ L<HTML::FormHandler::Model::DBIC>.
FormHandler forms are handled in two steps: 1) create with 'new',
2) handle with 'process' or 'update'. FormHandler doesn't
care whether most parameters are set on new or process or update,
-but a 'profile' argument should be passed in on 'new'.
+but a 'field_list' argument should be passed in on 'new'.
=head2 BUILD, BUILDARGS
@@ -521,7 +570,7 @@ These are called when the form object is first created (by Moose).
A single argument is an "item" parameter if it's a reference,
otherwise it's an "item_id".
-First BUILD calls the build_form method, which reads the profile and creates
+First BUILD calls the build_form method, which reads the field_list and creates
the fields object array.
Then 'init_from_object' is called to load each field's internal value
@@ -645,7 +694,7 @@ sub clear_state
=head2 clear_values
-Clears field value, input, errors. Form params.
+Clears field value, input, errors
=cut
@@ -662,7 +711,7 @@ sub clear_values
=head2 build_form
-This parses the form profile and creates the individual
+This parses the form field_list and creates the individual
field objects. It calls the make_field() method for each field.
=cut
@@ -670,16 +719,16 @@ field objects. It calls the make_field() method for each field.
sub build_form
{
my $self = shift;
-$DB::single=1;
- my $field_list = $self->meta->field_list;
- $self->_build_fields( $field_list, 0 ) if $field_list;
- my $profile = $self->profile;
+ my $meta_field_list = $self->meta->field_list;
+ $self->_build_fields( $meta_field_list, 0 ) if $meta_field_list;
+
+ my $field_list = $self->field_list;
for my $group ( 'required', 'optional', 'fields' )
{
my $required = $group eq 'required' ? 1 : 0;
- $self->_build_fields( $profile->{$group}, $required );
- my $auto_fields = $profile->{ 'auto_' . $group } || next;
+ $self->_build_fields( $field_list->{$group}, $required );
+ my $auto_fields = $field_list->{ 'auto_' . $group } || next;
$self->_build_fields( $auto_fields, $required, 'Auto' );
}
}
@@ -1128,7 +1177,7 @@ sub set_dependency
{
my $self = shift;
- my $depends = $self->profile->{dependency} || return;
+ my $depends = $self->dependency || return;
my $params = $self->params;
for my $group (@$depends)
{
@@ -1258,7 +1307,7 @@ sub uuid
Gerda Shank, gshank@cpan.org
-Based on the original source code of L<Form::Processor::Field> by Bill Moseley
+Based on the original source code of L<Form::Processor> by Bill Moseley
=head1 COPYRIGHT
View
26 lib/HTML/FormHandler/Field.pm
@@ -13,7 +13,7 @@ HTML::FormHandler::Field - Base class for HTML::FormHandler Fields
=head1 SYNOPSIS
Instances of Field subclasses are generally built by L<HTML::FormHandler>
-from the profile, but they can also be constructed using new.
+from the field_list, but they can also be constructed using new.
use HTML::FormHandler::Field::Text;
my $field = HTML::FormHandler::Field::Text->new( name => $name, ... );
@@ -30,7 +30,7 @@ In your custom field class:
=head1 DESCRIPTION
This is the base class for form fields. The 'type' of a field class
-is used in the FormHandler profile to identify which field class to
+is used in the FormHandler field_list or has_field to identify which field class to
load.
A number of field classes are provided by the distribution. The basic
@@ -259,7 +259,7 @@ rendering roles. Fields of different type can use the same
widget.
This attribute is set in the field classes, or in the fields
-defined in the profile.
+defined in the form.
Widget types for the provided field classes:
@@ -289,9 +289,9 @@ This is the field's order used for sorting errors and field lists.
See the "set_order" method and F::P method "sorted_fields".
The order field is set for the fields when the form is built, but
if the fields are defined with a hashref the order will not be defined.
-The "auto" and "fields" profile attributes will take an arrayref which
+The "auto" and "fields" field_list attributes will take an arrayref which
will preserve the order. If you explicitly set "order" on the fields
-in a profile, you should set it on all the fields, otherwise results
+in a field_list, you should set it on all the fields, otherwise results
will be unpredictable.
=cut
@@ -343,7 +343,7 @@ does not have 'options'.
The IntRange field uses this range to create a select list
with a range of integers.
-In a FormHandler profile:
+In a FormHandler field_list
age => {
type => 'Integer',
@@ -381,7 +381,7 @@ The field's 'value' will be formatted with two decimal places.
=cut
-has 'value_sprintf' => ( isa => 'Str|Undef', is => 'rw', default => undef );
+has 'value_sprintf' => ( isa => 'Str|Undef', is => 'rw' );
=head2 id, build_id
@@ -418,7 +418,7 @@ the C<$form->fif> and C<$field->fif> methods.
=cut
-has 'password' => ( isa => 'Bool', is => 'rw', default => 0 );
+has 'password' => ( isa => 'Bool', is => 'rw' );
=head2 writeonly
@@ -430,7 +430,7 @@ be used for columns that should only be written to the database on updates.
=cut
-has 'writeonly' => ( isa => 'Bool', is => 'rw', default => 0 );
+has 'writeonly' => ( isa => 'Bool', is => 'rw' );
=head2 clear
@@ -439,7 +439,7 @@ field. Validation is also not run on this field.
=cut
-has 'clear' => ( isa => 'Bool', is => 'rw', default => 0 );
+has 'clear' => ( isa => 'Bool', is => 'rw' );
=head2 disabled
@@ -452,8 +452,8 @@ in constructing HTML.
=cut
-has 'disabled' => ( isa => 'Bool', is => 'rw', default => '0' );
-has 'readonly' => ( isa => 'Bool', is => 'rw', default => '0' );
+has 'disabled' => ( isa => 'Bool', is => 'rw' );
+has 'readonly' => ( isa => 'Bool', is => 'rw' );
=head2 noupdate
@@ -465,7 +465,7 @@ written to the data store.
=cut
-has 'noupdate' => ( isa => 'Bool', is => 'rw', default => '0' );
+has 'noupdate' => ( isa => 'Bool', is => 'rw' );
=head2 errors
View
2 lib/HTML/FormHandler/Manual/Cookbook.pod
@@ -107,7 +107,7 @@ Then:
extends 'MyApp::Form::Base';
has 'title' => ( default => 'This page is an example of what to expect...' );
- has '+profile' => ( default => .... );
+ has '+field_list' => ( default => .... );
1;
And in the template:
View
167 lib/HTML/FormHandler/Manual/Intro.pod
@@ -1,6 +1,6 @@
=head1 NAME
-HTML::FormHandler::Intro - basic usage of FormHandler
+HTML::FormHandler::Manual::Intro - basic usage of FormHandler
=head1 SUMMARY
@@ -42,7 +42,7 @@ the form in an HTML page.
Create a Form, subclassed from HTML::FormHandler::Model::DBIC
package MyApp:Form::User;
- use Moose;
+ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';
# Associate this form with a DBIx::Class result class
@@ -54,48 +54,27 @@ Create a Form, subclassed from HTML::FormHandler::Model::DBIC
# Field names are usually column, accessor, or relationship names in your
# DBIx::Class result class. You can also have fields that don't exist
# in your result class.
- sub profile { # or: has '+profile' => ( default => ...)
- return {
- fields => {
- name => {
- type => 'Text',
- label => 'Username',
- required => 1,
- required_message => 'You must enter a username',
- noupdate => 1,
- unique => 1, # unique in db
- unique_message => 'That username is already taken'
- },
- age => {
- type => 'PosInteger',
- label => 'Age',
- required => 1,
- css_class => 'box', # not used by HF, for templates
- title => 'User age in years', # for templates
- widget => 'age_text', # allows selecting a particular
- # widget in your templates or in
- # a rendering role
- range_start => 18, # can't enter an age less than 18
- },
- sex => {
- type => 'Select',
- label => 'Gender',
- required => 1,
- },
- birthdate => '+MyApp::Field::Date', # customized field class
- hobbies => {
- type => 'Multiple',
- size => 5,
- },
- address => 'Text',
- city => 'Text',
- state => 'Select',
- },
- dependency => [
+ has_field 'name' => ( type => 'Text', label => 'Username, required => 1,
+ required_message => 'You must enter a username', unique => 1,
+ unique_message => 'That username is already taken' );
+ # the css_class, title, and widget attributes are for use in templates
+ has_field 'age' => ( type => 'PosInteger', required => 1, css_class => 'box',
+ title => 'User age in years', widget => 'age_text', range_start => 18 );
+ has_field 'sex' => ( type => 'Select', label => 'Gender', required => 1 );
+ # a customized field class
+ has_field 'birthdate => ( type => '+MyApp::Field::Date' );
+ has_field 'hobbies' => ( type => 'Multiple', size => 5 );
+ has_field 'address' => ( type => 'Text' );
+ has_field 'city' => ( type => 'Text' );
+ has_field 'state' => ( type => 'Select' );
+
+ has '+dependency' => ( default => sub {
+ [
['address', 'city', 'state'],
],
- };
+ }
+ );
In a template, for an input field:
@@ -241,26 +220,25 @@ The C<< $form->process >> or C<< $form->update >> methods will validate
the parameters and then update or create the database row object.
-=head1 The form profile
+=head1 The form field_list
Returns a hashref of field definitions.
-The possible keys in the profile hashref are:
+The possible keys in the field_list hashref are:
required
optional
fields
auto_required
auto_optional
- dependency
-The profile is the easiest way to define the fields in your form (though
+The field_list one way to define the fields in your form (though
you can also add fields individually).
You can categorize your fields as required and optional with two separate
hashrefs:
- my $profile => {
+ my $field_list => {
required => {
field_one => 'Text',
},
@@ -272,7 +250,7 @@ hashrefs:
Or you can use one hashref and indicate 'required' as yet another field
attribute:
- my $profile => {
+ my $field_list => {
fields => [
field_one => {
type => 'Text',
@@ -289,7 +267,7 @@ All other keys are attributes of L<HTML::FormHandler::Field> or its subclasses.
An example of a select field:
- my $profile = {
+ my $field_list = {
fields => {
favorite_color => {
type => 'Select',
@@ -309,7 +287,7 @@ The definition above is the equivalent of the following code:
$form->add_field( $field );
-For the "auto" profile keys, provide a list of field names.
+For the "auto" field_list keys, provide a list of field names.
The field types will be determined by calling 'guess_field_type'
in the model.
@@ -319,32 +297,13 @@ in the model.
The 'guess_field_type' method could be customized to provide more
sophisticated determination of types. See the model class.
-The 'dependency' profile key is an array of arrays of field names.
-During validation, if any field in a given group
-contains the pattern /\S/ (non-blank), the 'required' flag
-is set for all of the fields in the group.
-
- sub profile {
- return {
- fields => [
- name => 'Text',
- age => 'Integer',
- date => 'DateTime',
- comment => 'Text',
- ...
- ],
- dependency => [
- ['address', 'city', 'state', 'zip'],
- ['cc_no', 'cc_expires'],
- ],
- };
- }
=head1 Fields
-A form's fields are created from the definitions in the "profile" subroutine.
-FormHandler processes the profile and creates an array of
-L<HTML::FormHandler::Field> objects. The "type" of a field in the profile
+A form's fields are created from the 'has_field' and 'field_list'
+definitions.
+FormHandler processes the field lists and creates an array of
+L<HTML::FormHandler::Field> objects. The "type" of a field
determines which field class to use. The field class determines which
attributes are valid for a particular field. A number of field classes are
provided by FormHandler. You can customize the validation in your form on a
@@ -353,22 +312,8 @@ might be more easily handled in a custom field class.
Fields can also be added dynamically with the 'add_field' method.
-In the template the fields are accessed with form.field('name').
-Field errors are in $field->errors.
-
-Each form field is associated with a general type. The type name
-is used to load a module by that name:
-
- my $profile = {
- required => {
- title => 'Text',
- age => 'Integer',
- },
- };
-
-
-Type "Text" loads the HTML::FormHandler::Field::Text module and type
-'Integer' loads HTML::FormHandler::Field::Integer.
+In the template the fields are accessed with C< form.field('name') >.
+Field errors are in C<< $field->errors >>.
The fields are assumed to be in the HTML::FormHandler::Field name
space. If you want to explicitly list the field's package, prefix it
@@ -377,10 +322,8 @@ be set with the form's "field_name_space" attribute:
has '+field_name_space' => ( default => 'MyApp::Form::Field' );
- required => {
- name => 'Text', # HTML::FormHandler::Field::Text
- foo => '+Foo', # MyApp::Form::Field::Foo
- },
+ has_field 'name' => ( type => 'Text' ); # HTML::FormHandler::Field::Text
+ has_field 'foo' => ( type => +Foo' ); # MyApp::Form::Field::Foo
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.
@@ -405,6 +348,45 @@ By default, the validation is simply to copy the data from the "input" to the "v
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).
+=head1 Common form attributes
+
+The 'dependency' field_list key is an array of arrays of field names.
+During validation, if any field in a given group
+contains the pattern /\S/ (non-blank), the 'required' flag
+is set for all of the fields in the group.
+
+ has '+dependency' => ( default => sub {
+ [
+ ['address', 'city', 'state', 'zip'],
+ ['cc_no', 'cc_expires'],
+ ],
+ },
+ );
+
+The 'item_class':
+
+ has '+item_class' => ( default => 'Book' );
+
+The form name:
+
+ has '+name' => ( default => 'book_form' );
+
+The field name space for use with '+' prefixed fields:
+
+ has '+field_name_space' => ( default => 'MyApp::Form::Field' );
+ ...
+ has_field 'subname' => ( type => '+SubName' );
+
+An 'init_object' for filling in the form with default values instead of
+the database object. (To set individual field values use "init_value_$fieldname".)
+
+ has '+init_object' => ( default => sub {
+ { name => 'Choose name',
+ project => 'Standard'
+ }
+ }
+ );
+
=head1 Other methods for your form
=over 4
@@ -450,6 +432,7 @@ in the database.
return $item->license_id;
}
+
=item validate_$fieldname
Do per-field validation customization not handled by the Field class.
View
6 lib/HTML/FormHandler/Manual/Reference.pod
@@ -82,16 +82,16 @@ These attributes are usually accessed in a subroutine or in a template.
schema Schema of item
item DB row object
init_object For default values instead of $item
+ dependency Array of arrays of field names. If one name has a value, all
+ fields in the list are set to 'required'
-=head2 Form Profile attributes
+=head2 Form field_list attributes
fields Array (or hashref) of field definitions
required Hashref of 'required' fields
optional Hashref of non-required fields
auto_required Array of required field names (types from 'guess_field_type')
auto_optional Array of optional field names
- dependency Array of arrays of field names. If one name has a value, all
- fields in the list are set to 'required'
=head2 Other Form attributes
View
99 lib/HTML/FormHandler/Manual/Tutorial.pod
@@ -29,28 +29,22 @@ create the file Book.pm.
package MyApp::Form::Book;
- use Moose;
+ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';
has '+item_class' => ( default =>'Books' );
- sub profile {
- return {
- fields => {
- title => 'Text',
- rating => 'Integer',
- authors => {
- type => 'Multiple',
- label_column => 'last_name',
- },
- }
- }
- }
+ has_field 'title' => ( type => 'Text' );
+ has_field 'rating' => ( type => 'Integer' );
+ has_field 'authors' => ( type => 'Multiple', label_column => 'last_name' );
+
+ no HTML::FormHandler::Moose;
1;
This is your Form class. The form initializes the 'item_class' to the
source name of your DBIx::Class result class. The form's fields are defined
-in the 'profile' attribute. The names of the fields should match
-a column, relationship, or other accessor in your DBIx::Class result class.
+with the 'has_field' sugar, or in a 'field_list'. The names of the fields
+should match a column, relationship, or other accessor in your DBIx::Class
+result class.
The basic fields have only a 'type', such as
'Text', or 'Integer'. These types are actually the names of
@@ -109,8 +103,9 @@ schema.
=head2 Create a Template for the form
-L<HTML::FormHandler> doesn't provide a 'render' routine to automatically
-create the HTML for your forms (though you could create one of your own).
+L<HTML::FormHandler> provides only a simple sample 'render' routine to
+automatically create the HTML for your forms that you could use as
+a model for creating your own rendering routines.
You could also use TT macros to do pretty sophisticated
template generation. But for now, we'll stick to a straightforward TT
template:
@@ -204,36 +199,17 @@ character to the rating field. You should get an error message.
=head2 Add additional attributes to your form's fields
-Start by adding a 'label' attribute to the fields, replacing the
-simple type string with a hashref containing various attribute
-keys and values:
-
- sub profile {
- return {
- fields => {
- title => {
- type => 'Text',
- label => 'Title of Book',
- },
- rating => {
- type => 'Integer',
- label => 'Rating (1-5)',
- },
- authors => {
- type => 'Multiple',
- label_column => 'last_name',
- },
- }
- }
+We'll add a couple of 'label' attribute to the fields:
+
+ has_field 'title' => ( type => 'Text', label => 'Title of a Book' );
+ has_field 'rating' => ( type => 'Integer', label => 'Rating (1-5)' );
+ has_field 'authors' => ( type => 'Multiple', label_column => 'last_name' );
+
L<HTML::FormHandler> doesn't have built-in attributes for a submit button, but
if you want to put one in your form to use in a template, go ahead.
- sub submit {
- return {
- name => 'submit',
- value => 'Submit',
- }
+ has '+submit' => ( default => sub { { name => 'submit', value => 'Submit' }});
In a template, you could then access this with:
@@ -263,34 +239,15 @@ attribute for all your fields. Or use a Moose role instead of inheritance.
Now we'll add more validation to ensure that users
are entering correct data.
-Update the 'profile' subroutine in your MyApp::Form::Book file:
-
- sub profile {
- return {
- fields => {
- title => {
- type => 'Text',
- label => 'Title of Book',
- required => 1,
- size => 40,
- min_length => 5,
- },
- rating => {
- type => 'Integer',
- label => 'Rating',
- required => 1,
- required_message => 'You must rate the book',
- range_start => 1,
- range_end => 5,
- },
- authors => {
- type => 'Multiple',
- label_column => 'last_name',
- required => 1,
- },
- }
- }
- }
+Update the fields form file:
+
+ has_field 'title' => ( type => 'Text', label => 'Title of a Book',
+ required => 1, size => 40, min_length => 5 );
+ has_field 'rating' => ( type => 'Integer', label => 'Rating (1-5)',
+ required => 1, required_message => 'You must rate the book',
+ range_start => 1, range_end => 5 );
+ has_field 'authors' => ( type => 'Multiple', label_column => 'last_name',
+ required => 1 );
We've made all the fields required.
We added 'size' and 'min_length' attributes to the 'title' field. These
View
21 lib/HTML/FormHandler/Meta/Class.pm
@@ -3,7 +3,28 @@ package # hide from Pause
use Moose;
extends 'Moose::Meta::Class';
+=head1 NAME
+
+HTML::FormHandler::Meta::Class
+
+=head1 SYNOPSIS
+
+Adds a 'field_list' meta attribute for handling 'has_field'
+
+=cut
+
has 'field_list' => ( is => 'rw' );
+=head1 AUTHOR
+
+Gerda Shank, gshank@cpan.org
+
+=head1 COPYRIGHT
+
+This library is free software, you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut
+
no Moose;
1;
View
4 lib/HTML/FormHandler/Model.pm
@@ -151,7 +151,7 @@ sub init_value
=head2 validate_model
-Validates profile items that are dependent on the model.
+Validates fields that are dependent on the model.
This is called via the validation process and the model class
must at least validate "unique" constraints defined in the form
class.
@@ -179,7 +179,7 @@ sub clear_model { }
Gerda Shank, gshank@cpan.org
-Based on the original source code of L<Form::Processor::Field> by Bill Moseley
+Based on the original source code of L<Form::Processor::Model> by Bill Moseley
=head1 COPYRIGHT
View
12 lib/HTML/FormHandler/Model/CDBI.pm
@@ -22,9 +22,7 @@ HTML::FormHandler::Model::CDBI - Class::DBI model class for HTML::FormHandler
has '+item_class' => ( default => 'MyDB::User' );
# Define the fields that this form will operate on
- sub profile {
- my $self = shift;
-
+ sub field_list {
return {
fields => [
name => 'Text',
@@ -247,7 +245,7 @@ sub init_value {
=head2 validate_model
-Validates profile items that are dependent on the model.
+Validates fields that are dependent on the model.
Currently, "unique" fields are checked to make sure they are unique.
This validation happens after other form validation. The form already has any
@@ -271,9 +269,7 @@ Checks that the value for the field is not currently in the database.
sub validate_unique {
my ($self) = @_;
- my $unique_from_profile = $self->profile->{unique};
- my @unique_from_fields = map { $_->name } grep { $_->unique } $self->fields;
- my @unique = ( @$unique_from_profile, @unique_from_fields );
+ my @unique = map { $_->name } grep { $_->unique } $self->fields;
return 1 unless @unique;
my $item = $self->item;
@@ -410,7 +406,7 @@ sub obj_key {
Gerda Shank, gshank@cpan.org
-Based on the original source code of L<Form::Processor::Field> by Bill Moseley
+Based on the original source code of L<Form::Processor::Model::CDBI> by Bill Moseley
=head1 COPYRIGHT
View
2 lib/HTML/FormHandler/Model/DBIC.pm
@@ -39,7 +39,7 @@ To use FormHandler to create new database records, pass in undef for the item_id
and supply an 'item_class' and 'schema', or pass in an empty row (using
the resultset 'new_result' method).
-The field names in the profile of your form should match column, relationship,
+The field names in the field_list of your form should match column, relationship,
or accessor names in your DBIx::Class result source.
=head1 DESCRIPTION
View
28 lib/HTML/FormHandler/Moose.pm
@@ -4,6 +4,23 @@ package # hide from Pause
use Moose;
use HTML::FormHandler::Meta::Class;
+=head1 NAME
+
+HTML::FormHandler::Moose - to add FormHandler sugar
+
+=head1 SYNOPSIS
+
+ package MyApp::Form::Foo;
+
+ use HTML::FormHandler::Moose;
+
+ < define form>
+
+ no HTML::FormHandler::Moose;
+ 1;
+
+=cut
+
Moose::Exporter->setup_import_methods(
with_caller => [ 'has_field' ],
also => 'Moose',
@@ -25,4 +42,15 @@ sub has_field
$list = $caller->meta->field_list;
}
+=head1 AUTHOR
+
+Gerda Shank, gshank@cpan.org
+
+=head1 COPYRIGHT
+
+This library is free software, you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut
+
1;
View
2 t/Field/password.t
@@ -66,7 +66,7 @@ use strict;
use warnings;
use base 'HTML::FormHandler';
-sub profile {
+sub field_list {
return {
optional => {
login => 'Text',
View
2 t/auto_fields.t
@@ -22,7 +22,7 @@ ok($schema, 'get schema');
has '+item_class' => ( default => 'Book' );
- sub profile {
+ sub field_list {
return {
auto_required => ['title', 'author', 'isbn', 'publisher'],
auto_optional => ['genres', 'format', 'year', 'pages'],
View
2 t/bad_item_id.t
@@ -24,7 +24,7 @@ $record->delete if $record;
has '+item_class' => ( default => 'Book' );
- sub profile {
+ sub field_list {
return {
fields => [
title => {
View
BIN t/db/book.db
Binary file not shown.
View
36 t/dependency.t
@@ -4,30 +4,26 @@ use DateTime;
{
package My::Form;
- use Moose;
+ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
- sub profile {
- return {
- required => {
- name => 'Text',
- age => 'Integer',
- },
- optional => {
- comment => 'Text',
- address => 'Text',
- city => 'Text',
- state => 'Text',
- zip => 'Text',
- cc_no => 'Text',
- cc_expires => 'Text',
- },
- dependency => [
+ has_field 'name' => ( type => 'Text', required => 1 );
+ has_field 'age' => ( type => 'Integer', required => 1 );
+ has_field 'comment' => ( type => 'Text' );
+ has_field 'address' => ( type => 'Text' );
+ has_field 'city' => ( type => 'Text' );
+ has_field 'state' => ( type => 'Text' );
+ has_field 'zip' => ( type => 'Text' );
+ has_field 'cc_no' => ( type => 'Text' );
+ has_field 'cc_expires' => ( type => 'Text' );
+
+ has '+dependency' => ( default => sub {
+ [
[ 'address', 'city', 'state', 'zip' ],
[ 'cc_no', 'cc_expires' ],
- ],
- };
- }
+ ]
+ }
+ );
}
View
2 t/errors.t
@@ -9,7 +9,7 @@ use_ok( 'HTML::FormHandler' );
use Moose;
extends 'HTML::FormHandler';
has '+name' => ( default => 'testform_' );
- sub profile {
+ sub field_list {
return {
fields => {
reqname => {
View
2 t/field_counter.t
@@ -22,7 +22,7 @@ use strict;
use warnings;
use base 'HTML::FormHandler';
-sub profile {
+sub field_list {
return {
fields => {
field_one => 'Text',
View
2 t/form_handler.t
@@ -13,7 +13,7 @@ use_ok( 'HTML::FormHandler' );
has '+name' => ( default => 'testform_' );
- sub profile {
+ sub field_list {
return {
required => {
reqname => 'Text',
View
16 t/init_object.t
@@ -15,22 +15,13 @@ my $schema = BookDB::Schema::DB->connect('dbi:SQLite:t/db/book.db');
{
package My::Form;
- use Moose;
+ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';
has '+item_class' => ( default => 'Book' );
- sub profile {
- return {
- fields => [
- title => {
- type => 'Text',
- required => 1,
- },
- author => 'Text',
- ],
- };
- }
+ has_field 'title' => ( type => 'Text', required => 1 );
+ has_field 'author' => ( type => 'Text' );
sub init_value_author
{
@@ -68,4 +59,3 @@ is( $book->title, 'We Love to Test Perl Form Processors', 'title updated');
$book->delete;
-#------------------------
View
2 t/lib/BookDB/Form/Book.pm
@@ -20,7 +20,7 @@ Catalyst Form.
has '+item_class' => ( default => 'Book' );
-sub profile {
+sub field_list {
my $self = shift;
return {
View
4 t/lib/BookDB/Form/BookAuto.pm
@@ -22,9 +22,7 @@ has '+name_prefix' => ( default => 'book' );
__PACKAGE__->meta->make_immutable;
-sub profile {
- my $self = shift;
-
+sub field_list {
return {
auto_required => ['title', 'author', 'isbn', 'publisher'],
auto_optional => ['genres', 'format', 'year', 'pages'],
View
2 t/lib/BookDB/Form/BookHTML.pm
@@ -7,7 +7,7 @@ has '+item_class' => ( default => 'Book' );
has '+name' => ( default => 'book' );
has '+html_prefix' => ( default => 1 );
-sub profile {
+sub field_list {
return {
fields => [
title => {
View
2 t/lib/BookDB/Form/BookM2M.pm
@@ -19,7 +19,7 @@ Catalyst Form.
has '+item_class' => ( default => 'Book' );
-sub profile {
+sub field_list {
my $self = shift;
return {
View
2 t/lib/BookDB/Form/BookView.pm
@@ -7,7 +7,7 @@ use DateTime;
has '+item_class' => ( default => 'Book' );
-sub profile {
+sub field_list {
return {
required => {
borrower => 'Select',
View
2 t/lib/BookDB/Form/Borrower.pm
@@ -21,7 +21,7 @@ has '+name_prefix' => ( default => 'borrower' );
__PACKAGE__->meta->make_immutable;
-sub profile {
+sub field_list {
return {
fields => {
name => {
View
4 t/lib/BookDB/Form/Borrower.pm.auto
@@ -19,10 +19,10 @@ Catalyst Controller.
has '+item_class' => ( default => 'Borrower' );
-sub profile {
+sub field_list {
return {
auto_required => ['name', 'email'],
- auto_optional => ['phone', 'url'],
+ auto_optional => ['phone', 'url'],
};
}
View
2 t/lib/BookDB/Form/BorrowerX.pm
@@ -21,7 +21,7 @@ has '+name_prefix' => ( default => 'borrower' );
__PACKAGE__->meta->make_immutable;
-sub profile {
+sub field_list {
return {
fields => {
name => {
View
25 t/load_field.t
@@ -4,32 +4,19 @@ use lib 't/lib';
{
package My::Form;
- use Moose;
+ use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
# this form specifies the form name
#sub init_field_name_space { 'BookDB::Form::Field' }
has '+field_name_space' => ( default => 'BookDB::Form::Field' );
- sub profile {
- return {
- fields => {
- field_one => {
- type => '+AltText',
- another_attribute => 'one',
- },
- field_two => {
- type => '+AltText',
- another_attribute => 'two',
- },
- field_three => {
- type => '+AltText',
- another_attribute => 'three',
- },
- },
- };
- }
+ has_field 'field_one' => ( type => '+AltText', another_attribute => 'one' );
+ has_field 'field_two' => ( type => '+AltText', another_attribute => 'two' );
+ has_field 'field_three' => ( type => '+AltText', another_attribute => 'three' );
+
}
+
my $form = My::Form->new;
ok( $form, 'get form' );
View
4 t/model_dbic.t
@@ -21,7 +21,7 @@ ok($schema, 'get schema');
extends 'HTML::FormHandler::Model::DBIC';
has '+item_class' => ( default => 'Book' );
- has '+profile' => ( default => sub {
+ has '+field_list' => ( default => sub {
{
fields => [
title => {
@@ -52,7 +52,7 @@ ok( $author_field->order == 2, 'order for author');
use Moose;
extends 'HTML::FormHandler::Model::DBIC';
- has '+profile' => ( default => sub {
+ has '+field_list' => ( default => sub {
{
fields => [
title => {
View
4 t/multiple_forms.t
@@ -12,7 +12,7 @@ use_ok( 'HTML::FormHandler' );
has '+name' => ( default => 'One' );
has '+html_prefix' => ( default => 1 );
- sub profile {
+ sub field_list {
return {
fields => {
field_one => 'Text',
@@ -33,7 +33,7 @@ ok( $form1, 'get first form' );
# this form uses the default random form name generation
has '+html_prefix' => ( default => 1 );
- sub profile {
+ sub field_list {
return {
fields => {
field_one => 'Text',
View
2 t/order.t
@@ -8,7 +8,7 @@ use_ok( 'HTML::FormHandler' );
use Moose;
extends 'HTML::FormHandler';
- sub profile {
+ sub field_list {
return {
fields => [
field_one => 'Text',
View
2 t/render.t
@@ -9,7 +9,7 @@ use HTML::FormHandler::Field::Text;
extends 'HTML::FormHandler';
with 'HTML::FormHandler::Render::Simple';
- sub profile
+ sub field_list
{
return {
fields => {
View
2 t/unique.t
@@ -43,7 +43,7 @@ is( $errors[0], 'Duplicate value for ISBN', 'error message for duplicate');
has '+item_class' => ( default => 'Book' );
- sub profile {
+ sub field_list {
return {
fields => [
title => {
View
2 t/value_sprintf.t
@@ -8,7 +8,7 @@ use_ok( 'HTML::FormHandler' );
use Moose;
extends 'HTML::FormHandler';
- sub profile {
+ sub field_list {
return {
fields => {
price => {

0 comments on commit 8896fd4

Please sign in to comment.
Something went wrong with that request. Please try again.