correction for unexpected check for _application being blessed
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
CommitLineData
5ee249f2 1package Catalyst::Controller;
2
ae29b412 3use Moose;
eff60019 4use Class::MOP;
c6392ad5 5use Class::Load ':all';
eff60019 6use String::RewritePrefix;
a58af53d 7use Moose::Util qw/find_meta/;
eff60019 8use List::Util qw/first/;
4f4ab5b4 9use List::MoreUtils qw/uniq/;
ae29b412 10use namespace::clean -except => 'meta';
11
a0c37f08 12BEGIN {
13 extends qw/Catalyst::Component/;
14 with qw/MooseX::MethodAttributes::Role::AttrContainer::Inheritable/;
15}
234763d4 16
cf37d21a 17use MooseX::MethodAttributes;
234763d4 18use Catalyst::Exception;
19use Catalyst::Utils;
ae29b412 20
21with 'Catalyst::Component::ApplicationAttribute';
22
aea897b2 23has path_prefix => (
24 is => 'rw',
25 isa => 'Str',
26 init_arg => 'path',
27 predicate => 'has_path_prefix',
28);
29
30has action_namespace => (
31 is => 'rw',
32 isa => 'Str',
33 init_arg => 'namespace',
34 predicate => 'has_action_namespace',
35);
36
37has actions => (
38 accessor => '_controller_actions',
39 isa => 'HashRef',
40 init_arg => undef,
41);
ae29b412 42
eff60019 43has _action_role_args => (
44 traits => [qw(Array)],
45 isa => 'ArrayRef[Str]',
46 init_arg => 'action_roles',
47 default => sub { [] },
48 handles => {
49 _action_role_args => 'elements',
50 },
51);
52
53has _action_roles => (
54 traits => [qw(Array)],
55 isa => 'ArrayRef[RoleName]',
56 init_arg => undef,
57 lazy => 1,
58 builder => '_build__action_roles',
59 handles => {
60 _action_roles => 'elements',
61 },
62);
63
bf7c9c87 64has action_args => (is => 'ro');
65
bdd6684e 66# ->config(actions => { '*' => ...
67has _all_actions_attributes => (
68 is => 'ro',
69 isa => 'HashRef',
70 init_arg => undef,
71 lazy => 1,
72 builder => '_build__all_actions_attributes',
73);
74
7f22a5aa 75sub BUILD {
76 my ($self, $args) = @_;
ae29b412 77 my $action = delete $args->{action} || {};
78 my $actions = delete $args->{actions} || {};
7f22a5aa 79 my $attr_value = $self->merge_config_hashes($actions, $action);
80 $self->_controller_actions($attr_value);
5ee249f2 81
bdd6684e 82 # trigger lazy builder
83 $self->_all_actions_attributes;
eff60019 84 $self->_action_roles;
85}
86
87sub _build__action_roles {
88 my $self = shift;
89 my @roles = $self->_expand_role_shortname($self->_action_role_args);
c6392ad5 90 load_class($_) for @roles;
eff60019 91 return \@roles;
bdd6684e 92}
d0e5dfb5 93
bdd6684e 94sub _build__all_actions_attributes {
95 my ($self) = @_;
96 delete $self->_controller_actions->{'*'} || {};
97}
d0e5dfb5 98
5ee249f2 99=head1 NAME
100
101Catalyst::Controller - Catalyst Controller base class
102
103=head1 SYNOPSIS
104
234763d4 105 package MyApp::Controller::Search
a269e0c2 106 use base qw/Catalyst::Controller/;
234763d4 107
27ae4114 108 sub foo : Local {
85d9fce6 109 my ($self,$c,@args) = @_;
27ae4114 110 ...
234763d4 111 } # Dispatches to /search/foo
5ee249f2 112
113=head1 DESCRIPTION
114
a269e0c2 115Controllers are where the actions in the Catalyst framework
116reside. Each action is represented by a function with an attribute to
117identify what kind of action it is. See the L<Catalyst::Dispatcher>
118for more info about how Catalyst dispatches to actions.
234763d4 119
120=cut
121
ae29b412 122#I think both of these could be attributes. doesn't really seem like they need
bd85860b 123#to be class data. i think that attributes +default would work just fine
eff60019 124__PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
234763d4 125
126__PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
7b41db70 127__PACKAGE__->_action_class('Catalyst::Action');
eff60019 128__PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
234763d4 129
234763d4 130
131sub _DISPATCH : Private {
132 my ( $self, $c ) = @_;
133
134 foreach my $disp ( @{ $self->_dispatch_steps } ) {
135 last unless $c->forward($disp);
136 }
137
138 $c->forward('_END');
139}
140
141sub _BEGIN : Private {
142 my ( $self, $c ) = @_;
143 my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
144 return 1 unless $begin;
145 $begin->dispatch( $c );
e459bd03 146 #If there is an error, all bets off
147 if( @{ $c->error }) {
148 return !@{ $c->error };
149 } else {
150 return $c->state || 1;
151 }
234763d4 152}
153
154sub _AUTO : Private {
155 my ( $self, $c ) = @_;
156 my @auto = $c->get_actions( 'auto', $c->namespace );
157 foreach my $auto (@auto) {
4c71cf1b 158 # We FORCE the auto action user to explicitly return
159 # true. We need to do this since there's some auto
160 # users (Catalyst::Authentication::Credential::HTTP) that
161 # actually do a detach instead.
162 $c->state(0);
234763d4 163 $auto->dispatch( $c );
164 return 0 unless $c->state;
165 }
e459bd03 166 return $c->state || 1;
234763d4 167}
168
169sub _ACTION : Private {
170 my ( $self, $c ) = @_;
171 if ( ref $c->action
172 && $c->action->can('execute')
53119b78 173 && defined $c->req->action )
234763d4 174 {
175 $c->action->dispatch( $c );
176 }
e459bd03 177 #If there is an error, all bets off
178 if( @{ $c->error }) {
179 return !@{ $c->error };
180 } else {
181 return $c->state || 1;
182 }
234763d4 183}
184
185sub _END : Private {
186 my ( $self, $c ) = @_;
187 my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
188 return 1 unless $end;
189 $end->dispatch( $c );
190 return !@{ $c->error };
191}
192
234763d4 193sub action_for {
194 my ( $self, $name ) = @_;
195 my $app = ($self->isa('Catalyst') ? $self : $self->_application);
196 return $app->dispatcher->get_action($name, $self->action_namespace);
197}
198
27ae4114 199#my opinion is that this whole sub really should be a builder method, not
ae29b412 200#something that happens on every call. Anyone else disagree?? -- groditi
201## -- apparently this is all just waiting for app/ctx split
202around action_namespace => sub {
203 my $orig = shift;
234763d4 204 my ( $self, $c ) = @_;
ae29b412 205
df960201 206 my $class = ref($self) || $self;
207 my $appclass = ref($c) || $c;
ae29b412 208 if( ref($self) ){
209 return $self->$orig if $self->has_action_namespace;
210 } else {
df960201 211 return $class->config->{namespace} if exists $class->config->{namespace};
234763d4 212 }
234763d4 213
ae29b412 214 my $case_s;
215 if( $c ){
df960201 216 $case_s = $appclass->config->{case_sensitive};
ae29b412 217 } else {
218 if ($self->isa('Catalyst')) {
df960201 219 $case_s = $class->config->{case_sensitive};
ae29b412 220 } else {
221 if (ref $self) {
f5f241c1 222 # This seems like total wack from 2009. Not sure
223 # why we'd take a ref on _application since we
224 # expect it to be a string... Seems like it was
225 # part of a whole bunch of changes related to the
226 # failed app/ctx stuff from years ago. However
227 # in cases where the controller gets called in
228 # application context, this now fails hard. I've
229 # added defensive 'if its a ref' code just to be
230 # safe but I don't think its really ever used
231 my $local_app = ref($self->_application) ?
232 ref($self->_application): $self->_application;
233 $case_s = $local_app->config->{case_sensitive};
ae29b412 234 } else {
235 confess("Can't figure out case_sensitive setting");
236 }
237 }
234763d4 238 }
ae29b412 239
8f6cebb2 240 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
ae29b412 241 $self->$orig($namespace) if ref($self);
242 return $namespace;
243};
244
245#Once again, this is probably better written as a builder method
246around path_prefix => sub {
247 my $orig = shift;
248 my $self = shift;
249 if( ref($self) ){
250 return $self->$orig if $self->has_path_prefix;
251 } else {
252 return $self->config->{path} if exists $self->config->{path};
253 }
254 my $namespace = $self->action_namespace(@_);
255 $self->$orig($namespace) if ref($self);
256 return $namespace;
257};
234763d4 258
9ab7d83d 259sub get_action_methods {
260 my $self = shift;
2bf074ab 261 my $meta = find_meta($self) || confess("No metaclass setup for $self");
69048792 262 confess(
263 sprintf "Metaclass %s for %s cannot support register_actions.",
264 ref $meta, $meta->name,
265 ) unless $meta->can('get_nearest_methods_with_attributes');
cf37d21a 266 my @methods = $meta->get_nearest_methods_with_attributes;
fa649eb7 267
268 # actions specified via config are also action_methods
269 push(
270 @methods,
271 map {
d0e78355 272 $meta->find_method_by_name($_)
e87273a4 273 || confess( sprintf 'Action "%s" is not available from controller %s',
274 $_, ref $self )
bdd6684e 275 } keys %{ $self->_controller_actions }
fa649eb7 276 ) if ( ref $self );
4f4ab5b4 277 return uniq @methods;
9ab7d83d 278}
234763d4 279
fa649eb7 280
234763d4 281sub register_actions {
282 my ( $self, $c ) = @_;
9ab7d83d 283 $self->register_action_methods( $c, $self->get_action_methods );
284}
285
286sub register_action_methods {
287 my ( $self, $c, @methods ) = @_;
8f6cebb2 288 my $class = $self->catalyst_component_name;
ae29b412 289 #this is still not correct for some reason.
234763d4 290 my $namespace = $self->action_namespace($c);
234763d4 291
f3c5b1c9 292 # FIXME - fugly
a202886b 293 if (!blessed($self) && $self eq $c && scalar(@methods)) {
f3c5b1c9 294 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
295 if (scalar(@really_bad_methods)) {
296 $c->log->warn("Action methods (" . join(', ', @really_bad_methods) . ") found defined in your application class, $self. This is deprecated, please move them into a Root controller.");
297 }
a202886b 298 }
d2598ac8 299
ba545c13 300 foreach my $method (@methods) {
301 my $name = $method->name;
d0f30dbc 302 # Horrible hack! All method metaclasses should have an attributes
303 # method, core Moose bug - see r13354.
10e970e4 304 my $attributes = $method->can('attributes') ? $method->attributes : [];
ba545c13 305 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
234763d4 306 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
f63dea6f 307 $c->log->warn( 'Bad action definition "'
ba545c13 308 . join( ' ', @{ $attributes } )
309 . qq/" for "$class->$name"/ )
234763d4 310 if $c->debug;
311 next;
312 }
bc677969 313 my $reverse = $namespace ? "${namespace}/${name}" : $name;
234763d4 314 my $action = $self->create_action(
ba545c13 315 name => $name,
316 code => $method->body,
234763d4 317 reverse => $reverse,
318 namespace => $namespace,
319 class => $class,
320 attributes => $attrs,
321 );
322
323 $c->dispatcher->register( $c, $action );
324 }
325}
326
eff60019 327sub _apply_action_class_roles {
328 my ($self, $class, @roles) = @_;
329
c6392ad5 330 load_class($_) for @roles;
eff60019 331 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
332 superclasses => [$class],
333 roles => \@roles,
334 cache => 1,
335 );
336 $meta->add_method(meta => sub { $meta });
337
338 return $meta->name;
339}
340
f0a9b791 341sub action_class {
7b41db70 342 my $self = shift;
343 my %args = @_;
234763d4 344
345 my $class = (exists $args{attributes}{ActionClass}
f0a9b791 346 ? $args{attributes}{ActionClass}[0]
347 : $self->_action_class);
348
e7399d8b 349 load_class($class);
f0a9b791 350 return $class;
351}
352
353sub create_action {
354 my $self = shift;
355 my %args = @_;
a7e955ae 356
f0a9b791 357 my $class = $self->action_class(%args);
eff60019 358
359 load_class($class);
360 Moose->init_meta(for_class => $class)
361 unless Class::MOP::does_metaclass_exist($class);
362
363 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
364 my @roles = $self->gather_action_roles(%args);
60034b8c 365 push @roles, $self->gather_default_action_roles(%args);
366
eff60019 367 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
368 }
369
bf7c9c87 370 my $action_args = (
371 ref($self)
372 ? $self->action_args
373 : $self->config->{action_args}
374 );
f0a9b791 375
a7e955ae 376 my %extra_args = (
377 %{ $action_args->{'*'} || {} },
378 %{ $action_args->{ $args{name} } || {} },
379 );
380
381 return $class->new({ %extra_args, %args });
234763d4 382}
383
eff60019 384sub gather_action_roles {
385 my ($self, %args) = @_;
eff60019 386 return (
387 (blessed $self ? $self->_action_roles : ()),
388 @{ $args{attributes}->{Does} || [] },
389 );
390}
391
60034b8c 392sub gather_default_action_roles {
393 my ($self, %args) = @_;
394 my @roles = ();
395 push @roles, 'Catalyst::ActionRole::HTTPMethods'
396 if $args{attributes}->{Method};
3e0665e4 397
398 push @roles, 'Catalyst::ActionRole::ConsumesContent'
399 if $args{attributes}->{Consumes};
400
342d2169 401 push @roles, 'Catalyst::ActionRole::Scheme'
402 if $args{attributes}->{Scheme};
25ca36c2 403
404 push @roles, 'Catalyst::ActionRole::QueryMatching'
405 if $args{attributes}->{Query};
3e0665e4 406 return @roles;
60034b8c 407}
408
234763d4 409sub _parse_attrs {
410 my ( $self, $c, $name, @attrs ) = @_;
411
412 my %raw_attributes;
413
414 foreach my $attr (@attrs) {
415
416 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
417
698e6f19 418 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)?\s*\))?$/ ) )
234763d4 419 {
420
421 if ( defined $value ) {
422 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
423 }
424 push( @{ $raw_attributes{$key} }, $value );
425 }
426 }
427
bdd6684e 428 my ($actions_config, $all_actions_config);
ae29b412 429 if( ref($self) ) {
bdd6684e 430 $actions_config = $self->_controller_actions;
431 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
432 $all_actions_config = $self->_all_actions_attributes;
ae29b412 433 } else {
434 my $cfg = $self->config;
bdd6684e 435 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
436 $all_actions_config = {};
234763d4 437 }
438
ed9d06b6 439 %raw_attributes = (
440 %raw_attributes,
e95b2b49 441 # Note we deep copy array refs here to stop crapping on config
442 # when attributes are parsed. RT#65463
443 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
ed9d06b6 444 );
ae29b412 445
ed9d06b6 446 # Private actions with additional attributes will raise a warning and then
447 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
448 # which are Private, will prevent those from being registered. They should
449 # probably be turned into :Actions instead, or we might want to otherwise
450 # disambiguate between those built-in internal actions and user-level
451 # Private ones.
bdd6684e 452 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
453 unless $raw_attributes{Private};
ae29b412 454
234763d4 455 my %final_attributes;
456
0b0aee67 457 while (my ($key, $value) = each %raw_attributes){
458 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
459 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
460 }
234763d4 461
0b0aee67 462 return \%final_attributes;
463}
234763d4 464
0b0aee67 465sub _parse_attr {
466 my ($self, $c, $name, $key, $values) = @_;
234763d4 467
0b0aee67 468 my %final_attributes;
469 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
470 my $meth = "_parse_${key}_attr";
471 if ( my $code = $self->can($meth) ) {
472 my %new_attrs = $self->$code( $c, $name, $value );
473 while (my ($new_key, $value) = each %new_attrs){
474 my $new_attrs = $key eq $new_key ?
475 { $new_key => [$value] } :
476 $self->_parse_attr($c, $name, $new_key => $value );
477 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
234763d4 478 }
0b0aee67 479 }
480 else {
234763d4 481 push( @{ $final_attributes{$key} }, $value );
482 }
483 }
484
485 return \%final_attributes;
486}
487
488sub _parse_Global_attr {
489 my ( $self, $c, $name, $value ) = @_;
0b0aee67 490 # _parse_attr will call _parse_Path_attr for us
491 return Path => "/$name";
234763d4 492}
493
494sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
495
496sub _parse_Local_attr {
497 my ( $self, $c, $name, $value ) = @_;
0b0aee67 498 # _parse_attr will call _parse_Path_attr for us
499 return Path => $name;
234763d4 500}
501
502sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
503
504sub _parse_Path_attr {
505 my ( $self, $c, $name, $value ) = @_;
53119b78 506 $value = '' if !defined $value;
234763d4 507 if ( $value =~ m!^/! ) {
508 return ( 'Path', $value );
509 }
510 elsif ( length $value ) {
511 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
512 }
513 else {
514 return ( 'Path', $self->path_prefix($c) );
515 }
516}
517
f3107403 518sub _parse_Chained_attr {
519 my ($self, $c, $name, $value) = @_;
520
521 if (defined($value) && length($value)) {
522 if ($value eq '.') {
523 $value = '/'.$self->action_namespace($c);
fb56008f 524 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 525 my @parts = split '/', $self->action_namespace($c);
fb56008f 526 my @levels = split '/', $rel;
527
528 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 529 } elsif ($value !~ m/^\//) {
530 my $action_ns = $self->action_namespace($c);
531
532 if ($action_ns) {
533 $value = '/'.join('/', $action_ns, $value);
534 } else {
535 $value = '/'.$value; # special case namespace '' (root)
536 }
537 }
538 } else {
539 $value = '/'
540 }
541
542 return Chained => $value;
543}
544
9356b981 545sub _parse_ChainedParent_attr {
546 my ($self, $c, $name, $value) = @_;
547 return $self->_parse_Chained_attr($c, $name, '../'.$name);
548}
549
e5d2cfdb 550sub _parse_PathPrefix_attr {
02825551 551 my ( $self, $c ) = @_;
552 return PathPart => $self->path_prefix($c);
e5d2cfdb 553}
554
234763d4 555sub _parse_ActionClass_attr {
556 my ( $self, $c, $name, $value ) = @_;
5d8129e9 557 my $appname = $self->_application;
558 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 559 return ( 'ActionClass', $value );
560}
561
9287719b 562sub _parse_MyAction_attr {
563 my ( $self, $c, $name, $value ) = @_;
564
565 my $appclass = Catalyst::Utils::class2appclass($self);
0b0aee67 566 $value = "+${appclass}::Action::${value}";
234763d4 567
9287719b 568 return ( 'ActionClass', $value );
569}
234763d4 570
eff60019 571sub _parse_Does_attr {
572 my ($self, $app, $name, $value) = @_;
573 return Does => $self->_expand_role_shortname($value);
574}
575
e2a8c7e5 576sub _parse_GET_attr { Method => 'GET' }
577sub _parse_POST_attr { Method => 'POST' }
578sub _parse_PUT_attr { Method => 'PUT' }
579sub _parse_DELETE_attr { Method => 'DELETE' }
580sub _parse_OPTIONS_attr { Method => 'OPTIONS' }
581sub _parse_HEAD_attr { Method => 'HEAD' }
9f3e69ee 582sub _parse_PATCH_attr { Method => 'PATCH' }
760d121e 583
eff60019 584sub _expand_role_shortname {
585 my ($self, @shortnames) = @_;
586 my $app = $self->_application;
587
588 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
589 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
590
591 return String::RewritePrefix->rewrite(
592 { '' => sub {
c6392ad5 593 my $loaded = load_first_existing_class(
eff60019 594 map { "$_$_[0]" } @prefixes
595 );
596 return first { $loaded =~ /^$_/ }
597 sort { length $b <=> length $a } @prefixes;
598 },
599 '~' => $prefixes[0],
600 '+' => '' },
601 @shortnames,
602 );
603}
604
ae29b412 605__PACKAGE__->meta->make_immutable;
606
234763d4 6071;
608
609__END__
610
611=head1 CONFIGURATION
612
a269e0c2 613Like any other L<Catalyst::Component>, controllers have a config hash,
614accessible through $self->config from the controller actions. Some
615settings are in use by the Catalyst framework:
234763d4 616
617=head2 namespace
618
a269e0c2 619This specifies the internal namespace the controller should be bound
620to. By default the controller is bound to the URI version of the
621controller name. For instance controller 'MyApp::Controller::Foo::Bar'
622will be bound to 'foo/bar'. The default Root controller is an example
623of setting namespace to '' (the null string).
234763d4 624
27ae4114 625=head2 path
234763d4 626
627Sets 'path_prefix', as described below.
628
0a2577a8 629=head2 action
630
631Allows you to set the attributes that the dispatcher creates actions out of.
632This allows you to do 'rails style routes', or override some of the
f4dda4a8 633attribute definitions of actions composed from Roles.
0a2577a8 634You can set arguments globally (for all actions of the controller) and
635specifically (for a single action).
636
637 __PACKAGE__->config(
638 action => {
639 '*' => { Chained => 'base', Args => 0 },
640 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
641 },
642 );
643
644In the case above every sub in the package would be made into a Chain
645endpoint with a URI the same as the sub name for each sub, chained
646to the sub named C<base>. Ergo dispatch to C</example> would call the
647C<base> method, then the C<example> method.
648
c8136648 649=head2 action_args
650
4d4e5de8 651Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 652globally and specifically (as above).
653This is particularly useful when using C<ActionRole>s
b939ae6b 654(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 655
b939ae6b 656 __PACKAGE__->config(
c8136648 657 action_args => {
b939ae6b 658 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
659 'specific_action' => { customarg => 'arg1' },
cea3f28a 660 },
b939ae6b 661 );
cea3f28a 662
b939ae6b 663In the case above the action class associated with C<specific_action> would get
664passed the following arguments, in addition to the normal action constructor
665arguments, when it is instantiated:
666
667 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 668
234763d4 669=head1 METHODS
670
c4d02967 671=head2 BUILDARGS ($app, @args)
234763d4 672
c4d02967 673From L<Catalyst::Component::ApplicationAttribute>, stashes the application
674instance as $self->_application.
234763d4 675
676=head2 $self->action_for('name')
677
a269e0c2 678Returns the Catalyst::Action object (if any) for a given method name
679in this component.
234763d4 680
234763d4 681=head2 $self->action_namespace($c)
682
a269e0c2 683Returns the private namespace for actions in this component. Defaults
684to a value from the controller name (for
685e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
686overridden from the "namespace" config key.
234763d4 687
688
689=head2 $self->path_prefix($c)
690
4ba7161b 691Returns the default path prefix for :PathPrefix, :Local and
e5d2cfdb 692relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 693can be overridden from the "path" config key.
234763d4 694
c4d02967 695=head2 $self->register_actions($c)
696
697Finds all applicable actions for this component, creates
698Catalyst::Action objects (using $self->create_action) for them and
699registers them with $c->dispatcher.
700
701=head2 $self->get_action_methods()
702
703Returns a list of L<Moose::Meta::Method> objects, doing the
704L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
705action methods for this package.
706
707=head2 $self->register_action_methods($c, @methods)
708
709Creates action objects for a set of action methods using C< create_action >,
710and registers them with the dispatcher.
711
f0a9b791 712=head2 $self->action_class(%args)
713
714Used when a controller is creating an action to determine the correct base
24d2dfaf 715action class to use.
f0a9b791 716
234763d4 717=head2 $self->create_action(%args)
718
a269e0c2 719Called with a hash of data to be use for construction of a new
720Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 721
eff60019 722=head2 $self->gather_action_roles(\%action_args)
723
724Gathers the list of roles to apply to an action with the given %action_args.
725
60034b8c 726=head2 $self->gather_default_action_roles(\%action_args)
727
728returns a list of action roles to be applied based on core, builtin rules.
729Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
730this way.
731
a269e0c2 732=head2 $self->_application
234763d4 733
734=head2 $self->_app
735
736Returns the application instance stored by C<new()>
5ee249f2 737
5b41c28c 738=head1 ACTION SUBROUTINE ATTRIBUTES
739
740Please see L<Catalyst::Manual::Intro> for more details
741
742Think of action attributes as a sort of way to record metadata about an action,
743similar to how annotations work in other languages you might have heard of.
744Generally L<Catalyst> uses these to influence how the dispatcher sees your
745action and when it will run it in response to an incoming request. They can
746also be used for other things. Here's a summary, but you should refer to the
aaa85094 747linked manual page for additional help.
5b41c28c 748
749=head2 Global
750
751 sub homepage :Global { ... }
752
753A global action defined in any controller always runs relative to your root.
754So the above is the same as:
755
756 sub myaction :Path("/homepage") { ... }
757
758=head2 Absolute
759
760Status: Deprecated alias to L</Global>.
761
762=head2 Local
763
764Alias to "Path("$action_name"). The following two actions are the same:
765
766 sub myaction :Local { ... }
767 sub myaction :Path('myaction') { ... }
768
769=head2 Relative
770
771Status: Deprecated alias to L</Local>
772
773=head2 Path
774
775Handle various types of paths:
776
777 package MyApp::Controller::Baz {
778
779 ...
780
781 sub myaction1 :Path { ... } # -> /baz
c59b922b 782 sub myaction2 :Path('foo') { ... } # -> /baz/foo
5b41c28c 783 sub myaction2 :Path('/bar') { ... } # -> /bar
784 }
785
97b0e7a0 786This is a general toolbox for attaching your action to a given path.
5b41c28c 787
788
789=head2 Regex
790
791=head2 Regexp
792
5070f111 793B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 794If you really depend on this, install the standalone
795L<Catalyst::DispatchType::Regex> distribution.
5b41c28c 796
797A global way to match a give regular expression in the incoming request path.
798
799=head2 LocalRegex
800
801=head2 LocalRegexp
802
5070f111 803B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 804If you really depend on this, install the standalone
805L<Catalyst::DispatchType::Regex> distribution.
806
5b41c28c 807Like L</Regex> but scoped under the namespace of the containing controller
808
809=head2 Chained
810
811=head2 ChainedParent
812
813=head2 PathPrefix
814
815=head2 PathPart
816
817=head2 CaptureArgs
818
480d94b5 819Allowed values for CaptureArgs is a single integer (CaptureArgs(2), meaning two
820allowed) or you can declare a L<Moose>, L<MooseX::Types> or L<Type::Tiny>
821named constraint such as CaptureArgs(Int,Str) would require two args with
822the first being a Integer and the second a string. You may declare your own
823custom type constraints and import them into the controller namespace:
824
825 package MyApp::Controller::Root;
826
827 use Moose;
828 use MooseX::MethodAttributes;
829 use MyApp::Types qw/Int/;
830
831 extends 'Catalyst::Controller';
832
833 sub chain_base :Chained(/) CaptureArgs(1) { }
834
835 sub any_priority_chain :Chained(chain_base) PathPart('') Args(1) { }
836
837 sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { }
838
839See L<Catalyst::RouteMatching> for more.
840
841Please see L<Catalyst::DispatchType::Chained> for more.
5b41c28c 842
843=head2 ActionClass
844
845Set the base class for the action, defaults to L</Catalyst::Action>. It is now
846preferred to use L</Does>.
847
848=head2 MyAction
849
051a69b9 850Set the ActionClass using a custom Action in your project namespace.
851
852The following is exactly the same:
853
854 sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
855 sub foo_action2 : Local MyAction('Bar') { ... }
5b41c28c 856
857=head2 Does
858
859 package MyApp::Controller::Zoo;
860
861 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
862 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
863 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
864
865=head2 GET
866
867=head2 POST
868
869=head2 PUT
870
871=head2 DELETE
872
873=head2 OPTION
874
875=head2 HEAD
876
60034b8c 877=head2 PATCH
878
879=head2 Method('...')
880
881Sets the give action path to match the specified HTTP method, or via one of the
882broadly accepted methods of overriding the 'true' method (see
883L<Catalyst::ActionRole::HTTPMethods>).
5b41c28c 884
885=head2 Args
886
887When used with L</Path> indicates the number of arguments expected in
888the path. However if no Args value is set, assumed to 'slurp' all
889remaining path pars under this namespace.
890
480d94b5 891Allowed values for Args is a single integer (Args(2), meaning two allowed) or you
892can declare a L<Moose>, L<MooseX::Types> or L<Type::Tiny> named constraint such
893as Args(Int,Str) would require two args with the first being a Integer and the
894second a string. You may declare your own custom type constraints and import
895them into the controller namespace:
896
897 package MyApp::Controller::Root;
898
899 use Moose;
900 use MooseX::MethodAttributes;
901 use MyApp::Types qw/Tuple Int Str StrMatch UserId/;
902
903 extends 'Catalyst::Controller';
904
905 sub user :Local Args(UserId) {
906 my ($self, $c, $int) = @_;
907 }
908
909 sub an_int :Local Args(Int) {
910 my ($self, $c, $int) = @_;
911 }
912
913 sub many_ints :Local Args(ArrayRef[Int]) {
914 my ($self, $c, @ints) = @_;
915 }
916
917 sub match :Local Args(StrMatch[qr{\d\d-\d\d-\d\d}]) {
918 my ($self, $c, $int) = @_;
919 }
920
75ce30d0 921If you choose not to use imported type constraints (like L<Type::Tiny>, or <MooseX::Types>
922you may use L<Moose> 'stringy' types however just like when you use these types in your
923declared attributes you must quote them:
924
925 sub my_moose_type :Local Args('Int') { ... }
926
d9f0a350 927If you use 'reference' type constraints (such as ArrayRef[Int]) that have an unknown
928number of allowed matches, we set this the same way "Args" is. Please keep in mind
79fb8f95 929that actions with an undetermined number of args match at lower precedence than those
d9f0a350 930with a fixed number. You may use reference types such as Tuple from L<Types::Standard>
931that allows you to fix the number of allowed args. For example Args(Tuple[Int,Int])
932would be determined to be two args (or really the same as Args(Int,Int).) You may
933find this useful for creating custom subtypes with complex matching rules that you
934wish to reuse over many actions.
935
480d94b5 936See L<Catalyst::RouteMatching> for more.
937
68c372d1 938=head2 Consumes('...')
939
940Matches the current action against the content-type of the request. Typically
941this is used when the request is a POST or PUT and you want to restrict the
942submitted content type. For example, you might have an HTML for that either
943returns classic url encoded form data, or JSON when Javascript is enabled. In
944this case you may wish to match either incoming type to one of two different
945actions, for properly processing.
946
947Examples:
948
949 sub is_json : Chained('start') Consumes('application/json') { ... }
950 sub is_urlencoded : Chained('start') Consumes('application/x-www-form-urlencoded') { ... }
951 sub is_multipart : Chained('start') Consumes('multipart/form-data') { ... }
952
953To reduce boilerplate, we include the following content type shortcuts:
954
955Examples
956
957 sub is_json : Chained('start') Consume(JSON) { ... }
958 sub is_urlencoded : Chained('start') Consumes(UrlEncoded) { ... }
959 sub is_multipart : Chained('start') Consumes(Multipart) { ... }
960
961You may specify more than one match:
962
963 sub is_more_than_one
964 : Chained('start')
965 : Consumes('application/x-www-form-urlencoded')
966 : Consumes('multipart/form-data')
967
968 sub is_more_than_one
969 : Chained('start')
970 : Consumes(UrlEncoded)
971 : Consumes(Multipart)
972
973Since it is a common case the shortcut C<HTMLForm> matches both
974'application/x-www-form-urlencoded' and 'multipart/form-data'. Here's the full
975list of available shortcuts:
976
977 JSON => 'application/json',
978 JS => 'application/javascript',
979 PERL => 'application/perl',
980 HTML => 'text/html',
981 XML => 'text/XML',
982 Plain => 'text/plain',
983 UrlEncoded => 'application/x-www-form-urlencoded',
984 Multipart => 'multipart/form-data',
985 HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
986
987Please keep in mind that when dispatching, L<Catalyst> will match the first most
efba3342 988relevant case, so if you use the C<Consumes> attribute, you should place your
68c372d1 989most accurate matches early in the Chain, and your 'catchall' actions last.
990
991See L<Catalyst::ActionRole::ConsumesContent> for more.
992
342d2169 993=head2 Scheme(...)
994
995Allows you to specify a URI scheme for the action or action chain. For example
996you can required that a given path be C<https> or that it is a websocket endpoint
997C<ws> or C<wss>. For an action chain you may currently only have one defined
998Scheme.
999
1000 package MyApp::Controller::Root;
1001
1002 use base 'Catalyst::Controller';
1003
1004 sub is_http :Path(scheme) Scheme(http) Args(0) {
1005 my ($self, $c) = @_;
1006 $c->response->body("is_http");
1007 }
1008
1009 sub is_https :Path(scheme) Scheme(https) Args(0) {
1010 my ($self, $c) = @_;
1011 $c->response->body("is_https");
1012 }
1013
1014In the above example http://localhost/root/scheme would match the first
1015action (is_http) but https://localhost/root/scheme would match the second.
1016
1017As an added benefit, if an action or action chain defines a Scheme, when using
1018$c->uri_for the scheme of the generated URL will use what you define in the action
1019or action chain (the current behavior is to set the scheme based on the current
1020incoming request). This makes it easier to use uri_for on websites where some
1021paths are secure and others are not. You may also use this to other schemes
1022like websockets.
1023
1024See L<Catalyst::ActionRole::Scheme> for more.
1025
5b41c28c 1026=head1 OPTIONAL METHODS
1027
1028=head2 _parse_[$name]_attr
1029
1030Allows you to customize parsing of subroutine attributes.
1031
1032 sub myaction1 :Path TwoArgs { ... }
1033
1034 sub _parse_TwoArgs_attr {
1035 my ( $self, $c, $name, $value ) = @_;
1036 # $self -> controller instance
1037 #
1038 return(Args => 2);
1039 }
1040
1041Please note that this feature does not let you actually assign new functions
1042to actions via subroutine attributes, but is really more for creating useful
1043aliases to existing core and extended attributes, and transforms based on
1044existing information (like from configuration). Code for actually doing
1045something meaningful with the subroutine attributes will be located in the
1046L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
1047in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
1048called basically once when the application is starting, not per request!
1049
0bf7ab71 1050=head1 AUTHORS
5ee249f2 1051
0bf7ab71 1052Catalyst Contributors, see Catalyst.pm
5ee249f2 1053
1054=head1 COPYRIGHT
1055
536bee89 1056This library is free software. You can redistribute it and/or modify
a269e0c2 1057it under the same terms as Perl itself.
5ee249f2 1058
1059=cut