instead of using MI, compose a role which brings in the same Inheritable behaviour
[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
123#to ble 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
ae29b412 323 Class::MOP::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};
371 return @roles;
372}
373
234763d4 374sub _parse_attrs {
375 my ( $self, $c, $name, @attrs ) = @_;
376
377 my %raw_attributes;
378
379 foreach my $attr (@attrs) {
380
381 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
382
383 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
384 {
385
386 if ( defined $value ) {
387 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
388 }
389 push( @{ $raw_attributes{$key} }, $value );
390 }
391 }
392
bdd6684e 393 my ($actions_config, $all_actions_config);
ae29b412 394 if( ref($self) ) {
bdd6684e 395 $actions_config = $self->_controller_actions;
396 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
397 $all_actions_config = $self->_all_actions_attributes;
ae29b412 398 } else {
399 my $cfg = $self->config;
bdd6684e 400 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
401 $all_actions_config = {};
234763d4 402 }
403
ed9d06b6 404 %raw_attributes = (
405 %raw_attributes,
e95b2b49 406 # Note we deep copy array refs here to stop crapping on config
407 # when attributes are parsed. RT#65463
408 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
ed9d06b6 409 );
ae29b412 410
ed9d06b6 411 # Private actions with additional attributes will raise a warning and then
412 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
413 # which are Private, will prevent those from being registered. They should
414 # probably be turned into :Actions instead, or we might want to otherwise
415 # disambiguate between those built-in internal actions and user-level
416 # Private ones.
bdd6684e 417 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
418 unless $raw_attributes{Private};
ae29b412 419
234763d4 420 my %final_attributes;
421
0b0aee67 422 while (my ($key, $value) = each %raw_attributes){
423 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
424 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
425 }
234763d4 426
0b0aee67 427 return \%final_attributes;
428}
234763d4 429
0b0aee67 430sub _parse_attr {
431 my ($self, $c, $name, $key, $values) = @_;
234763d4 432
0b0aee67 433 my %final_attributes;
434 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
435 my $meth = "_parse_${key}_attr";
436 if ( my $code = $self->can($meth) ) {
437 my %new_attrs = $self->$code( $c, $name, $value );
438 while (my ($new_key, $value) = each %new_attrs){
439 my $new_attrs = $key eq $new_key ?
440 { $new_key => [$value] } :
441 $self->_parse_attr($c, $name, $new_key => $value );
442 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
234763d4 443 }
0b0aee67 444 }
445 else {
234763d4 446 push( @{ $final_attributes{$key} }, $value );
447 }
448 }
449
450 return \%final_attributes;
451}
452
453sub _parse_Global_attr {
454 my ( $self, $c, $name, $value ) = @_;
0b0aee67 455 # _parse_attr will call _parse_Path_attr for us
456 return Path => "/$name";
234763d4 457}
458
459sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
460
461sub _parse_Local_attr {
462 my ( $self, $c, $name, $value ) = @_;
0b0aee67 463 # _parse_attr will call _parse_Path_attr for us
464 return Path => $name;
234763d4 465}
466
467sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
468
469sub _parse_Path_attr {
470 my ( $self, $c, $name, $value ) = @_;
53119b78 471 $value = '' if !defined $value;
234763d4 472 if ( $value =~ m!^/! ) {
473 return ( 'Path', $value );
474 }
475 elsif ( length $value ) {
476 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
477 }
478 else {
479 return ( 'Path', $self->path_prefix($c) );
480 }
481}
482
f3107403 483sub _parse_Chained_attr {
484 my ($self, $c, $name, $value) = @_;
485
486 if (defined($value) && length($value)) {
487 if ($value eq '.') {
488 $value = '/'.$self->action_namespace($c);
fb56008f 489 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 490 my @parts = split '/', $self->action_namespace($c);
fb56008f 491 my @levels = split '/', $rel;
492
493 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 494 } elsif ($value !~ m/^\//) {
495 my $action_ns = $self->action_namespace($c);
496
497 if ($action_ns) {
498 $value = '/'.join('/', $action_ns, $value);
499 } else {
500 $value = '/'.$value; # special case namespace '' (root)
501 }
502 }
503 } else {
504 $value = '/'
505 }
506
507 return Chained => $value;
508}
509
9356b981 510sub _parse_ChainedParent_attr {
511 my ($self, $c, $name, $value) = @_;
512 return $self->_parse_Chained_attr($c, $name, '../'.$name);
513}
514
e5d2cfdb 515sub _parse_PathPrefix_attr {
02825551 516 my ( $self, $c ) = @_;
517 return PathPart => $self->path_prefix($c);
e5d2cfdb 518}
519
234763d4 520sub _parse_ActionClass_attr {
521 my ( $self, $c, $name, $value ) = @_;
5d8129e9 522 my $appname = $self->_application;
523 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 524 return ( 'ActionClass', $value );
525}
526
9287719b 527sub _parse_MyAction_attr {
528 my ( $self, $c, $name, $value ) = @_;
529
530 my $appclass = Catalyst::Utils::class2appclass($self);
0b0aee67 531 $value = "+${appclass}::Action::${value}";
234763d4 532
9287719b 533 return ( 'ActionClass', $value );
534}
234763d4 535
eff60019 536sub _parse_Does_attr {
537 my ($self, $app, $name, $value) = @_;
538 return Does => $self->_expand_role_shortname($value);
539}
540
ba3f8a81 541sub _parse_GET_attr { Method => 'GET' }
542sub _parse_POST_attr { Method => 'POST' }
543sub _parse_PUT_attr { Method => 'PUT' }
760d121e 544sub _parse_DELETE_attr { Method => 'DELETE' }
545sub _parse_OPTION_attr { Method => 'OPTION' }
ba3f8a81 546sub _parse_HEAD_attr { Method => 'HEAD' }
760d121e 547
eff60019 548sub _expand_role_shortname {
549 my ($self, @shortnames) = @_;
550 my $app = $self->_application;
551
552 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
553 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
554
555 return String::RewritePrefix->rewrite(
556 { '' => sub {
c6392ad5 557 my $loaded = load_first_existing_class(
eff60019 558 map { "$_$_[0]" } @prefixes
559 );
560 return first { $loaded =~ /^$_/ }
561 sort { length $b <=> length $a } @prefixes;
562 },
563 '~' => $prefixes[0],
564 '+' => '' },
565 @shortnames,
566 );
567}
568
ae29b412 569__PACKAGE__->meta->make_immutable;
570
234763d4 5711;
572
573__END__
574
575=head1 CONFIGURATION
576
a269e0c2 577Like any other L<Catalyst::Component>, controllers have a config hash,
578accessible through $self->config from the controller actions. Some
579settings are in use by the Catalyst framework:
234763d4 580
581=head2 namespace
582
a269e0c2 583This specifies the internal namespace the controller should be bound
584to. By default the controller is bound to the URI version of the
585controller name. For instance controller 'MyApp::Controller::Foo::Bar'
586will be bound to 'foo/bar'. The default Root controller is an example
587of setting namespace to '' (the null string).
234763d4 588
27ae4114 589=head2 path
234763d4 590
591Sets 'path_prefix', as described below.
592
0a2577a8 593=head2 action
594
595Allows you to set the attributes that the dispatcher creates actions out of.
596This allows you to do 'rails style routes', or override some of the
f4dda4a8 597attribute definitions of actions composed from Roles.
0a2577a8 598You can set arguments globally (for all actions of the controller) and
599specifically (for a single action).
600
601 __PACKAGE__->config(
602 action => {
603 '*' => { Chained => 'base', Args => 0 },
604 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
605 },
606 );
607
608In the case above every sub in the package would be made into a Chain
609endpoint with a URI the same as the sub name for each sub, chained
610to the sub named C<base>. Ergo dispatch to C</example> would call the
611C<base> method, then the C<example> method.
612
c8136648 613=head2 action_args
614
4d4e5de8 615Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 616globally and specifically (as above).
617This is particularly useful when using C<ActionRole>s
b939ae6b 618(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 619
b939ae6b 620 __PACKAGE__->config(
c8136648 621 action_args => {
b939ae6b 622 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
623 'specific_action' => { customarg => 'arg1' },
cea3f28a 624 },
b939ae6b 625 );
cea3f28a 626
b939ae6b 627In the case above the action class associated with C<specific_action> would get
628passed the following arguments, in addition to the normal action constructor
629arguments, when it is instantiated:
630
631 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 632
234763d4 633=head1 METHODS
634
c4d02967 635=head2 BUILDARGS ($app, @args)
234763d4 636
c4d02967 637From L<Catalyst::Component::ApplicationAttribute>, stashes the application
638instance as $self->_application.
234763d4 639
640=head2 $self->action_for('name')
641
a269e0c2 642Returns the Catalyst::Action object (if any) for a given method name
643in this component.
234763d4 644
234763d4 645=head2 $self->action_namespace($c)
646
a269e0c2 647Returns the private namespace for actions in this component. Defaults
648to a value from the controller name (for
649e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
650overridden from the "namespace" config key.
234763d4 651
652
653=head2 $self->path_prefix($c)
654
4ba7161b 655Returns the default path prefix for :PathPrefix, :Local and
e5d2cfdb 656relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 657can be overridden from the "path" config key.
234763d4 658
c4d02967 659=head2 $self->register_actions($c)
660
661Finds all applicable actions for this component, creates
662Catalyst::Action objects (using $self->create_action) for them and
663registers them with $c->dispatcher.
664
665=head2 $self->get_action_methods()
666
667Returns a list of L<Moose::Meta::Method> objects, doing the
668L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
669action methods for this package.
670
671=head2 $self->register_action_methods($c, @methods)
672
673Creates action objects for a set of action methods using C< create_action >,
674and registers them with the dispatcher.
675
f0a9b791 676=head2 $self->action_class(%args)
677
678Used when a controller is creating an action to determine the correct base
24d2dfaf 679action class to use.
f0a9b791 680
234763d4 681=head2 $self->create_action(%args)
682
a269e0c2 683Called with a hash of data to be use for construction of a new
684Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 685
eff60019 686=head2 $self->gather_action_roles(\%action_args)
687
688Gathers the list of roles to apply to an action with the given %action_args.
689
60034b8c 690=head2 $self->gather_default_action_roles(\%action_args)
691
692returns a list of action roles to be applied based on core, builtin rules.
693Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
694this way.
695
a269e0c2 696=head2 $self->_application
234763d4 697
698=head2 $self->_app
699
700Returns the application instance stored by C<new()>
5ee249f2 701
5b41c28c 702=head1 ACTION SUBROUTINE ATTRIBUTES
703
704Please see L<Catalyst::Manual::Intro> for more details
705
706Think of action attributes as a sort of way to record metadata about an action,
707similar to how annotations work in other languages you might have heard of.
708Generally L<Catalyst> uses these to influence how the dispatcher sees your
709action and when it will run it in response to an incoming request. They can
710also be used for other things. Here's a summary, but you should refer to the
711liked manual page for additional help.
712
713=head2 Global
714
715 sub homepage :Global { ... }
716
717A global action defined in any controller always runs relative to your root.
718So the above is the same as:
719
720 sub myaction :Path("/homepage") { ... }
721
722=head2 Absolute
723
724Status: Deprecated alias to L</Global>.
725
726=head2 Local
727
728Alias to "Path("$action_name"). The following two actions are the same:
729
730 sub myaction :Local { ... }
731 sub myaction :Path('myaction') { ... }
732
733=head2 Relative
734
735Status: Deprecated alias to L</Local>
736
737=head2 Path
738
739Handle various types of paths:
740
741 package MyApp::Controller::Baz {
742
743 ...
744
745 sub myaction1 :Path { ... } # -> /baz
c59b922b 746 sub myaction2 :Path('foo') { ... } # -> /baz/foo
5b41c28c 747 sub myaction2 :Path('/bar') { ... } # -> /bar
748 }
749
750This is a general toolbox for attaching your action to a give path.
751
752
753=head2 Regex
754
755=head2 Regexp
756
5070f111 757B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 758If you really depend on this, install the standalone
759L<Catalyst::DispatchType::Regex> distribution.
5b41c28c 760
761A global way to match a give regular expression in the incoming request path.
762
763=head2 LocalRegex
764
765=head2 LocalRegexp
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.
770
5b41c28c 771Like L</Regex> but scoped under the namespace of the containing controller
772
773=head2 Chained
774
775=head2 ChainedParent
776
777=head2 PathPrefix
778
779=head2 PathPart
780
781=head2 CaptureArgs
782
783Please see L<Catalyst::DispatchType::Chained>
784
785=head2 ActionClass
786
787Set the base class for the action, defaults to L</Catalyst::Action>. It is now
788preferred to use L</Does>.
789
790=head2 MyAction
791
051a69b9 792Set the ActionClass using a custom Action in your project namespace.
793
794The following is exactly the same:
795
796 sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
797 sub foo_action2 : Local MyAction('Bar') { ... }
5b41c28c 798
799=head2 Does
800
801 package MyApp::Controller::Zoo;
802
803 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
804 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
805 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
806
807=head2 GET
808
809=head2 POST
810
811=head2 PUT
812
813=head2 DELETE
814
815=head2 OPTION
816
817=head2 HEAD
818
60034b8c 819=head2 PATCH
820
821=head2 Method('...')
822
823Sets the give action path to match the specified HTTP method, or via one of the
824broadly accepted methods of overriding the 'true' method (see
825L<Catalyst::ActionRole::HTTPMethods>).
5b41c28c 826
827=head2 Args
828
829When used with L</Path> indicates the number of arguments expected in
830the path. However if no Args value is set, assumed to 'slurp' all
831remaining path pars under this namespace.
832
833=head1 OPTIONAL METHODS
834
835=head2 _parse_[$name]_attr
836
837Allows you to customize parsing of subroutine attributes.
838
839 sub myaction1 :Path TwoArgs { ... }
840
841 sub _parse_TwoArgs_attr {
842 my ( $self, $c, $name, $value ) = @_;
843 # $self -> controller instance
844 #
845 return(Args => 2);
846 }
847
848Please note that this feature does not let you actually assign new functions
849to actions via subroutine attributes, but is really more for creating useful
850aliases to existing core and extended attributes, and transforms based on
851existing information (like from configuration). Code for actually doing
852something meaningful with the subroutine attributes will be located in the
853L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
854in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
855called basically once when the application is starting, not per request!
856
0bf7ab71 857=head1 AUTHORS
5ee249f2 858
0bf7ab71 859Catalyst Contributors, see Catalyst.pm
5ee249f2 860
861=head1 COPYRIGHT
862
536bee89 863This library is free software. You can redistribute it and/or modify
a269e0c2 864it under the same terms as Perl itself.
5ee249f2 865
866=cut