NAME

Form::Factory::Action - Role implemented by actions

VERSION

version 0.022

DESCRIPTION

This is the role implemented by all form actions. Rather than doing so directly, you should use Form::Factory::Processor as demonstrated in the "SYNOPSIS".

SYNOPSIS

package MyApp::Action::Foo;
use Form::Factory::Processor;

has_control bar => (
    type => 'text',
);

sub run {
    my $self = shift;

    # Do something...
}

ATTRIBUTES

All form actions have the following attributes.

form_interface

This is the Form::Factory::Interface that constructed this action. If you need to get at the implementation directly for some reason, here it is. This is mostly used by the action itself when calling the "render" and "consume" methods.

globals

This is a hash of extra parameters to keep with the form. Normally, these are saved with a call to "stash" and recovered with a call to "unstash".

results

This is a Form::Factory::Result::Gathered object that tracks the general success, failure, messages, and output from the execution of this action.

Actions delegate a number of methods to this object. See "RESULTS".

result

This is a Form::Factory::Result::Single used to record general outcome.

Actions delegate a number of methods to this object. See "RESULTS".

features

This is a list of Form::Factory::Feature objects used to modify the object. This will always contain the features that are attached to the class itself. Additional features may be added here.

controls

This is a hash of controls attached to this action. For every has_control line in the action class, there should be a matching control in this hash.

METHODS

stash

$action->stash($moniker);

Given a $moniker (a key under which to store the information related to this form), this will stash the form's stashable information under that name using the Form::Factory::Stasher associated with the "form_interface".

The globals, values of controls, and the results are stashed. This allows those values to be recovered across requests or between process calls or whatever the implementation requires.

unstash

$action->unstash($moniker);

Given a $moniker previously named in a call to "stash", it restores the previously stashed state. This is a no-op if nothing is stashed under this moniker.

clear

This method clears the stashable state of the action.

render

$action->render(%options);

Renders the form using the associated "form_interface". You may specify the following options:

controls

This is a list of control names to render. If not given, all controls will be rendered.

Any other options will be passed on to the "render_control" in Form::Factory::Interface method.

setup_and_render

$self->setup_and_render(%options);

This performs the most common steps to prepare for a render and render:

  1. Unstashes from the given moniker.

  2. Adds the given globals to the globals.

  3. Renders the action.

  4. Clears the results.

  5. Stashes what we've done back into the given moniker.

render_control

my $control = $action->render_control($name, \%options);

Creates and renders a one time control. This is mostly useful for attaching buttons to a form. The control is not added to the list of controls on the action and will not be processed later.

This method returns the control object that was just rendered.

consume

$action->consume(%options);

This consumes any input from user and places it into the controls of the form. You may pass the following options:

controls

This is a list of names of controls to consume. Any not listed here will not be consumed. If this option is missing, all control values are consumed.

Any additional options will be passed to the "consume_control" in Form::Factory::Interface method call.

consume_control

my $control = $action->consume_control($name, \%options, %params);

Consumes the value of a one time control. This is useful for testing to see if a form submitted using a one-time control has been submitted or not.

This method returns the control object that was consumed.

clean

$action->clean(%options);

Takes the values consumed from the user and cleans them up. For example, if you allow users to type in a phone number, this can be used to clear out any unwanted or incorrect punctuation and format the phone number properly.

This method runs through all the requested Form::Factory::Feature objects in "features" and runs the "clean" in Form::Factory::Feature method for each.

The following options are used:

controls

This is the list of controls to clean. If not given, all features will be run. If given, only the control-features (those implementing Form::Factory::Feature::Role::Control attached to the named controls) will be run. Any form-features or unlisted control-features will not be run.

check

$action->check(%options);

The check method is responsible for verifying the correctness of the input. It assumes that "clean" has already run.

It runs the "check" in Form::Factory::Feature method of all the selected "features" attached to the action. It also sets the is_valid flag to true if no errors have been recored yet or to false if they have.

The following options are used:

controls

This is the list of controls to check. If not given, all features will be run. If given, only the control-features (those implementing Form::Factory::Feature::Role::Control attached to the named controls) will be run. Any form-features or unlisted control-features will not be run.

process

$action->process;

This does nothing if the action did not validate.

