some sort of docs for controller action subroutine attributes
[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
ba545c13 12BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
234763d4 13
cf37d21a 14use MooseX::MethodAttributes;
234763d4 15use Catalyst::Exception;
16use Catalyst::Utils;
ae29b412 17
18with 'Catalyst::Component::ApplicationAttribute';
19
aea897b2 20has path_prefix => (
21 is => 'rw',
22 isa => 'Str',
23 init_arg => 'path',
24 predicate => 'has_path_prefix',
25);
26
27has action_namespace => (
28 is => 'rw',
29 isa => 'Str',
30 init_arg => 'namespace',
31 predicate => 'has_action_namespace',
32);
33
34has actions => (
35 accessor => '_controller_actions',
36 isa => 'HashRef',
37 init_arg => undef,
38);
ae29b412 39
eff60019 40has _action_role_args => (
41 traits => [qw(Array)],
42 isa => 'ArrayRef[Str]',
43 init_arg => 'action_roles',
44 default => sub { [] },
45 handles => {
46 _action_role_args => 'elements',
47 },
48);
49
50has _action_roles => (
51 traits => [qw(Array)],
52 isa => 'ArrayRef[RoleName]',
53 init_arg => undef,
54 lazy => 1,
55 builder => '_build__action_roles',
56 handles => {
57 _action_roles => 'elements',
58 },
59);
60
bf7c9c87 61has action_args => (is => 'ro');
62
bdd6684e 63# ->config(actions => { '*' => ...
64has _all_actions_attributes => (
65 is => 'ro',
66 isa => 'HashRef',
67 init_arg => undef,
68 lazy => 1,
69 builder => '_build__all_actions_attributes',
70);
71
7f22a5aa 72sub BUILD {
73 my ($self, $args) = @_;
ae29b412 74 my $action = delete $args->{action} || {};
75 my $actions = delete $args->{actions} || {};
7f22a5aa 76 my $attr_value = $self->merge_config_hashes($actions, $action);
77 $self->_controller_actions($attr_value);
5ee249f2 78
bdd6684e 79 # trigger lazy builder
80 $self->_all_actions_attributes;
eff60019 81 $self->_action_roles;
82}
83
84sub _build__action_roles {
85 my $self = shift;
86 my @roles = $self->_expand_role_shortname($self->_action_role_args);
c6392ad5 87 load_class($_) for @roles;
eff60019 88 return \@roles;
bdd6684e 89}
d0e5dfb5 90
bdd6684e 91sub _build__all_actions_attributes {
92 my ($self) = @_;
93 delete $self->_controller_actions->{'*'} || {};
94}
d0e5dfb5 95
5ee249f2 96=head1 NAME
97
98Catalyst::Controller - Catalyst Controller base class
99
100=head1 SYNOPSIS
101
234763d4 102 package MyApp::Controller::Search
a269e0c2 103 use base qw/Catalyst::Controller/;
234763d4 104
27ae4114 105 sub foo : Local {
85d9fce6 106 my ($self,$c,@args) = @_;
27ae4114 107 ...
234763d4 108 } # Dispatches to /search/foo
5ee249f2 109
110=head1 DESCRIPTION
111
a269e0c2 112Controllers are where the actions in the Catalyst framework
113reside. Each action is represented by a function with an attribute to
114identify what kind of action it is. See the L<Catalyst::Dispatcher>
115for more info about how Catalyst dispatches to actions.
234763d4 116
117=cut
118
ae29b412 119#I think both of these could be attributes. doesn't really seem like they need
120#to ble class data. i think that attributes +default would work just fine
eff60019 121__PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
234763d4 122
123__PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
7b41db70 124__PACKAGE__->_action_class('Catalyst::Action');
eff60019 125__PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
234763d4 126
234763d4 127
128sub _DISPATCH : Private {
129 my ( $self, $c ) = @_;
130
131 foreach my $disp ( @{ $self->_dispatch_steps } ) {
132 last unless $c->forward($disp);
133 }
134
135 $c->forward('_END');
136}
137
138sub _BEGIN : Private {
139 my ( $self, $c ) = @_;
140 my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
141 return 1 unless $begin;
142 $begin->dispatch( $c );
143 return !@{ $c->error };
144}
145
146sub _AUTO : Private {
147 my ( $self, $c ) = @_;
148 my @auto = $c->get_actions( 'auto', $c->namespace );
149 foreach my $auto (@auto) {
150 $auto->dispatch( $c );
151 return 0 unless $c->state;
152 }
153 return 1;
154}
155
156sub _ACTION : Private {
157 my ( $self, $c ) = @_;
158 if ( ref $c->action
159 && $c->action->can('execute')
53119b78 160 && defined $c->req->action )
234763d4 161 {
162 $c->action->dispatch( $c );
163 }
164 return !@{ $c->error };
165}
166
167sub _END : Private {
168 my ( $self, $c ) = @_;
169 my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
170 return 1 unless $end;
171 $end->dispatch( $c );
172 return !@{ $c->error };
173}
174
234763d4 175sub action_for {
176 my ( $self, $name ) = @_;
177 my $app = ($self->isa('Catalyst') ? $self : $self->_application);
178 return $app->dispatcher->get_action($name, $self->action_namespace);
179}
180
27ae4114 181#my opinion is that this whole sub really should be a builder method, not
ae29b412 182#something that happens on every call. Anyone else disagree?? -- groditi
183## -- apparently this is all just waiting for app/ctx split
184around action_namespace => sub {
185 my $orig = shift;
234763d4 186 my ( $self, $c ) = @_;
ae29b412 187
df960201 188 my $class = ref($self) || $self;
189 my $appclass = ref($c) || $c;
ae29b412 190 if( ref($self) ){
191 return $self->$orig if $self->has_action_namespace;
192 } else {
df960201 193 return $class->config->{namespace} if exists $class->config->{namespace};
234763d4 194 }
234763d4 195
ae29b412 196 my $case_s;
197 if( $c ){
df960201 198 $case_s = $appclass->config->{case_sensitive};
ae29b412 199 } else {
200 if ($self->isa('Catalyst')) {
df960201 201 $case_s = $class->config->{case_sensitive};
ae29b412 202 } else {
203 if (ref $self) {
df960201 204 $case_s = ref($self->_application)->config->{case_sensitive};
ae29b412 205 } else {
206 confess("Can't figure out case_sensitive setting");
207 }
208 }
234763d4 209 }
ae29b412 210
8f6cebb2 211 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
ae29b412 212 $self->$orig($namespace) if ref($self);
213 return $namespace;
214};
215
216#Once again, this is probably better written as a builder method
217around path_prefix => sub {
218 my $orig = shift;
219 my $self = shift;
220 if( ref($self) ){
221 return $self->$orig if $self->has_path_prefix;
222 } else {
223 return $self->config->{path} if exists $self->config->{path};
224 }
225 my $namespace = $self->action_namespace(@_);
226 $self->$orig($namespace) if ref($self);
227 return $namespace;
228};
234763d4 229
9ab7d83d 230sub get_action_methods {
231 my $self = shift;
2bf074ab 232 my $meta = find_meta($self) || confess("No metaclass setup for $self");
69048792 233 confess(
234 sprintf "Metaclass %s for %s cannot support register_actions.",
235 ref $meta, $meta->name,
236 ) unless $meta->can('get_nearest_methods_with_attributes');
cf37d21a 237 my @methods = $meta->get_nearest_methods_with_attributes;
fa649eb7 238
239 # actions specified via config are also action_methods
240 push(
241 @methods,
242 map {
d0e78355 243 $meta->find_method_by_name($_)
e87273a4 244 || confess( sprintf 'Action "%s" is not available from controller %s',
245 $_, ref $self )
bdd6684e 246 } keys %{ $self->_controller_actions }
fa649eb7 247 ) if ( ref $self );
4f4ab5b4 248 return uniq @methods;
9ab7d83d 249}
234763d4 250
fa649eb7 251
234763d4 252sub register_actions {
253 my ( $self, $c ) = @_;
9ab7d83d 254 $self->register_action_methods( $c, $self->get_action_methods );
255}
256
257sub register_action_methods {
258 my ( $self, $c, @methods ) = @_;
8f6cebb2 259 my $class = $self->catalyst_component_name;
ae29b412 260 #this is still not correct for some reason.
234763d4 261 my $namespace = $self->action_namespace($c);
234763d4 262
f3c5b1c9 263 # FIXME - fugly
a202886b 264 if (!blessed($self) && $self eq $c && scalar(@methods)) {
f3c5b1c9 265 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
266 if (scalar(@really_bad_methods)) {
267 $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.");
268 }
a202886b 269 }
d2598ac8 270
ba545c13 271 foreach my $method (@methods) {
272 my $name = $method->name;
d0f30dbc 273 # Horrible hack! All method metaclasses should have an attributes
274 # method, core Moose bug - see r13354.
10e970e4 275 my $attributes = $method->can('attributes') ? $method->attributes : [];
ba545c13 276 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
234763d4 277 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
f63dea6f 278 $c->log->warn( 'Bad action definition "'
ba545c13 279 . join( ' ', @{ $attributes } )
280 . qq/" for "$class->$name"/ )
234763d4 281 if $c->debug;
282 next;
283 }
bc677969 284 my $reverse = $namespace ? "${namespace}/${name}" : $name;
234763d4 285 my $action = $self->create_action(
ba545c13 286 name => $name,
287 code => $method->body,
234763d4 288 reverse => $reverse,
289 namespace => $namespace,
290 class => $class,
291 attributes => $attrs,
292 );
293
294 $c->dispatcher->register( $c, $action );
295 }
296}
297
eff60019 298sub _apply_action_class_roles {
299 my ($self, $class, @roles) = @_;
300
c6392ad5 301 load_class($_) for @roles;
eff60019 302 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
303 superclasses => [$class],
304 roles => \@roles,
305 cache => 1,
306 );
307 $meta->add_method(meta => sub { $meta });
308
309 return $meta->name;
310}
311
f0a9b791 312sub action_class {
7b41db70 313 my $self = shift;
314 my %args = @_;
234763d4 315
316 my $class = (exists $args{attributes}{ActionClass}
f0a9b791 317 ? $args{attributes}{ActionClass}[0]
318 : $self->_action_class);
319
ae29b412 320 Class::MOP::load_class($class);
f0a9b791 321 return $class;
322}
323
324sub create_action {
325 my $self = shift;
326 my %args = @_;
a7e955ae 327
f0a9b791 328 my $class = $self->action_class(%args);
eff60019 329
330 load_class($class);
331 Moose->init_meta(for_class => $class)
332 unless Class::MOP::does_metaclass_exist($class);
333
334 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
335 my @roles = $self->gather_action_roles(%args);
336 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
337 }
338
bf7c9c87 339 my $action_args = (
340 ref($self)
341 ? $self->action_args
342 : $self->config->{action_args}
343 );
f0a9b791 344
a7e955ae 345 my %extra_args = (
346 %{ $action_args->{'*'} || {} },
347 %{ $action_args->{ $args{name} } || {} },
348 );
349
350 return $class->new({ %extra_args, %args });
234763d4 351}
352
eff60019 353sub gather_action_roles {
354 my ($self, %args) = @_;
355
356 return (
357 (blessed $self ? $self->_action_roles : ()),
358 @{ $args{attributes}->{Does} || [] },
359 );
360}
361
234763d4 362sub _parse_attrs {
363 my ( $self, $c, $name, @attrs ) = @_;
364
365 my %raw_attributes;
366
367 foreach my $attr (@attrs) {
368
369 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
370
371 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
372 {
373
374 if ( defined $value ) {
375 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
376 }
377 push( @{ $raw_attributes{$key} }, $value );
378 }
379 }
380
bdd6684e 381 my ($actions_config, $all_actions_config);
ae29b412 382 if( ref($self) ) {
bdd6684e 383 $actions_config = $self->_controller_actions;
384 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
385 $all_actions_config = $self->_all_actions_attributes;
ae29b412 386 } else {
387 my $cfg = $self->config;
bdd6684e 388 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
389 $all_actions_config = {};
234763d4 390 }
391
ed9d06b6 392 %raw_attributes = (
393 %raw_attributes,
e95b2b49 394 # Note we deep copy array refs here to stop crapping on config
395 # when attributes are parsed. RT#65463
396 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
ed9d06b6 397 );
ae29b412 398
ed9d06b6 399 # Private actions with additional attributes will raise a warning and then
400 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
401 # which are Private, will prevent those from being registered. They should
402 # probably be turned into :Actions instead, or we might want to otherwise
403 # disambiguate between those built-in internal actions and user-level
404 # Private ones.
bdd6684e 405 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
406 unless $raw_attributes{Private};
ae29b412 407
234763d4 408 my %final_attributes;
409
0b0aee67 410 while (my ($key, $value) = each %raw_attributes){
411 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
412 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
413 }
234763d4 414
0b0aee67 415 return \%final_attributes;
416}
234763d4 417
0b0aee67 418sub _parse_attr {
419 my ($self, $c, $name, $key, $values) = @_;
234763d4 420
0b0aee67 421 my %final_attributes;
422 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
423 my $meth = "_parse_${key}_attr";
424 if ( my $code = $self->can($meth) ) {
425 my %new_attrs = $self->$code( $c, $name, $value );
426 while (my ($new_key, $value) = each %new_attrs){
427 my $new_attrs = $key eq $new_key ?
428 { $new_key => [$value] } :
429 $self->_parse_attr($c, $name, $new_key => $value );
430 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
234763d4 431 }
0b0aee67 432 }
433 else {
234763d4 434 push( @{ $final_attributes{$key} }, $value );
435 }
436 }
437
438 return \%final_attributes;
439}
440
441sub _parse_Global_attr {
442 my ( $self, $c, $name, $value ) = @_;
0b0aee67 443 # _parse_attr will call _parse_Path_attr for us
444 return Path => "/$name";
234763d4 445}
446
447sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
448
449sub _parse_Local_attr {
450 my ( $self, $c, $name, $value ) = @_;
0b0aee67 451 # _parse_attr will call _parse_Path_attr for us
452 return Path => $name;
234763d4 453}
454
455sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
456
457sub _parse_Path_attr {
458 my ( $self, $c, $name, $value ) = @_;
53119b78 459 $value = '' if !defined $value;
234763d4 460 if ( $value =~ m!^/! ) {
461 return ( 'Path', $value );
462 }
463 elsif ( length $value ) {
464 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
465 }
466 else {
467 return ( 'Path', $self->path_prefix($c) );
468 }
469}
470
471sub _parse_Regex_attr {
472 my ( $self, $c, $name, $value ) = @_;
473 return ( 'Regex', $value );
474}
475
476sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
477
478sub _parse_LocalRegex_attr {
479 my ( $self, $c, $name, $value ) = @_;
480 unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
19c01ee1 481
482 my $prefix = $self->path_prefix( $c );
483 $prefix .= '/' if length( $prefix );
27ae4114 484
19c01ee1 485 return ( 'Regex', "^${prefix}${value}" );
234763d4 486}
487
488sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
489
f3107403 490sub _parse_Chained_attr {
491 my ($self, $c, $name, $value) = @_;
492
493 if (defined($value) && length($value)) {
494 if ($value eq '.') {
495 $value = '/'.$self->action_namespace($c);
fb56008f 496 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 497 my @parts = split '/', $self->action_namespace($c);
fb56008f 498 my @levels = split '/', $rel;
499
500 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 501 } elsif ($value !~ m/^\//) {
502 my $action_ns = $self->action_namespace($c);
503
504 if ($action_ns) {
505 $value = '/'.join('/', $action_ns, $value);
506 } else {
507 $value = '/'.$value; # special case namespace '' (root)
508 }
509 }
510 } else {
511 $value = '/'
512 }
513
514 return Chained => $value;
515}
516
9356b981 517sub _parse_ChainedParent_attr {
518 my ($self, $c, $name, $value) = @_;
519 return $self->_parse_Chained_attr($c, $name, '../'.$name);
520}
521
e5d2cfdb 522sub _parse_PathPrefix_attr {
02825551 523 my ( $self, $c ) = @_;
524 return PathPart => $self->path_prefix($c);
e5d2cfdb 525}
526
234763d4 527sub _parse_ActionClass_attr {
528 my ( $self, $c, $name, $value ) = @_;
5d8129e9 529 my $appname = $self->_application;
530 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 531 return ( 'ActionClass', $value );
532}
533
9287719b 534sub _parse_MyAction_attr {
535 my ( $self, $c, $name, $value ) = @_;
536
537 my $appclass = Catalyst::Utils::class2appclass($self);
0b0aee67 538 $value = "+${appclass}::Action::${value}";
234763d4 539
9287719b 540 return ( 'ActionClass', $value );
541}
234763d4 542
eff60019 543sub _parse_Does_attr {
544 my ($self, $app, $name, $value) = @_;
545 return Does => $self->_expand_role_shortname($value);
546}
547
760d121e 548sub _parse_GET_attr { Method => 'GET' }
549sub _parse_POST_attr { Method => 'POST' }
550sub _parse_PUT_attr { Method => 'PUT' }
551sub _parse_DELETE_attr { Method => 'DELETE' }
552sub _parse_OPTION_attr { Method => 'OPTION' }
553sub _parse_HEAD_attr { Method => 'HEAD' }
554
eff60019 555sub _expand_role_shortname {
556 my ($self, @shortnames) = @_;
557 my $app = $self->_application;
558
559 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
560 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
561
562 return String::RewritePrefix->rewrite(
563 { '' => sub {
c6392ad5 564 my $loaded = load_first_existing_class(
eff60019 565 map { "$_$_[0]" } @prefixes
566 );
567 return first { $loaded =~ /^$_/ }
568 sort { length $b <=> length $a } @prefixes;
569 },
570 '~' => $prefixes[0],
571 '+' => '' },
572 @shortnames,
573 );
574}
575
ae29b412 576__PACKAGE__->meta->make_immutable;
577
234763d4 5781;
579
580__END__
581
582=head1 CONFIGURATION
583
a269e0c2 584Like any other L<Catalyst::Component>, controllers have a config hash,
585accessible through $self->config from the controller actions. Some
586settings are in use by the Catalyst framework:
234763d4 587
588=head2 namespace
589
a269e0c2 590This specifies the internal namespace the controller should be bound
591to. By default the controller is bound to the URI version of the
592controller name. For instance controller 'MyApp::Controller::Foo::Bar'
593will be bound to 'foo/bar'. The default Root controller is an example
594of setting namespace to '' (the null string).
234763d4 595
27ae4114 596=head2 path
234763d4 597
598Sets 'path_prefix', as described below.
599
0a2577a8 600=head2 action
601
602Allows you to set the attributes that the dispatcher creates actions out of.
603This allows you to do 'rails style routes', or override some of the
f4dda4a8 604attribute definitions of actions composed from Roles.
0a2577a8 605You can set arguments globally (for all actions of the controller) and
606specifically (for a single action).
607
608 __PACKAGE__->config(
609 action => {
610 '*' => { Chained => 'base', Args => 0 },
611 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
612 },
613 );
614
615In the case above every sub in the package would be made into a Chain
616endpoint with a URI the same as the sub name for each sub, chained
617to the sub named C<base>. Ergo dispatch to C</example> would call the
618C<base> method, then the C<example> method.
619
c8136648 620=head2 action_args
621
4d4e5de8 622Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 623globally and specifically (as above).
624This is particularly useful when using C<ActionRole>s
b939ae6b 625(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 626
b939ae6b 627 __PACKAGE__->config(
c8136648 628 action_args => {
b939ae6b 629 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
630 'specific_action' => { customarg => 'arg1' },
cea3f28a 631 },
b939ae6b 632 );
cea3f28a 633
b939ae6b 634In the case above the action class associated with C<specific_action> would get
635passed the following arguments, in addition to the normal action constructor
636arguments, when it is instantiated:
637
638 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 639
234763d4 640=head1 METHODS
641
c4d02967 642=head2 BUILDARGS ($app, @args)
234763d4 643
c4d02967 644From L<Catalyst::Component::ApplicationAttribute>, stashes the application
645instance as $self->_application.
234763d4 646
647=head2 $self->action_for('name')
648
a269e0c2 649Returns the Catalyst::Action object (if any) for a given method name
650in this component.
234763d4 651
234763d4 652=head2 $self->action_namespace($c)
653
a269e0c2 654Returns the private namespace for actions in this component. Defaults
655to a value from the controller name (for
656e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
657overridden from the "namespace" config key.
234763d4 658
659
660=head2 $self->path_prefix($c)
661
e5d2cfdb 662Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
663relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 664can be overridden from the "path" config key.
234763d4 665
c4d02967 666=head2 $self->register_actions($c)
667
668Finds all applicable actions for this component, creates
669Catalyst::Action objects (using $self->create_action) for them and
670registers them with $c->dispatcher.
671
672=head2 $self->get_action_methods()
673
674Returns a list of L<Moose::Meta::Method> objects, doing the
675L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
676action methods for this package.
677
678=head2 $self->register_action_methods($c, @methods)
679
680Creates action objects for a set of action methods using C< create_action >,
681and registers them with the dispatcher.
682
f0a9b791 683=head2 $self->action_class(%args)
684
685Used when a controller is creating an action to determine the correct base
24d2dfaf 686action class to use.
f0a9b791 687
234763d4 688=head2 $self->create_action(%args)
689
a269e0c2 690Called with a hash of data to be use for construction of a new
691Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 692
eff60019 693=head2 $self->gather_action_roles(\%action_args)
694
695Gathers the list of roles to apply to an action with the given %action_args.
696
a269e0c2 697=head2 $self->_application
234763d4 698
699=head2 $self->_app
700
701Returns the application instance stored by C<new()>
5ee249f2 702
5b41c28c 703=head1 ACTION SUBROUTINE ATTRIBUTES
704
705Please see L<Catalyst::Manual::Intro> for more details
706
707Think of action attributes as a sort of way to record metadata about an action,
708similar to how annotations work in other languages you might have heard of.
709Generally L<Catalyst> uses these to influence how the dispatcher sees your
710action and when it will run it in response to an incoming request. They can
711also be used for other things. Here's a summary, but you should refer to the
712liked manual page for additional help.
713
714=head2 Global
715
716 sub homepage :Global { ... }
717
718A global action defined in any controller always runs relative to your root.
719So the above is the same as:
720
721 sub myaction :Path("/homepage") { ... }
722
723=head2 Absolute
724
725Status: Deprecated alias to L</Global>.
726
727=head2 Local
728
729Alias to "Path("$action_name"). The following two actions are the same:
730
731 sub myaction :Local { ... }
732 sub myaction :Path('myaction') { ... }
733
734=head2 Relative
735
736Status: Deprecated alias to L</Local>
737
738=head2 Path
739
740Handle various types of paths:
741
742 package MyApp::Controller::Baz {
743
744 ...
745
746 sub myaction1 :Path { ... } # -> /baz
747 sub myaction2 :Path('foo') { ... } # -> /baz/bar
748 sub myaction2 :Path('/bar') { ... } # -> /bar
749 }
750
751This is a general toolbox for attaching your action to a give path.
752
753
754=head2 Regex
755
756=head2 Regexp
757
758Status: Deprecated. Use Chained methods or other techniques
759
760A global way to match a give regular expression in the incoming request path.
761
762=head2 LocalRegex
763
764=head2 LocalRegexp
765
766Like L</Regex> but scoped under the namespace of the containing controller
767
768=head2 Chained
769
770=head2 ChainedParent
771
772=head2 PathPrefix
773
774=head2 PathPart
775
776=head2 CaptureArgs
777
778Please see L<Catalyst::DispatchType::Chained>
779
780=head2 ActionClass
781
782Set the base class for the action, defaults to L</Catalyst::Action>. It is now
783preferred to use L</Does>.
784
785=head2 MyAction
786
787Set the ActionClass using a custom Action in your project namespace (such as
788C<MyApp::Action::MyAction> => MyAction('MyAction').
789
790=head2 Does
791
792 package MyApp::Controller::Zoo;
793
794 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
795 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
796 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
797
798=head2 GET
799
800=head2 POST
801
802=head2 PUT
803
804=head2 DELETE
805
806=head2 OPTION
807
808=head2 HEAD
809
810Sets the give action path to match the specified HTTP method.
811
812=head2 Args
813
814When used with L</Path> indicates the number of arguments expected in
815the path. However if no Args value is set, assumed to 'slurp' all
816remaining path pars under this namespace.
817
818=head1 OPTIONAL METHODS
819
820=head2 _parse_[$name]_attr
821
822Allows you to customize parsing of subroutine attributes.
823
824 sub myaction1 :Path TwoArgs { ... }
825
826 sub _parse_TwoArgs_attr {
827 my ( $self, $c, $name, $value ) = @_;
828 # $self -> controller instance
829 #
830 return(Args => 2);
831 }
832
833Please note that this feature does not let you actually assign new functions
834to actions via subroutine attributes, but is really more for creating useful
835aliases to existing core and extended attributes, and transforms based on
836existing information (like from configuration). Code for actually doing
837something meaningful with the subroutine attributes will be located in the
838L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
839in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
840called basically once when the application is starting, not per request!
841
0bf7ab71 842=head1 AUTHORS
5ee249f2 843
0bf7ab71 844Catalyst Contributors, see Catalyst.pm
5ee249f2 845
846=head1 COPYRIGHT
847
536bee89 848This library is free software. You can redistribute it and/or modify
a269e0c2 849it under the same terms as Perl itself.
5ee249f2 850
851=cut