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