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 )