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