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