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