CGI-Application-Plugin-FormState

 view release on metacpan or  search on metacpan

lib/CGI/Application/Plugin/FormState.pm  view on Meta::CPAN



=head1 DESCRIPTION

C<CGI::Application::Plugin::FormState> provides a temporary storage area
within the user's session for storing form-related data.

The main use of this is for multi-page forms.  Instead of using hidden
fields to store data related to the form, you store and retrieve values
from the form state.

In the first instance of your app:

    $self->form_state->param('some_name' => 'some_value');
    $self->form_state->param('some_other_name' => 'some_other_value');

And later, in a different instance of your app:

    $val1 = $self->form_state->param('some_name');
    $val2 = $self->form_state->param('some_other_name');

To connect the first instance and the second, you put a single hidden
field in your template:

    <input type="hidden" name="cap_form_state" value="<tmpl_var my_storage_name>">

You don't have to worry about creating the template param
C<cap_form_state>; it is added automatically to your template
parameters via the C<load_tmpl> hook.

If you want to use a parameter other than C<cap_form_state> you can do
so via the C<name> parameter to C<form_state->config>.

If you're skeptical about whether all this abstraction is a good idea,
see L<"MOTIVATION">, below.

=head1 PRESERVING FORM STATE ACROSS REDIRECTS

You can include the form_state hash in a link:

    my $link = '/app.cgi?rm=list&cap_form_state=' . $self->form_state->id;

If you use L<CGI::Application::Plugin::Redirect>, you can easily create redirect this way:

    $self->redirect('/app.cgi?rm=list&cap_form_state=' . $self->form_state->id);

If you also use L<CGI::Application::Plugin::LinkIntegrity>
it is as simple as:

    $self->redirect($self->link('/app.cgi', 'rm' => 'list', 'cap_form_state' => $self->form_state->id));

Or, in the case of a link to the currently running app:

    $self->redirect($self->self_link('rm' => 'list', 'cap_form_state' => $self->form_state->id));


=head1 IMPLEMENTATION

When you call C<< $self->form_state >> for the first time, a top-level
key is created in the user's session.  This key contains a random,
hard-to-guess element.  It might look something like:

   form_state_cap_form_state_84eb13cfed01764d9c401219faa56d53

All data you place in the form state with C<param> is stored in the
user's session under this key.

You pass the name of this key on to the next instance of your
application by means of a hidden field in your form:

    <input type="hidden" name="cap_form_state" value="<tmpl_var cap_form_state>">

You manually put this hidden field in your template.  The template
parameter C<cap_form_state> is automatically added to your template
parameters via the C<load_tmpl> hook.  It contains the random,
hard-to-guess portion (e.g. C<84eb13cfed01764d9c401219faa56d53>).  When
the template is filled, the hidden field will look something like this:

    <input type="hidden" name="cap_form_state" value="84eb13cfed01764d9c401219faa56d53">

Since all values are stored on the server in the user's session, the
user can't tamper with any of them.

To keep old form_data from cluttering up the user's session, the system
uses L<CGI::Session>'s C<expire> feature to expire old form state keys
after a reasonable amount of time has passed (2 days by default).

You can manually delete a form state storage by calling:

    $self->form_state->delete;

=cut

sub _new {
    my ($class, $webapp) = @_;

    my $self = {
        '__CGIAPP_OBJ'   => $webapp,
        '__STORAGE_NAME' => undef,
        '__STORAGE_HASH' => undef,
        '__STORAGE_KEY'  => undef,
        '__EXPIRES'      => undef,
        '__CONFIGURED'   => undef,
    };

    # Force reference to CGI::Application object to be weak to avoid
    # circular references
    weaken($self->{'__CGIAPP_OBJ'});

    return bless $self, $class;
}

sub form_state {
    my ($self) = @_;

    # It's possible that in the future we will allow named configs, e.g.
    #    $self->form_state('foo')->param('bar);

    if (not exists $self->{$CGIAPP_Namespace}->{'__DEFAULT_CONFIG'}) {
        $self->{$CGIAPP_Namespace}->{'__DEFAULT_CONFIG'} = __PACKAGE__->_new($self);
    }
    return $self->{$CGIAPP_Namespace}->{'__DEFAULT_CONFIG'};
}

=head1 METHODS

=over 4

=item config(%options)

Sets defaults for the plugin.

B<Calling config is purely optional, since the defaults should be fine most purposes.>

    $self->form_state->config('name' => 'storage_names', 'expires' => '3d')

lib/CGI/Application/Plugin/FormState.pm  view on Meta::CPAN

        }
        else {
            $param = { @_ };
        }
        $store->{$_} = $param->{$_} for keys %$param;

        # A param has been changed, so we touch the session
        $webapp->session->param($storage_key => $store);
    }
    else {
        return keys %$store;
    }
}

=item clear_params

Clear all of the values in the form state storage:

   $self->form_state->param('name' => 'Road Runner');
   $self->form_state->clear_params;
   print $self->form_state->param('name'); # undef


=cut

sub clear_params {
    my $self = shift;

    if (!$self->{'__CONFIGURED'}) {
        $self->config;
    }
    my $storage_key = $self->{'__STORAGE_KEY'};

    my $webapp = $self->{__CGIAPP_OBJ};
    $webapp->session->param($storage_key => {});
}

=item delete

Deletes the form_state storage from the user's session.

=cut

sub delete {
    my $self = shift;

    # No need to call $self->config and create the session key since we're
    # just going to delete it.
    #
    # However, it's very important not to call session->clear without a key;
    # if we do, we'll delete all params in the user's session!

    if ($self->{'__STORAGE_KEY'}) {
        $self->{__CGIAPP_OBJ}->session->clear($self->{'__STORAGE_KEY'});
    }
}


=item id

Returns the current value of the storage param - the "hard to guess"
portion of the session key.

    my $id = $self->form_state->id;

=cut

sub id {
    my $self = shift;

    if (!$self->{'__CONFIGURED'}) {
        $self->config;
    }
    $self->{'__STORAGE_HASH'};
}

=item name

Returns the current name being used for storage.
Defaults to C<cap_form_state>.

    my $name = $self->form_state->name;

=cut

sub name {
    my $self = shift;

    if (!$self->{'__CONFIGURED'}) {
        $self->config;
    }
    $self->{'__STORAGE_NAME'};
}

=item session_key

Returns the full key used for storage in the user's session.

    my $key = $self->form_state->session_key;

    # Get the full form state hash
    my $data = $self->session->param($key);

The following can be used to debug the form_state data:

    use Data::Dumper;
    print STDERR Dumper $self->session->param($self->form_state->session_key);

=back

=cut

sub session_key {
    my $self = shift;

    if (!$self->{'__CONFIGURED'}) {
        $self->config;
    }
    $self->{'__STORAGE_KEY'};
}



( run in 1.550 second using v1.01-cache-2.11-cpan-39bf76dae61 )