move all core use of "debug" to use "trace" instead (or almost all of them)
[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 ) ) {
14d2fa6a 281 $c->trace(1, 'Bad action definition "'
ba545c13 282 . join( ' ', @{ $attributes } )
14d2fa6a 283 . qq/" for "$class->$name"/ );
234763d4 284 next;
285 }
bc677969 286 my $reverse = $namespace ? "${namespace}/${name}" : $name;
234763d4 287 my $action = $self->create_action(
ba545c13 288 name => $name,
289 code => $method->body,
234763d4 290 reverse => $reverse,
291 namespace => $namespace,
292 class => $class,
293 attributes => $attrs,
294 );
295
296 $c->dispatcher->register( $c, $action );
297 }
298}
299
eff60019 300sub _apply_action_class_roles {
301 my ($self, $class, @roles) = @_;
302
c6392ad5 303 load_class($_) for @roles;
eff60019 304 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
305 superclasses => [$class],
306 roles => \@roles,
307 cache => 1,
308 );
309 $meta->add_method(meta => sub { $meta });
310
311 return $meta->name;
312}
313
f0a9b791 314sub action_class {
7b41db70 315 my $self = shift;
316 my %args = @_;
234763d4 317
318 my $class = (exists $args{attributes}{ActionClass}
f0a9b791 319 ? $args{attributes}{ActionClass}[0]
320 : $self->_action_class);
321
e7399d8b 322 load_class($class);
f0a9b791 323 return $class;
324}
325
326sub create_action {
327 my $self = shift;
328 my %args = @_;
a7e955ae 329
f0a9b791 330 my $class = $self->action_class(%args);
eff60019 331
332 load_class($class);
333 Moose->init_meta(for_class => $class)
334 unless Class::MOP::does_metaclass_exist($class);
335
336 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
337 my @roles = $self->gather_action_roles(%args);
60034b8c 338 push @roles, $self->gather_default_action_roles(%args);
339
eff60019 340 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
341 }
342
bf7c9c87 343 my $action_args = (
344 ref($self)
345 ? $self->action_args
346 : $self->config->{action_args}
347 );
f0a9b791 348
a7e955ae 349 my %extra_args = (
350 %{ $action_args->{'*'} || {} },
351 %{ $action_args->{ $args{name} } || {} },
352 );
353
354 return $class->new({ %extra_args, %args });
234763d4 355}
356
eff60019 357sub gather_action_roles {
358 my ($self, %args) = @_;
eff60019 359 return (
360 (blessed $self ? $self->_action_roles : ()),
361 @{ $args{attributes}->{Does} || [] },
362 );
363}
364
60034b8c 365sub gather_default_action_roles {
366 my ($self, %args) = @_;
367 my @roles = ();
368 push @roles, 'Catalyst::ActionRole::HTTPMethods'
369 if $args{attributes}->{Method};
3e0665e4 370
371 push @roles, 'Catalyst::ActionRole::ConsumesContent'
372 if $args{attributes}->{Consumes};
373
374 return @roles;
60034b8c 375}
376
234763d4 377sub _parse_attrs {
378 my ( $self, $c, $name, @attrs ) = @_;
379
380 my %raw_attributes;
381
382 foreach my $attr (@attrs) {
383
384 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
385
386 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
387 {
388
389 if ( defined $value ) {
390 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
391 }
392 push( @{ $raw_attributes{$key} }, $value );
393 }
394 }
395
bdd6684e 396 my ($actions_config, $all_actions_config);
ae29b412 397 if( ref($self) ) {
bdd6684e 398 $actions_config = $self->_controller_actions;
399 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
400 $all_actions_config = $self->_all_actions_attributes;
ae29b412 401 } else {
402 my $cfg = $self->config;
bdd6684e 403 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
404 $all_actions_config = {};
234763d4 405 }
406
ed9d06b6 407 %raw_attributes = (
408 %raw_attributes,
e95b2b49 409 # Note we deep copy array refs here to stop crapping on config
410 # when attributes are parsed. RT#65463
411 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
ed9d06b6 412 );
ae29b412 413
ed9d06b6 414 # Private actions with additional attributes will raise a warning and then
415 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
416 # which are Private, will prevent those from being registered. They should
417 # probably be turned into :Actions instead, or we might want to otherwise
418 # disambiguate between those built-in internal actions and user-level
419 # Private ones.
bdd6684e 420 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
421 unless $raw_attributes{Private};
ae29b412 422
234763d4 423 my %final_attributes;
424
0b0aee67 425 while (my ($key, $value) = each %raw_attributes){
426 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
427 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
428 }
234763d4 429
0b0aee67 430 return \%final_attributes;
431}
234763d4 432
0b0aee67 433sub _parse_attr {
434 my ($self, $c, $name, $key, $values) = @_;
234763d4 435
0b0aee67 436 my %final_attributes;
437 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
438 my $meth = "_parse_${key}_attr";
439 if ( my $code = $self->can($meth) ) {
440 my %new_attrs = $self->$code( $c, $name, $value );
441 while (my ($new_key, $value) = each %new_attrs){
442 my $new_attrs = $key eq $new_key ?
443 { $new_key => [$value] } :
444 $self->_parse_attr($c, $name, $new_key => $value );
445 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
234763d4 446 }
0b0aee67 447 }
448 else {
234763d4 449 push( @{ $final_attributes{$key} }, $value );
450 }
451 }
452
453 return \%final_attributes;
454}
455
456sub _parse_Global_attr {
457 my ( $self, $c, $name, $value ) = @_;
0b0aee67 458 # _parse_attr will call _parse_Path_attr for us
459 return Path => "/$name";
234763d4 460}
461
462sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
463
464sub _parse_Local_attr {
465 my ( $self, $c, $name, $value ) = @_;
0b0aee67 466 # _parse_attr will call _parse_Path_attr for us
467 return Path => $name;
234763d4 468}
469
470sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
471
472sub _parse_Path_attr {
473 my ( $self, $c, $name, $value ) = @_;
53119b78 474 $value = '' if !defined $value;
234763d4 475 if ( $value =~ m!^/! ) {
476 return ( 'Path', $value );
477 }
478 elsif ( length $value ) {
479 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
480 }
481 else {
482 return ( 'Path', $self->path_prefix($c) );
483 }
484}
485
f3107403 486sub _parse_Chained_attr {
487 my ($self, $c, $name, $value) = @_;
488
489 if (defined($value) && length($value)) {
490 if ($value eq '.') {
491 $value = '/'.$self->action_namespace($c);
fb56008f 492 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 493 my @parts = split '/', $self->action_namespace($c);
fb56008f 494 my @levels = split '/', $rel;
495
496 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 497 } elsif ($value !~ m/^\//) {
498 my $action_ns = $self->action_namespace($c);
499
500 if ($action_ns) {
501 $value = '/'.join('/', $action_ns, $value);
502 } else {
503 $value = '/'.$value; # special case namespace '' (root)
504 }
505 }
506 } else {
507 $value = '/'
508 }
509
510 return Chained => $value;
511}
512
9356b981 513sub _parse_ChainedParent_attr {
514 my ($self, $c, $name, $value) = @_;
515 return $self->_parse_Chained_attr($c, $name, '../'.$name);
516}
517
e5d2cfdb 518sub _parse_PathPrefix_attr {
02825551 519 my ( $self, $c ) = @_;
520 return PathPart => $self->path_prefix($c);
e5d2cfdb 521}
522
234763d4 523sub _parse_ActionClass_attr {
524 my ( $self, $c, $name, $value ) = @_;
5d8129e9 525 my $appname = $self->_application;
526 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 527 return ( 'ActionClass', $value );
528}
529
9287719b 530sub _parse_MyAction_attr {
531 my ( $self, $c, $name, $value ) = @_;
532
533 my $appclass = Catalyst::Utils::class2appclass($self);
0b0aee67 534 $value = "+${appclass}::Action::${value}";
234763d4 535
9287719b 536 return ( 'ActionClass', $value );
537}
234763d4 538
eff60019 539sub _parse_Does_attr {
540 my ($self, $app, $name, $value) = @_;
541 return Does => $self->_expand_role_shortname($value);
542}
543
ba3f8a81 544sub _parse_GET_attr { Method => 'GET' }
545sub _parse_POST_attr { Method => 'POST' }
546sub _parse_PUT_attr { Method => 'PUT' }
760d121e 547sub _parse_DELETE_attr { Method => 'DELETE' }
548sub _parse_OPTION_attr { Method => 'OPTION' }
ba3f8a81 549sub _parse_HEAD_attr { Method => 'HEAD' }
760d121e 550
eff60019 551sub _expand_role_shortname {
552 my ($self, @shortnames) = @_;
553 my $app = $self->_application;
554
555 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
556 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
557
558 return String::RewritePrefix->rewrite(
559 { '' => sub {
c6392ad5 560 my $loaded = load_first_existing_class(
eff60019 561 map { "$_$_[0]" } @prefixes
562 );
563 return first { $loaded =~ /^$_/ }
564 sort { length $b <=> length $a } @prefixes;
565 },
566 '~' => $prefixes[0],
567 '+' => '' },
568 @shortnames,
569 );
570}
571
ae29b412 572__PACKAGE__->meta->make_immutable;
573
234763d4 5741;
575
576__END__
577
578=head1 CONFIGURATION
579
a269e0c2 580Like any other L<Catalyst::Component>, controllers have a config hash,
581accessible through $self->config from the controller actions. Some
582settings are in use by the Catalyst framework:
234763d4 583
584=head2 namespace
585
a269e0c2 586This specifies the internal namespace the controller should be bound
587to. By default the controller is bound to the URI version of the
588controller name. For instance controller 'MyApp::Controller::Foo::Bar'
589will be bound to 'foo/bar'. The default Root controller is an example
590of setting namespace to '' (the null string).
234763d4 591
27ae4114 592=head2 path
234763d4 593
594Sets 'path_prefix', as described below.
595
0a2577a8 596=head2 action
597
598Allows you to set the attributes that the dispatcher creates actions out of.
599This allows you to do 'rails style routes', or override some of the
f4dda4a8 600attribute definitions of actions composed from Roles.
0a2577a8 601You can set arguments globally (for all actions of the controller) and
602specifically (for a single action).
603
604 __PACKAGE__->config(
605 action => {
606 '*' => { Chained => 'base', Args => 0 },
607 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
608 },
609 );
610
611In the case above every sub in the package would be made into a Chain
612endpoint with a URI the same as the sub name for each sub, chained
613to the sub named C<base>. Ergo dispatch to C</example> would call the
614C<base> method, then the C<example> method.
615
c8136648 616=head2 action_args
617
4d4e5de8 618Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 619globally and specifically (as above).
620This is particularly useful when using C<ActionRole>s
b939ae6b 621(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 622
b939ae6b 623 __PACKAGE__->config(
c8136648 624 action_args => {
b939ae6b 625 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
626 'specific_action' => { customarg => 'arg1' },
cea3f28a 627 },
b939ae6b 628 );
cea3f28a 629
b939ae6b 630In the case above the action class associated with C<specific_action> would get
631passed the following arguments, in addition to the normal action constructor
632arguments, when it is instantiated:
633
634 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 635
234763d4 636=head1 METHODS
637
c4d02967 638=head2 BUILDARGS ($app, @args)
234763d4 639
c4d02967 640From L<Catalyst::Component::ApplicationAttribute>, stashes the application
641instance as $self->_application.
234763d4 642
643=head2 $self->action_for('name')
644
a269e0c2 645Returns the Catalyst::Action object (if any) for a given method name
646in this component.
234763d4 647
234763d4 648=head2 $self->action_namespace($c)
649
a269e0c2 650Returns the private namespace for actions in this component. Defaults
651to a value from the controller name (for
652e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
653overridden from the "namespace" config key.
234763d4 654
655
656=head2 $self->path_prefix($c)
657
4ba7161b 658Returns the default path prefix for :PathPrefix, :Local and
e5d2cfdb 659relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 660can be overridden from the "path" config key.
234763d4 661
c4d02967 662=head2 $self->register_actions($c)
663
664Finds all applicable actions for this component, creates
665Catalyst::Action objects (using $self->create_action) for them and
666registers them with $c->dispatcher.
667
668=head2 $self->get_action_methods()
669
670Returns a list of L<Moose::Meta::Method> objects, doing the
671L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
672action methods for this package.
673
674=head2 $self->register_action_methods($c, @methods)
675
676Creates action objects for a set of action methods using C< create_action >,
677and registers them with the dispatcher.
678
f0a9b791 679=head2 $self->action_class(%args)
680
681Used when a controller is creating an action to determine the correct base
24d2dfaf 682action class to use.
f0a9b791 683
234763d4 684=head2 $self->create_action(%args)
685
a269e0c2 686Called with a hash of data to be use for construction of a new
687Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 688
eff60019 689=head2 $self->gather_action_roles(\%action_args)
690
691Gathers the list of roles to apply to an action with the given %action_args.
692
60034b8c 693=head2 $self->gather_default_action_roles(\%action_args)
694
695returns a list of action roles to be applied based on core, builtin rules.
696Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
697this way.
698
a269e0c2 699=head2 $self->_application
234763d4 700
701=head2 $self->_app
702
703Returns the application instance stored by C<new()>
5ee249f2 704
5b41c28c 705=head1 ACTION SUBROUTINE ATTRIBUTES
706
707Please see L<Catalyst::Manual::Intro> for more details
708
709Think of action attributes as a sort of way to record metadata about an action,
710similar to how annotations work in other languages you might have heard of.
711Generally L<Catalyst> uses these to influence how the dispatcher sees your
712action and when it will run it in response to an incoming request. They can
713also be used for other things. Here's a summary, but you should refer to the
aaa85094 714linked manual page for additional help.
5b41c28c 715
716=head2 Global
717
718 sub homepage :Global { ... }
719
720A global action defined in any controller always runs relative to your root.
721So the above is the same as:
722
723 sub myaction :Path("/homepage") { ... }
724
725=head2 Absolute
726
727Status: Deprecated alias to L</Global>.
728
729=head2 Local
730
731Alias to "Path("$action_name"). The following two actions are the same:
732
733 sub myaction :Local { ... }
734 sub myaction :Path('myaction') { ... }
735
736=head2 Relative
737
738Status: Deprecated alias to L</Local>
739
740=head2 Path
741
742Handle various types of paths:
743
744 package MyApp::Controller::Baz {
745
746 ...
747
748 sub myaction1 :Path { ... } # -> /baz
c59b922b 749 sub myaction2 :Path('foo') { ... } # -> /baz/foo
5b41c28c 750 sub myaction2 :Path('/bar') { ... } # -> /bar
751 }
752
97b0e7a0 753This is a general toolbox for attaching your action to a given path.
5b41c28c 754
755
756=head2 Regex
757
758=head2 Regexp
759
5070f111 760B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 761If you really depend on this, install the standalone
762L<Catalyst::DispatchType::Regex> distribution.
5b41c28c 763
764A global way to match a give regular expression in the incoming request path.
765
766=head2 LocalRegex
767
768=head2 LocalRegexp
769
5070f111 770B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 771If you really depend on this, install the standalone
772L<Catalyst::DispatchType::Regex> distribution.
773
5b41c28c 774Like L</Regex> but scoped under the namespace of the containing controller
775
776=head2 Chained
777
778=head2 ChainedParent
779
780=head2 PathPrefix
781
782=head2 PathPart
783
784=head2 CaptureArgs
785
786Please see L<Catalyst::DispatchType::Chained>
787
788=head2 ActionClass
789
790Set the base class for the action, defaults to L</Catalyst::Action>. It is now
791preferred to use L</Does>.
792
793=head2 MyAction
794
051a69b9 795Set the ActionClass using a custom Action in your project namespace.
796
797The following is exactly the same:
798
799 sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
800 sub foo_action2 : Local MyAction('Bar') { ... }
5b41c28c 801
802=head2 Does
803
804 package MyApp::Controller::Zoo;
805
806 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
807 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
808 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
809
810=head2 GET
811
812=head2 POST
813
814=head2 PUT
815
816=head2 DELETE
817
818=head2 OPTION
819
820=head2 HEAD
821
60034b8c 822=head2 PATCH
823
824=head2 Method('...')
825
826Sets the give action path to match the specified HTTP method, or via one of the
827broadly accepted methods of overriding the 'true' method (see
828L<Catalyst::ActionRole::HTTPMethods>).
5b41c28c 829
830=head2 Args
831
832When used with L</Path> indicates the number of arguments expected in
833the path. However if no Args value is set, assumed to 'slurp' all
834remaining path pars under this namespace.
835
68c372d1 836=head2 Consumes('...')
837
838Matches the current action against the content-type of the request. Typically
839this is used when the request is a POST or PUT and you want to restrict the
840submitted content type. For example, you might have an HTML for that either
841returns classic url encoded form data, or JSON when Javascript is enabled. In
842this case you may wish to match either incoming type to one of two different
843actions, for properly processing.
844
845Examples:
846
847 sub is_json : Chained('start') Consumes('application/json') { ... }
848 sub is_urlencoded : Chained('start') Consumes('application/x-www-form-urlencoded') { ... }
849 sub is_multipart : Chained('start') Consumes('multipart/form-data') { ... }
850
851To reduce boilerplate, we include the following content type shortcuts:
852
853Examples
854
855 sub is_json : Chained('start') Consume(JSON) { ... }
856 sub is_urlencoded : Chained('start') Consumes(UrlEncoded) { ... }
857 sub is_multipart : Chained('start') Consumes(Multipart) { ... }
858
859You may specify more than one match:
860
861 sub is_more_than_one
862 : Chained('start')
863 : Consumes('application/x-www-form-urlencoded')
864 : Consumes('multipart/form-data')
865
866 sub is_more_than_one
867 : Chained('start')
868 : Consumes(UrlEncoded)
869 : Consumes(Multipart)
870
871Since it is a common case the shortcut C<HTMLForm> matches both
872'application/x-www-form-urlencoded' and 'multipart/form-data'. Here's the full
873list of available shortcuts:
874
875 JSON => 'application/json',
876 JS => 'application/javascript',
877 PERL => 'application/perl',
878 HTML => 'text/html',
879 XML => 'text/XML',
880 Plain => 'text/plain',
881 UrlEncoded => 'application/x-www-form-urlencoded',
882 Multipart => 'multipart/form-data',
883 HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
884
885Please keep in mind that when dispatching, L<Catalyst> will match the first most
efba3342 886relevant case, so if you use the C<Consumes> attribute, you should place your
68c372d1 887most accurate matches early in the Chain, and your 'catchall' actions last.
888
889See L<Catalyst::ActionRole::ConsumesContent> for more.
890
5b41c28c 891=head1 OPTIONAL METHODS
892
893=head2 _parse_[$name]_attr
894
895Allows you to customize parsing of subroutine attributes.
896
897 sub myaction1 :Path TwoArgs { ... }
898
899 sub _parse_TwoArgs_attr {
900 my ( $self, $c, $name, $value ) = @_;
901 # $self -> controller instance
902 #
903 return(Args => 2);
904 }
905
906Please note that this feature does not let you actually assign new functions
907to actions via subroutine attributes, but is really more for creating useful
908aliases to existing core and extended attributes, and transforms based on
909existing information (like from configuration). Code for actually doing
910something meaningful with the subroutine attributes will be located in the
911L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
912in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
913called basically once when the application is starting, not per request!
914
0bf7ab71 915=head1 AUTHORS
5ee249f2 916
0bf7ab71 917Catalyst Contributors, see Catalyst.pm
5ee249f2 918
919=head1 COPYRIGHT
920
536bee89 921This library is free software. You can redistribute it and/or modify
a269e0c2 922it under the same terms as Perl itself.
5ee249f2 923
924=cut