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