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