package Mojolicious::Plugin::ParamExpand;
use Mojo::Base 'Mojolicious::Plugin';
use CGI::Expand;
our $VERSION = '0.01';
sub register
{
my ($self, $app, $config) = @_;
my $class = 'Mojolicious::Plugin::ParamExpand::expander';
_make_package($class, $config);
$app->hook(before_dispatch => sub {
my $c = shift;
my $hash;
eval { $hash = $class->expand_hash($c->req->params->to_hash) };
if($@) {
$c->render_exception($@);
return;
}
$c->param($_ => $hash->{$_}) for keys %$hash;
});
}
sub _make_package
{
no strict 'refs';
my ($class, $config) = @_;
@{"${class}::ISA"} = 'CGI::Expand';
for(qw|max_array separator|) {
my $val = $config->{$_};
*{"${class}::$_"} = sub { $val } if defined $val;
}
}
1;
__END__
=pod
=head1 NAME
Mojolicious::Plugin::ParamExpand - Use objects and data structures in your forms
=head1 SYNOPSIS
# Mojolicious
$self->plugin('ParamExpand', %options);
# Mojolicious::Lite
plugin 'ParamExpand', %options;
# In your action
sub action
{
my $self = shift;
my $order = $self->param('order');
$order->{address};
$order->{items}->[0]->{id};
$order->{items}->[0]->{price};
# ...
}
=head1 DESCRIPTION
L<Mojolicious::Plugin::ParamExpand> turns request parameters into nested data
structures using L<CGI::Expand>.
=head1 MOJOLICIOUS VERSION
Due to the old way C<Mojolicious::Controller> handled multi-valued request parameters,
versions of Mojolicious B<less than> 2.52 will not work with this plugin. If this is a problem for
you try L<Mojolicious::Plugin::GroupedParams>.
=head1 OPTIONS
Options must be specified when loading the plugin.
=head2 separator
$self->plugin('ParamExpand', separator => ',')
The character used to separate the data structure's hierarchy in the
flattened parameter. Defaults to C<'.'>.
=head2 max_array
$self->plugin('ParamExpand', max_array => 10)
Maximum number of array elements C<CGI::Expand> will create.
Defaults to C<100>. If a parameter contains more than C<max_array>
elements an exception will be raised.
To force the array into a hash keyed by its indexes set this to C<0>.
=head1 Methods
=head2 param
This is just L<Mojolicious::Controller/param> but, when using C<Mojolicious::Plugin::ParamExpand>, a
request with the parameters
users.0.name=nameA&users.1.name=nameB&id=123
will return a nested data structure for the param C<'users'>
@users = $self->param('users');
$users[0]->{name};
$users[1]->{name};
Other parameters can be accessed as usual
$id = $self->param('id');
The flattened parameter name can also be used
$name0 = $self->param('users.0.name');
=head3 Arguments
C<$name>
The name of the parameter.
=head3 Returns
The value for the given parameter. If applicable it will be an expanded
data structure.
Top level arrays will be returned as arrays B<not> as array references.
This is how C<Mojolicious> behaves. In other words
users.0=userA&users.1=userB
is equivlent to
users=userA&users=userB
If this is undesirable you could L<< set C<max_array> to zero|/max_array >>.
=head1 SEE ALSO
L<CGI::Expand>, L<Mojolicious::Plugin::GroupedParams>