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