NAME

Data::MuForm::Manual::Intro - introduction to using MuForm

VERSION

version 0.05

SYNOPSIS

Manual Index

Data::MuForm is a data validation and form handling package written in Moo. It is a conversion of FormHandler to Moo. The core behavior is the same, but things have been regularized, simplified and in some cases re-written. Rendering is substantially changed.

A MuForm 'validator' or 'form' is a Perl subclass of Data::MuForm. In your class you define fields and validators. Because it's a Perl class written with Moo, you have a lot of flexibility and control.

You can validate with Perl methods or Type::Tiny or Moose type constraints; you can use your own validation libraries. You can define your own field classes that perform specialized validation.

Basics

Create a validator/form class

The most common way of using MuForm is to create a new package. You must 'use' Moo and Data::MuForm::Meta and 'extend' MuForm.:

package MyApp::Form::Sample;
use Moo;
use Data::MuForm::Meta;
extends 'Data::MuForm';

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' );

For non-form validators there are field types such as Text, Integer, List, Compound, Float, Currency. For forms, common field types are Text, Select, Checkbox, Submit, Hidden, Reset, TextArea. See Data::MuForm::Manual::Fields for more information.

Or create a class dynamically

You can also create a class 'dynamically', by creating a 'new' Data::MuForm object. Use a 'field_list' parameter to create the fields instead of 'has_field'.

my $validator = Data::MuForm->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.

Process the form

The MuForm object's 'check' or 'process' method should be run on each request, passing in the data or request parameters:

$validator->check( data => { .... } );

$form->process( params => $c->request->body_parameters );

If the data or parameters are not empty, then validation will be performed.

You can set most other MuForm attributes on the 'process' call., One useful feature is that you can activate or inactivate fields:

$form->process( params => $params, active => ['field1', 'field2'] );

The return value of $form->process is the 'validated' flag, or the same as $form->validated.

See also Data::MuForm.

Or process a database form

A database form inherits from Data::MuForm::Model::DBIC instead of Data::MuForm. You pass in the DBIC row object on 'process':

$form->process( model => $row, params => $params );

The 'model' is used for defaults, unless it's a new_result row.

See also Data::MuForm::Manual::Database and Data::MuForm::Role::Model::DBIC.

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 $form->values, 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;

Rendering the form

At its simplest, all you need to do is $form->render in a template.

[% form.render %]

You can also easily render individual fields:

[% form.field('foo').render %]

or individual field elements:

[% form.field('foo').render_element({ class = 'mb20' }) %]

The form object will give you a hashref of values suitable for filling in the form with $form->fif.

For more rendering info, see Data::MuForm::Manual::Rendering.

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 ('model') that is passed in will provide initial values for the form, of course. You can also provide default values with an 'init_values', which acts kind of like a database object:

$form->process( init_values => { foo => '...', bar => '...' } );

There are a number of other flags and methods for providing defaults. See Data::MuForm::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' => ( methods => { validate => \&check_foo } );
  OR with shortcut
has_field 'foo' => ( 'meth.validate' => \&check_foo );
sub check_foo {
    my $self = shift; # self is field
    unless( $self->value == ... ) {
        $self->add_error( ... );
    }
}

You can use 'apply' to use Type::Tiny types for validation, from Data::MuForm::Types or another Type::Tiny or Moose type collection:

use Data::MuForm::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' } ] );

You can also create custom fields with custom validation, or use an existing field that does the validation you need.

See Data::MuForm::Manual::Validation for more information on validation or Data::MuForm::Manual::Fields for more information on fields.

Organizing your form code

You can use 'has_field' in Moo roles:

package MyApp::Form::Role::Address;
use Moo::Role;
use Data::MuForm::Meta;

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 Moo;
use Data::MuForm::Meta;
extends 'Data::MuForm::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 Moo;
use Data::MuForm::Meta;
extends 'Data::MuForm';

has '+field_name_space' => ( default => 'MyApp::Form::Field' );
has_field 'compound1' => ( type => 'Complex' );
has_field 'compound2' => ( type => 'Complex' );

Testing

It's much easier to write unit tests for MuForm forms than for Catalyst controllers. The 't' directory of the downloaded distribution has lots of examples. See Data::MuForm::Manual::Testing for more information.

Localization

MuForm's built-in errors are added to the form fields with $field->add_error, and to the form with $form->add_form_error.

If you wish to skip localization for a particular message (such as for system errors) you can use $field->push_error or $form->push_form_error.

See Data::MuForm::Localizer.

Performance

MuForm uses Moo, and is significantly faster than FormHandler on form creation. To make validation or form processing even faster, use a persistent form class in order to skip the object construction overhead. A 'clear' method is called at the beginning of each 'check' or process' call, but non-internal state added to the object will have to be cleared by the programmer.

AUTHOR

Gerda Shank

COPYRIGHT AND LICENSE

This software is copyright (c) 2018 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.