In the case the action is valid, this will use "set_attributes_from_controls" to copy the control values to the action attributes, run the "pre_process" in Form::Factory::Feature methods for all form-features and control-features, call the "run" method, run the "post_process" in Form::Factory::Feature methods for all form-features and control-features, and set the is_success flag to true if no errors are recorded or false if there are.

consume_and_clean_and_check_and_process

This is a shortcut for taking all the usual workflow actions in a single call:

$action->consume(@_);
$action->clean;
$action->check
$action->process;

ROLE METHODS

This method must be implemented by any action implementation.

run

This is the method that actually does the work. It takes no arguments and is expected to return nothing. You should draw your input from the action attributes (not the controls) and report your results to "result".

HELPER METHODS

These methods are primarily intended for internal use.

set_attribute_from_control

Given the name of a control, this will copy the current value in the control to the attribute.

set_attributes_from_controls

This method is used by "process" to copy the values out of the controls into the form action attributes. This assumes that such a copy will work because the "clean" and "check" phases should have already run and passed without error.

gather_results

Gathers results for all the associated "controls" and "result" into "results". This is called just before deciding if the action has validated correctly or if the action has succeeded.

RESULTS

Actions are tied closely to Form::Factory::Results. As such, a number of methods are delegated to result classes.

The following methods are delegated to "results" in Form::Factory::Result::Gathered.

is_valid
is_success
is_failure
is_validated
is_outcome_known
all_messages
regular_messages
field_messages
info_messages
warning_messages
error_messages
regular_info_messages
regular_warning_messages
regular_error_messages
field_info_messages
field_warning_messages
field_error_messages
content

These methods are delegated to result in Form::Factory::Result::Single.

success
failure
add_message
info
warning
error
field_info
field_warning
field_error

WORKFLOW

TYPICAL CASE

The action workflow typically goes like this. There are two phases.

PHASE 1: SHOW THE FORM

Phase 1 is responsible for showing the form to the user. This phase might be skipped altogether in situations where automatic processing is taking place where the robot doing the work already knows what inputs are expected for the action. However, typically, you do something like this:

my $action = $interface->new_action('Foo');
$action->unstash('foo');
$action->render;
$action->render_control(button => {
    name  => 'submit',
    label => 'Do It',
});
$action->stash('foo');

This tells the interface that you want to prepare a form object for class "Foo."

The call to "unstash" then pulls in any state saved from the user's prior entry. This will cause any errors that occurred on a previous validation or process execution to show up (assuming that your interface does that work for you). This also means that any previously stashed values entered should reappear in the form so that a failure to save or something won't cause the field information to be lost forever.

The call to "render" causes all of the controls of the form to be rendered for input.

The call to "render_control" causes a button to appear in the form.

The call to "stash" returns the form's stashable information back to the stash, since "unstash" typically removes it.

PHASE 2: PROCESSING THE INPUT

Once the user has submitted the form, you will want to process the input and perform the action. This typically looks like this:

my $action = $interface->new_action('Foo');
$action->unstash('foo');
$action->consume_and_clean_and_check_and_process( request => $q->Vars );

if ($action->is_valid and $action->is_success) {
    # Go on to the next thing
}
else {
    $action->stash('foo');
    # Go render the form again and show the errors
}

We request an instance of the form again and then call "unstash" to recover any stashed setup. We then call the "consume_and_clean_and_check_and_process" method, which will consume all the input. Here we use something that looks like a CGI request for the source of input, but it should be whatever is appropriate to your environment and the Form::Factory::Interface implementation used.

At the end, we check to see if the action checked out and then that the "run" method ran without problems. If so, we can show the success page or the record view or whatever is appropriate after filling this form.

If there are errors, we should perform the rendering action for "PHASE 1: SHOW THE FORM" again after doing a "stash" to make sure the information is ready to be recovered.

VARATIONS

PER-CONTROL CLEANING AND CHECKING

Ajax or GUIs will generally want to give their feedback as early as possible. As such, whenever the user finishes entering a value or the application thinks that validation is needed, the app might perform:

$action->check( controls => [ qw( some_control ) ] );
$action->clean( controls => [ qw( some_control ) ] );

unless ($action->is_valid) {
    # Report $action->results->error_messages
}

You will still run the steps above, but can do a check and clean on a subset of controls when you need to do so to give the user early feedback.

AUTHOR

Andrew Sterling Hanenkamp <hanenkamp@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by Qubling Software LLC.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.