use Carp qw/croak carp shortmess/;
use Try::Tiny;
use Safe::Isa;
+use Moose::Util 'find_meta';
use Plack::Middleware::Conditional;
use Plack::Middleware::ReverseProxy;
use Plack::Middleware::IIS6ScriptNameFix;
use Plack::Middleware::IIS7KeepAliveFix;
use Plack::Middleware::LighttpdScriptNameFix;
use Plack::Util;
-use JSON::MaybeXS qw(decode_json);
+use Class::Load 'load_class';
BEGIN { require 5.008003; }
my %p = ( _log => $self->log );
$p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp;
$p{data_handlers} = {$self->registered_data_handlers};
+ $p{_use_hash_multivalue} = $self->config->{use_hash_multivalue_in_request}
+ if $self->config->{use_hash_multivalue_in_request};
\%p;
}
# Remember to update this in Catalyst::Runtime as well!
-our $VERSION = '5.90049_001';
+our $VERSION = '5.90049_004';
sub import {
my ( $class, @arguments ) = @_;
=head2 $c->forward( $class, $method, [, \@arguments ] )
-Forwards processing to another action, by its private name. If you give a
+This is one way of calling another action (method) in the same or
+a different controller. You can also use C<< $self->my_method($c, @args) >>
+in the same controller or C<< $c->controller('MyController')->my_method($c, @args) >>
+in a different controller.
+The main difference is that 'forward' uses some of the Catalyst request
+cycle overhead, including debugging, which may be useful to you. On the
+other hand, there are some complications to using 'forward', restrictions
+on values returned from 'forward', and it may not handle errors as you prefer.
+Whether you use 'forward' or not is up to you; it is not considered superior to
+the other ways to call a method.
+
+'forward' calls another action, by its private name. If you give a
class name but no method, C<process()> is called. You may also optionally
pass arguments in an arrayref. The action will receive the arguments in
C<@_> and C<< $c->req->args >>. Upon returning from the function,
my @middleware = map {
ref $_ eq 'CODE' ?
"Inline Coderef" :
- (ref($_) .' '. ($_->can('VERSION') ? $_->VERSION : '')
+ (ref($_) .' '. ($_->can('VERSION') ? $_->VERSION || '' : '')
|| '') } $class->registered_middlewares;
if (@middleware) {
$class->log->debug( "Loaded PSGI Middleware:\n" . $t->draw . "\n" );
}
- my %dh = $class->registered_data_handlers || ();
- my @data_handlers = keys %dh;
-
- if (@data_handlers) {
+ my %dh = $class->registered_data_handlers;
+ if (my @data_handlers = keys %dh) {
my $column_width = Catalyst::Utils::term_width() - 6;
my $t = Text::SimpleTable->new($column_width);
$t->row($_) for @data_handlers;
sub _make_immutable_if_needed {
my $class = shift;
- my $meta = Class::MOP::get_metaclass_by_name($class);
+ my $meta = find_meta($class);
my $isa_ca = $class->isa('Class::Accessor::Fast') || $class->isa('Class::Accessor');
if (
$meta->is_immutable
$dispatcher = $class->dispatcher_class;
}
- Class::MOP::load_class($dispatcher);
+ load_class($dispatcher);
# dispatcher instance
$class->dispatcher( $dispatcher->new );
# Don't really setup_engine -- see _setup_psgi_app for explanation.
return if $class->loading_psgi_file;
- Class::MOP::load_class($engine);
+ load_class($engine);
if ($ENV{MOD_PERL}) {
my $apache = $class->engine_loader->auto;
my ( $proto, $plugin, $instant ) = @_;
my $class = ref $proto || $proto;
- Class::MOP::load_class( $plugin );
+ load_class( $plugin );
$class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is deprecated and will not work in 5.81" )
if $plugin->isa( 'Catalyst::Component' );
my $plugin_meta = Moose::Meta::Class->create($plugin);
} @{ $plugins };
for my $plugin ( reverse @plugins ) {
- Class::MOP::load_class($plugin->[0], $plugin->[1]);
+ load_class($plugin->[0], $plugin->[1]);
my $meta = find_meta($plugin->[0]);
next if $meta && $meta->isa('Moose::Meta::Role');
=head2 default_data_handlers
-Default Data Handler that come bundled with L<Catalyst>. Currently there is
-only one default data handler, for 'application/json'. This uses L<JSON::MaybeXS>
-which uses the dependency free L<JSON::PP> OR L<Cpanel::JSON::XS> if you have
-installed it. If you don't mind the XS dependency, you should add the faster
-L<Cpanel::JSON::XS> to you dependency list (in your Makefile.PL or dist.ini, or
-cpanfile, etc.)
+Default Data Handlers that come bundled with L<Catalyst>. Currently there are
+only two default data handlers, for 'application/json' and an alternative to
+'application/x-www-form-urlencoded' which supposed nested form parameters via
+L<CGI::Struct> or via L<CGI::Struct::XS> IF you've installed it.
+
+The 'application/json' data handler is used to parse incoming JSON into a Perl
+data structure. It used either L<JSON::MaybeXS> or L<JSON>, depending on which
+is installed. This allows you to fail back to L<JSON:PP>, which is a Pure Perl
+JSON decoder, and has the smallest dependency impact.
+
+Because we don't wish to add more dependencies to L<Catalyst>, if you wish to
+use this new feature we recommend installing L<JSON> or L<JSON::MaybeXS> in
+order to get the best performance. You should add either to your dependency
+list (Makefile.PL, dist.ini, cpanfile, etc.)
=cut
sub default_data_handlers {
my ($class) = @_;
return +{
- 'application/json' => sub { local $/; decode_json $_->getline },
+ 'application/x-www-form-urlencoded' => sub {
+ my ($fh, $req) = @_;
+ my $params = $req->_use_hash_multivalue ? $req->body_parameters->mixed : $req->body_parameters;
+ Class::Load::load_first_existing_class('CGI::Struct::XS', 'CGI::Struct')
+ ->can('build_cgi_struct')->($params);
+ },
+ 'application/json' => sub {
+ Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON')
+ ->can('decode_json')->(do { local $/; $_->getline });
+ },
};
}
=item *
+C<use_hash_multivalue_in_request>
+
+In L<Catalyst::Request> the methods C<query_parameters>, C<body_parametes>
+and C<parameters> return a hashref where values might be scalar or an arrayref
+depending on the incoming data. In many cases this can be undesirable as it
+leads one to writing defensive code like the following:
+
+ my ($val) = ref($c->req->parameters->{a}) ?
+ @{$c->req->parameters->{a}} :
+ $c->req->parameters->{a};
+
+Setting this configuration item to true will make L<Catalyst> populate the
+attributes underlying these methods with an instance of L<Hash::MultiValue>
+which is used by L<Plack::Request> and others to solve this very issue. You
+may prefer this behavior to the default, if so enable this option (be warned
+if you enable it in a legacy application we are not sure if it is completely
+backwardly compatible).
+
+=item *
+
C<psgi_middleware> - See L<PSGI MIDDLEWARE>.
=item *