Use Ref::Util where appropriate
[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/;
dd4530ec 10use Ref::Util qw(is_plain_arrayref);
ae29b412 11use namespace::clean -except => 'meta';
12
a0c37f08 13BEGIN {
14 extends qw/Catalyst::Component/;
15 with qw/MooseX::MethodAttributes::Role::AttrContainer::Inheritable/;
16}
234763d4 17
cf37d21a 18use MooseX::MethodAttributes;
234763d4 19use Catalyst::Exception;
20use Catalyst::Utils;
ae29b412 21
22with 'Catalyst::Component::ApplicationAttribute';
23
aea897b2 24has path_prefix => (
25 is => 'rw',
26 isa => 'Str',
27 init_arg => 'path',
28 predicate => 'has_path_prefix',
29);
30
31has action_namespace => (
32 is => 'rw',
33 isa => 'Str',
34 init_arg => 'namespace',
35 predicate => 'has_action_namespace',
36);
37
38has actions => (
39 accessor => '_controller_actions',
40 isa => 'HashRef',
41 init_arg => undef,
42);
ae29b412 43
eff60019 44has _action_role_args => (
45 traits => [qw(Array)],
46 isa => 'ArrayRef[Str]',
47 init_arg => 'action_roles',
48 default => sub { [] },
49 handles => {
50 _action_role_args => 'elements',
51 },
52);
53
54has _action_roles => (
55 traits => [qw(Array)],
56 isa => 'ArrayRef[RoleName]',
57 init_arg => undef,
58 lazy => 1,
59 builder => '_build__action_roles',
60 handles => {
61 _action_roles => 'elements',
62 },
63);
64
bf7c9c87 65has action_args => (is => 'ro');
66
bdd6684e 67# ->config(actions => { '*' => ...
68has _all_actions_attributes => (
69 is => 'ro',
70 isa => 'HashRef',
71 init_arg => undef,
72 lazy => 1,
73 builder => '_build__all_actions_attributes',
74);
75
7f22a5aa 76sub BUILD {
77 my ($self, $args) = @_;
ae29b412 78 my $action = delete $args->{action} || {};
79 my $actions = delete $args->{actions} || {};
7f22a5aa 80 my $attr_value = $self->merge_config_hashes($actions, $action);
81 $self->_controller_actions($attr_value);
5ee249f2 82
bdd6684e 83 # trigger lazy builder
84 $self->_all_actions_attributes;
eff60019 85 $self->_action_roles;
86}
87
88sub _build__action_roles {
89 my $self = shift;
90 my @roles = $self->_expand_role_shortname($self->_action_role_args);
c6392ad5 91 load_class($_) for @roles;
eff60019 92 return \@roles;
bdd6684e 93}
d0e5dfb5 94
bdd6684e 95sub _build__all_actions_attributes {
96 my ($self) = @_;
97 delete $self->_controller_actions->{'*'} || {};
98}
d0e5dfb5 99
5ee249f2 100=head1 NAME
101
102Catalyst::Controller - Catalyst Controller base class
103
104=head1 SYNOPSIS
105
234763d4 106 package MyApp::Controller::Search
a269e0c2 107 use base qw/Catalyst::Controller/;
234763d4 108
27ae4114 109 sub foo : Local {
85d9fce6 110 my ($self,$c,@args) = @_;
27ae4114 111 ...
234763d4 112 } # Dispatches to /search/foo
5ee249f2 113
114=head1 DESCRIPTION
115
a269e0c2 116Controllers are where the actions in the Catalyst framework
117reside. Each action is represented by a function with an attribute to
118identify what kind of action it is. See the L<Catalyst::Dispatcher>
119for more info about how Catalyst dispatches to actions.
234763d4 120
121=cut
122
ae29b412 123#I think both of these could be attributes. doesn't really seem like they need
bd85860b 124#to be class data. i think that attributes +default would work just fine
eff60019 125__PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
234763d4 126
127__PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
7b41db70 128__PACKAGE__->_action_class('Catalyst::Action');
eff60019 129__PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
234763d4 130
234763d4 131
132sub _DISPATCH : Private {
133 my ( $self, $c ) = @_;
134
135 foreach my $disp ( @{ $self->_dispatch_steps } ) {
136 last unless $c->forward($disp);
137 }
138
139 $c->forward('_END');
140}
141
142sub _BEGIN : Private {
143 my ( $self, $c ) = @_;
144 my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
145 return 1 unless $begin;
146 $begin->dispatch( $c );
e459bd03 147 #If there is an error, all bets off
148 if( @{ $c->error }) {
149 return !@{ $c->error };
150 } else {
151 return $c->state || 1;
152 }
234763d4 153}
154
155sub _AUTO : Private {
156 my ( $self, $c ) = @_;
157 my @auto = $c->get_actions( 'auto', $c->namespace );
158 foreach my $auto (@auto) {
4c71cf1b 159 # We FORCE the auto action user to explicitly return
160 # true. We need to do this since there's some auto
161 # users (Catalyst::Authentication::Credential::HTTP) that
162 # actually do a detach instead.
163 $c->state(0);
234763d4 164 $auto->dispatch( $c );
165 return 0 unless $c->state;
166 }
e459bd03 167 return $c->state || 1;
234763d4 168}
169
170sub _ACTION : Private {
171 my ( $self, $c ) = @_;
172 if ( ref $c->action
173 && $c->action->can('execute')
53119b78 174 && defined $c->req->action )
234763d4 175 {
176 $c->action->dispatch( $c );
177 }
e459bd03 178 #If there is an error, all bets off
179 if( @{ $c->error }) {
180 return !@{ $c->error };
181 } else {
182 return $c->state || 1;
183 }
234763d4 184}
185
186sub _END : Private {
187 my ( $self, $c ) = @_;
188 my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
189 return 1 unless $end;
190 $end->dispatch( $c );
191 return !@{ $c->error };
192}
193
234763d4 194sub action_for {
195 my ( $self, $name ) = @_;
196 my $app = ($self->isa('Catalyst') ? $self : $self->_application);
197 return $app->dispatcher->get_action($name, $self->action_namespace);
198}
199
27ae4114 200#my opinion is that this whole sub really should be a builder method, not
ae29b412 201#something that happens on every call. Anyone else disagree?? -- groditi
202## -- apparently this is all just waiting for app/ctx split
203around action_namespace => sub {
204 my $orig = shift;
234763d4 205 my ( $self, $c ) = @_;
ae29b412 206
df960201 207 my $class = ref($self) || $self;
208 my $appclass = ref($c) || $c;
ae29b412 209 if( ref($self) ){
210 return $self->$orig if $self->has_action_namespace;
211 } else {
df960201 212 return $class->config->{namespace} if exists $class->config->{namespace};
234763d4 213 }
234763d4 214
ae29b412 215 my $case_s;
216 if( $c ){
df960201 217 $case_s = $appclass->config->{case_sensitive};
ae29b412 218 } else {
219 if ($self->isa('Catalyst')) {
df960201 220 $case_s = $class->config->{case_sensitive};
ae29b412 221 } else {
222 if (ref $self) {
df960201 223 $case_s = ref($self->_application)->config->{case_sensitive};
ae29b412 224 } else {
225 confess("Can't figure out case_sensitive setting");
226 }
227 }
234763d4 228 }
ae29b412 229
8f6cebb2 230 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
ae29b412 231 $self->$orig($namespace) if ref($self);
232 return $namespace;
233};
234
235#Once again, this is probably better written as a builder method
236around path_prefix => sub {
237 my $orig = shift;
238 my $self = shift;
239 if( ref($self) ){
240 return $self->$orig if $self->has_path_prefix;
241 } else {
242 return $self->config->{path} if exists $self->config->{path};
243 }
244 my $namespace = $self->action_namespace(@_);
245 $self->$orig($namespace) if ref($self);
246 return $namespace;
247};
234763d4 248
9ab7d83d 249sub get_action_methods {
250 my $self = shift;
2bf074ab 251 my $meta = find_meta($self) || confess("No metaclass setup for $self");
69048792 252 confess(
253 sprintf "Metaclass %s for %s cannot support register_actions.",
254 ref $meta, $meta->name,
255 ) unless $meta->can('get_nearest_methods_with_attributes');
cf37d21a 256 my @methods = $meta->get_nearest_methods_with_attributes;
fa649eb7 257
258 # actions specified via config are also action_methods
259 push(
260 @methods,
261 map {
d0e78355 262 $meta->find_method_by_name($_)
e87273a4 263 || confess( sprintf 'Action "%s" is not available from controller %s',
264 $_, ref $self )
bdd6684e 265 } keys %{ $self->_controller_actions }
fa649eb7 266 ) if ( ref $self );
4f4ab5b4 267 return uniq @methods;
9ab7d83d 268}
234763d4 269
fa649eb7 270
234763d4 271sub register_actions {
272 my ( $self, $c ) = @_;
9ab7d83d 273 $self->register_action_methods( $c, $self->get_action_methods );
274}
275
276sub register_action_methods {
277 my ( $self, $c, @methods ) = @_;
8f6cebb2 278 my $class = $self->catalyst_component_name;
ae29b412 279 #this is still not correct for some reason.
234763d4 280 my $namespace = $self->action_namespace($c);
234763d4 281
f3c5b1c9 282 # FIXME - fugly
a202886b 283 if (!blessed($self) && $self eq $c && scalar(@methods)) {
f3c5b1c9 284 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
285 if (scalar(@really_bad_methods)) {
286 $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.");
287 }
a202886b 288 }
d2598ac8 289
ba545c13 290 foreach my $method (@methods) {
291 my $name = $method->name;
d0f30dbc 292 # Horrible hack! All method metaclasses should have an attributes
293 # method, core Moose bug - see r13354.
10e970e4 294 my $attributes = $method->can('attributes') ? $method->attributes : [];
ba545c13 295 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
234763d4 296 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
f63dea6f 297 $c->log->warn( 'Bad action definition "'
ba545c13 298 . join( ' ', @{ $attributes } )
299 . qq/" for "$class->$name"/ )
234763d4 300 if $c->debug;
301 next;
302 }
bc677969 303 my $reverse = $namespace ? "${namespace}/${name}" : $name;
234763d4 304 my $action = $self->create_action(
ba545c13 305 name => $name,
306 code => $method->body,
234763d4 307 reverse => $reverse,
308 namespace => $namespace,
309 class => $class,
310 attributes => $attrs,
311 );
312
313 $c->dispatcher->register( $c, $action );
314 }
315}
316
eff60019 317sub _apply_action_class_roles {
318 my ($self, $class, @roles) = @_;
319
c6392ad5 320 load_class($_) for @roles;
eff60019 321 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
322 superclasses => [$class],
323 roles => \@roles,
324 cache => 1,
325 );
326 $meta->add_method(meta => sub { $meta });
327
328 return $meta->name;
329}
330
f0a9b791 331sub action_class {
7b41db70 332 my $self = shift;
333 my %args = @_;
234763d4 334
335 my $class = (exists $args{attributes}{ActionClass}
f0a9b791 336 ? $args{attributes}{ActionClass}[0]
337 : $self->_action_class);
338
e7399d8b 339 load_class($class);
f0a9b791 340 return $class;
341}
342
343sub create_action {
344 my $self = shift;
345 my %args = @_;
a7e955ae 346
f0a9b791 347 my $class = $self->action_class(%args);
eff60019 348
349 load_class($class);
350 Moose->init_meta(for_class => $class)
351 unless Class::MOP::does_metaclass_exist($class);
352
353 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
354 my @roles = $self->gather_action_roles(%args);
60034b8c 355 push @roles, $self->gather_default_action_roles(%args);
356
eff60019 357 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
358 }
359
bf7c9c87 360 my $action_args = (
361 ref($self)
362 ? $self->action_args
363 : $self->config->{action_args}
364 );
f0a9b791 365
a7e955ae 366 my %extra_args = (
367 %{ $action_args->{'*'} || {} },
368 %{ $action_args->{ $args{name} } || {} },
369 );
370
371 return $class->new({ %extra_args, %args });
234763d4 372}
373
eff60019 374sub gather_action_roles {
375 my ($self, %args) = @_;
eff60019 376 return (
377 (blessed $self ? $self->_action_roles : ()),
378 @{ $args{attributes}->{Does} || [] },
379 );
380}
381
60034b8c 382sub gather_default_action_roles {
383 my ($self, %args) = @_;
384 my @roles = ();
385 push @roles, 'Catalyst::ActionRole::HTTPMethods'
386 if $args{attributes}->{Method};
3e0665e4 387
388 push @roles, 'Catalyst::ActionRole::ConsumesContent'
389 if $args{attributes}->{Consumes};
390
342d2169 391 push @roles, 'Catalyst::ActionRole::Scheme'
392 if $args{attributes}->{Scheme};
25ca36c2 393
394 push @roles, 'Catalyst::ActionRole::QueryMatching'
395 if $args{attributes}->{Query};
3e0665e4 396 return @roles;
60034b8c 397}
398
234763d4 399sub _parse_attrs {
400 my ( $self, $c, $name, @attrs ) = @_;
401
402 my %raw_attributes;
403
404 foreach my $attr (@attrs) {
405
406 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
407
698e6f19 408 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)?\s*\))?$/ ) )
234763d4 409 {
410
411 if ( defined $value ) {
412 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
413 }
414 push( @{ $raw_attributes{$key} }, $value );
415 }
416 }
417
bdd6684e 418 my ($actions_config, $all_actions_config);
ae29b412 419 if( ref($self) ) {
bdd6684e 420 $actions_config = $self->_controller_actions;
421 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
422 $all_actions_config = $self->_all_actions_attributes;
ae29b412 423 } else {
424 my $cfg = $self->config;
bdd6684e 425 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
426 $all_actions_config = {};
234763d4 427 }
428
ed9d06b6 429 %raw_attributes = (
430 %raw_attributes,
e95b2b49 431 # Note we deep copy array refs here to stop crapping on config
432 # when attributes are parsed. RT#65463
dd4530ec 433 exists $actions_config->{$name} ? map { is_plain_arrayref($_) ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
ed9d06b6 434 );
ae29b412 435
ed9d06b6 436 # Private actions with additional attributes will raise a warning and then
437 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
438 # which are Private, will prevent those from being registered. They should
439 # probably be turned into :Actions instead, or we might want to otherwise
440 # disambiguate between those built-in internal actions and user-level
441 # Private ones.
bdd6684e 442 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
443 unless $raw_attributes{Private};
ae29b412 444
234763d4 445 my %final_attributes;
446
0b0aee67 447 while (my ($key, $value) = each %raw_attributes){
448 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
449 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
450 }
234763d4 451
0b0aee67 452 return \%final_attributes;
453}
234763d4 454
0b0aee67 455sub _parse_attr {
456 my ($self, $c, $name, $key, $values) = @_;
234763d4 457
0b0aee67 458 my %final_attributes;
dd4530ec 459 foreach my $value (is_plain_arrayref($values) ? @$values : $values) {
0b0aee67 460 my $meth = "_parse_${key}_attr";
461 if ( my $code = $self->can($meth) ) {
462 my %new_attrs = $self->$code( $c, $name, $value );
463 while (my ($new_key, $value) = each %new_attrs){
464 my $new_attrs = $key eq $new_key ?
465 { $new_key => [$value] } :
466 $self->_parse_attr($c, $name, $new_key => $value );
467 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
234763d4 468 }
0b0aee67 469 }
470 else {
234763d4 471 push( @{ $final_attributes{$key} }, $value );
472 }
473 }
474
475 return \%final_attributes;
476}
477
478sub _parse_Global_attr {
479 my ( $self, $c, $name, $value ) = @_;
0b0aee67 480 # _parse_attr will call _parse_Path_attr for us
481 return Path => "/$name";
234763d4 482}
483
484sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
485
486sub _parse_Local_attr {
487 my ( $self, $c, $name, $value ) = @_;
0b0aee67 488 # _parse_attr will call _parse_Path_attr for us
489 return Path => $name;
234763d4 490}
491
492sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
493
494sub _parse_Path_attr {
495 my ( $self, $c, $name, $value ) = @_;
53119b78 496 $value = '' if !defined $value;
234763d4 497 if ( $value =~ m!^/! ) {
498 return ( 'Path', $value );
499 }
500 elsif ( length $value ) {
501 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
502 }
503 else {
504 return ( 'Path', $self->path_prefix($c) );
505 }
506}
507
f3107403 508sub _parse_Chained_attr {
509 my ($self, $c, $name, $value) = @_;
510
511 if (defined($value) && length($value)) {
512 if ($value eq '.') {
513 $value = '/'.$self->action_namespace($c);
fb56008f 514 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
eb270c30 515 my @parts = split '/', $self->action_namespace($c);
fb56008f 516 my @levels = split '/', $rel;
517
518 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
f3107403 519 } elsif ($value !~ m/^\//) {
520 my $action_ns = $self->action_namespace($c);
521
522 if ($action_ns) {
523 $value = '/'.join('/', $action_ns, $value);
524 } else {
525 $value = '/'.$value; # special case namespace '' (root)
526 }
527 }
528 } else {
529 $value = '/'
530 }
531
532 return Chained => $value;
533}
534
9356b981 535sub _parse_ChainedParent_attr {
536 my ($self, $c, $name, $value) = @_;
537 return $self->_parse_Chained_attr($c, $name, '../'.$name);
538}
539
e5d2cfdb 540sub _parse_PathPrefix_attr {
02825551 541 my ( $self, $c ) = @_;
542 return PathPart => $self->path_prefix($c);
e5d2cfdb 543}
544
234763d4 545sub _parse_ActionClass_attr {
546 my ( $self, $c, $name, $value ) = @_;
5d8129e9 547 my $appname = $self->_application;
548 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
234763d4 549 return ( 'ActionClass', $value );
550}
551
9287719b 552sub _parse_MyAction_attr {
553 my ( $self, $c, $name, $value ) = @_;
554
555 my $appclass = Catalyst::Utils::class2appclass($self);
0b0aee67 556 $value = "+${appclass}::Action::${value}";
234763d4 557
9287719b 558 return ( 'ActionClass', $value );
559}
234763d4 560
eff60019 561sub _parse_Does_attr {
562 my ($self, $app, $name, $value) = @_;
563 return Does => $self->_expand_role_shortname($value);
564}
565
e2a8c7e5 566sub _parse_GET_attr { Method => 'GET' }
567sub _parse_POST_attr { Method => 'POST' }
568sub _parse_PUT_attr { Method => 'PUT' }
569sub _parse_DELETE_attr { Method => 'DELETE' }
570sub _parse_OPTIONS_attr { Method => 'OPTIONS' }
571sub _parse_HEAD_attr { Method => 'HEAD' }
9f3e69ee 572sub _parse_PATCH_attr { Method => 'PATCH' }
760d121e 573
eff60019 574sub _expand_role_shortname {
575 my ($self, @shortnames) = @_;
576 my $app = $self->_application;
577
578 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
579 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
580
581 return String::RewritePrefix->rewrite(
582 { '' => sub {
c6392ad5 583 my $loaded = load_first_existing_class(
eff60019 584 map { "$_$_[0]" } @prefixes
585 );
586 return first { $loaded =~ /^$_/ }
587 sort { length $b <=> length $a } @prefixes;
588 },
589 '~' => $prefixes[0],
590 '+' => '' },
591 @shortnames,
592 );
593}
594
ae29b412 595__PACKAGE__->meta->make_immutable;
596
234763d4 5971;
598
599__END__
600
601=head1 CONFIGURATION
602
a269e0c2 603Like any other L<Catalyst::Component>, controllers have a config hash,
604accessible through $self->config from the controller actions. Some
605settings are in use by the Catalyst framework:
234763d4 606
607=head2 namespace
608
a269e0c2 609This specifies the internal namespace the controller should be bound
610to. By default the controller is bound to the URI version of the
611controller name. For instance controller 'MyApp::Controller::Foo::Bar'
612will be bound to 'foo/bar'. The default Root controller is an example
613of setting namespace to '' (the null string).
234763d4 614
27ae4114 615=head2 path
234763d4 616
617Sets 'path_prefix', as described below.
618
0a2577a8 619=head2 action
620
621Allows you to set the attributes that the dispatcher creates actions out of.
622This allows you to do 'rails style routes', or override some of the
f4dda4a8 623attribute definitions of actions composed from Roles.
0a2577a8 624You can set arguments globally (for all actions of the controller) and
625specifically (for a single action).
626
627 __PACKAGE__->config(
628 action => {
629 '*' => { Chained => 'base', Args => 0 },
630 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
631 },
632 );
633
634In the case above every sub in the package would be made into a Chain
635endpoint with a URI the same as the sub name for each sub, chained
636to the sub named C<base>. Ergo dispatch to C</example> would call the
637C<base> method, then the C<example> method.
638
c8136648 639=head2 action_args
640
4d4e5de8 641Allows you to set constructor arguments on your actions. You can set arguments
0a2577a8 642globally and specifically (as above).
643This is particularly useful when using C<ActionRole>s
b939ae6b 644(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
c8136648 645
b939ae6b 646 __PACKAGE__->config(
c8136648 647 action_args => {
b939ae6b 648 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
649 'specific_action' => { customarg => 'arg1' },
cea3f28a 650 },
b939ae6b 651 );
cea3f28a 652
b939ae6b 653In the case above the action class associated with C<specific_action> would get
654passed the following arguments, in addition to the normal action constructor
655arguments, when it is instantiated:
656
657 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
c8136648 658
234763d4 659=head1 METHODS
660
c4d02967 661=head2 BUILDARGS ($app, @args)
234763d4 662
c4d02967 663From L<Catalyst::Component::ApplicationAttribute>, stashes the application
664instance as $self->_application.
234763d4 665
6e3dd95f 666=head2 $self->action_for($action_name)
234763d4 667
6e3dd95f 668Returns the Catalyst::Action object (if any) for a given action in this
669controller or relative to it. You may refer to actions in controllers
670nested under the current controllers namespace, or in controllers 'up'
671from the current controller namespace. For example:
672
673 package MyApp::Controller::One::Two;
674 use base 'Catalyst::Controller';
675
676 sub foo :Local {
677 my ($self, $c) = @_;
678 $self->action_for('foo'); # action 'foo' in Controller 'One::Two'
679 $self->action_for('three/bar'); # action 'bar' in Controller 'One::Two::Three'
680 $self->action_for('../boo'); # action 'boo' in Controller 'One'
681 }
682
683This returns 'undef' if there is no action matching the requested action
684name (after any path normalization) so you should check for this as needed.
234763d4 685
234763d4 686=head2 $self->action_namespace($c)
687
a269e0c2 688Returns the private namespace for actions in this component. Defaults
689to a value from the controller name (for
690e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
691overridden from the "namespace" config key.
234763d4 692
693
694=head2 $self->path_prefix($c)
695
4ba7161b 696Returns the default path prefix for :PathPrefix, :Local and
e5d2cfdb 697relative :Path actions in this component. Defaults to the action_namespace or
a269e0c2 698can be overridden from the "path" config key.
234763d4 699
c4d02967 700=head2 $self->register_actions($c)
701
702Finds all applicable actions for this component, creates
703Catalyst::Action objects (using $self->create_action) for them and
704registers them with $c->dispatcher.
705
706=head2 $self->get_action_methods()
707
708Returns a list of L<Moose::Meta::Method> objects, doing the
709L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
710action methods for this package.
711
712=head2 $self->register_action_methods($c, @methods)
713
714Creates action objects for a set of action methods using C< create_action >,
715and registers them with the dispatcher.
716
f0a9b791 717=head2 $self->action_class(%args)
718
719Used when a controller is creating an action to determine the correct base
24d2dfaf 720action class to use.
f0a9b791 721
234763d4 722=head2 $self->create_action(%args)
723
a269e0c2 724Called with a hash of data to be use for construction of a new
725Catalyst::Action (or appropriate sub/alternative class) object.
234763d4 726
eff60019 727=head2 $self->gather_action_roles(\%action_args)
728
729Gathers the list of roles to apply to an action with the given %action_args.
730
60034b8c 731=head2 $self->gather_default_action_roles(\%action_args)
732
733returns a list of action roles to be applied based on core, builtin rules.
734Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
735this way.
736
a269e0c2 737=head2 $self->_application
234763d4 738
739=head2 $self->_app
740
741Returns the application instance stored by C<new()>
5ee249f2 742
5b41c28c 743=head1 ACTION SUBROUTINE ATTRIBUTES
744
745Please see L<Catalyst::Manual::Intro> for more details
746
747Think of action attributes as a sort of way to record metadata about an action,
748similar to how annotations work in other languages you might have heard of.
749Generally L<Catalyst> uses these to influence how the dispatcher sees your
750action and when it will run it in response to an incoming request. They can
751also be used for other things. Here's a summary, but you should refer to the
aaa85094 752linked manual page for additional help.
5b41c28c 753
754=head2 Global
755
756 sub homepage :Global { ... }
757
758A global action defined in any controller always runs relative to your root.
759So the above is the same as:
760
761 sub myaction :Path("/homepage") { ... }
762
763=head2 Absolute
764
765Status: Deprecated alias to L</Global>.
766
767=head2 Local
768
769Alias to "Path("$action_name"). The following two actions are the same:
770
771 sub myaction :Local { ... }
772 sub myaction :Path('myaction') { ... }
773
774=head2 Relative
775
776Status: Deprecated alias to L</Local>
777
778=head2 Path
779
780Handle various types of paths:
781
782 package MyApp::Controller::Baz {
783
784 ...
785
786 sub myaction1 :Path { ... } # -> /baz
c59b922b 787 sub myaction2 :Path('foo') { ... } # -> /baz/foo
5b41c28c 788 sub myaction2 :Path('/bar') { ... } # -> /bar
789 }
790
97b0e7a0 791This is a general toolbox for attaching your action to a given path.
5b41c28c 792
793
794=head2 Regex
795
796=head2 Regexp
797
5070f111 798B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 799If you really depend on this, install the standalone
800L<Catalyst::DispatchType::Regex> distribution.
5b41c28c 801
802A global way to match a give regular expression in the incoming request path.
803
804=head2 LocalRegex
805
806=head2 LocalRegexp
807
5070f111 808B<Status: Deprecated.> Use Chained methods or other techniques.
4ba7161b 809If you really depend on this, install the standalone
810L<Catalyst::DispatchType::Regex> distribution.
811
5b41c28c 812Like L</Regex> but scoped under the namespace of the containing controller
813
814=head2 Chained
815
816=head2 ChainedParent
817
818=head2 PathPrefix
819
820=head2 PathPart
821
822=head2 CaptureArgs
823
480d94b5 824Allowed values for CaptureArgs is a single integer (CaptureArgs(2), meaning two
825allowed) or you can declare a L<Moose>, L<MooseX::Types> or L<Type::Tiny>
826named constraint such as CaptureArgs(Int,Str) would require two args with
827the first being a Integer and the second a string. You may declare your own
828custom type constraints and import them into the controller namespace:
829
830 package MyApp::Controller::Root;
831
832 use Moose;
833 use MooseX::MethodAttributes;
834 use MyApp::Types qw/Int/;
835
836 extends 'Catalyst::Controller';
837
838 sub chain_base :Chained(/) CaptureArgs(1) { }
839
840 sub any_priority_chain :Chained(chain_base) PathPart('') Args(1) { }
841
842 sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { }
843
844See L<Catalyst::RouteMatching> for more.
845
846Please see L<Catalyst::DispatchType::Chained> for more.
5b41c28c 847
848=head2 ActionClass
849
850Set the base class for the action, defaults to L</Catalyst::Action>. It is now
851preferred to use L</Does>.
852
853=head2 MyAction
854
051a69b9 855Set the ActionClass using a custom Action in your project namespace.
856
857The following is exactly the same:
858
859 sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
860 sub foo_action2 : Local MyAction('Bar') { ... }
5b41c28c 861
862=head2 Does
863
864 package MyApp::Controller::Zoo;
865
866 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
867 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
868 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
869
870=head2 GET
871
872=head2 POST
873
874=head2 PUT
875
876=head2 DELETE
877
878=head2 OPTION
879
880=head2 HEAD
881
60034b8c 882=head2 PATCH
883
884=head2 Method('...')
885
886Sets the give action path to match the specified HTTP method, or via one of the
887broadly accepted methods of overriding the 'true' method (see
888L<Catalyst::ActionRole::HTTPMethods>).
5b41c28c 889
890=head2 Args
891
892When used with L</Path> indicates the number of arguments expected in
893the path. However if no Args value is set, assumed to 'slurp' all
894remaining path pars under this namespace.
895
480d94b5 896Allowed values for Args is a single integer (Args(2), meaning two allowed) or you
897can declare a L<Moose>, L<MooseX::Types> or L<Type::Tiny> named constraint such
898as Args(Int,Str) would require two args with the first being a Integer and the
899second a string. You may declare your own custom type constraints and import
900them into the controller namespace:
901
902 package MyApp::Controller::Root;
903
904 use Moose;
905 use MooseX::MethodAttributes;
906 use MyApp::Types qw/Tuple Int Str StrMatch UserId/;
907
908 extends 'Catalyst::Controller';
909
910 sub user :Local Args(UserId) {
911 my ($self, $c, $int) = @_;
912 }
913
914 sub an_int :Local Args(Int) {
915 my ($self, $c, $int) = @_;
916 }
917
918 sub many_ints :Local Args(ArrayRef[Int]) {
919 my ($self, $c, @ints) = @_;
920 }
921
922 sub match :Local Args(StrMatch[qr{\d\d-\d\d-\d\d}]) {
923 my ($self, $c, $int) = @_;
924 }
925
75ce30d0 926If you choose not to use imported type constraints (like L<Type::Tiny>, or <MooseX::Types>
927you may use L<Moose> 'stringy' types however just like when you use these types in your
928declared attributes you must quote them:
929
930 sub my_moose_type :Local Args('Int') { ... }
931
d9f0a350 932If you use 'reference' type constraints (such as ArrayRef[Int]) that have an unknown
933number of allowed matches, we set this the same way "Args" is. Please keep in mind
79fb8f95 934that actions with an undetermined number of args match at lower precedence than those
d9f0a350 935with a fixed number. You may use reference types such as Tuple from L<Types::Standard>
936that allows you to fix the number of allowed args. For example Args(Tuple[Int,Int])
937would be determined to be two args (or really the same as Args(Int,Int).) You may
938find this useful for creating custom subtypes with complex matching rules that you
939wish to reuse over many actions.
940
480d94b5 941See L<Catalyst::RouteMatching> for more.
942
5dd46e24 943B<Note>: It is highly recommended to use L<Type::Tiny> for your type constraints over
944other options. L<Type::Tiny> exposed a better meta data interface which allows us to
945do more and better types of introspection driving tests and debugging.
946
68c372d1 947=head2 Consumes('...')
948
949Matches the current action against the content-type of the request. Typically
950this is used when the request is a POST or PUT and you want to restrict the
951submitted content type. For example, you might have an HTML for that either
952returns classic url encoded form data, or JSON when Javascript is enabled. In
953this case you may wish to match either incoming type to one of two different
954actions, for properly processing.
955
956Examples:
957
958 sub is_json : Chained('start') Consumes('application/json') { ... }
959 sub is_urlencoded : Chained('start') Consumes('application/x-www-form-urlencoded') { ... }
960 sub is_multipart : Chained('start') Consumes('multipart/form-data') { ... }
961
962To reduce boilerplate, we include the following content type shortcuts:
963
964Examples
965
966 sub is_json : Chained('start') Consume(JSON) { ... }
967 sub is_urlencoded : Chained('start') Consumes(UrlEncoded) { ... }
968 sub is_multipart : Chained('start') Consumes(Multipart) { ... }
969
970You may specify more than one match:
971
972 sub is_more_than_one
973 : Chained('start')
974 : Consumes('application/x-www-form-urlencoded')
975 : Consumes('multipart/form-data')
976
977 sub is_more_than_one
978 : Chained('start')
979 : Consumes(UrlEncoded)
980 : Consumes(Multipart)
981
982Since it is a common case the shortcut C<HTMLForm> matches both
983'application/x-www-form-urlencoded' and 'multipart/form-data'. Here's the full
984list of available shortcuts:
985
986 JSON => 'application/json',
987 JS => 'application/javascript',
988 PERL => 'application/perl',
989 HTML => 'text/html',
990 XML => 'text/XML',
991 Plain => 'text/plain',
992 UrlEncoded => 'application/x-www-form-urlencoded',
993 Multipart => 'multipart/form-data',
994 HTMLForm => ['application/x-www-form-urlencoded','multipart/form-data'],
995
996Please keep in mind that when dispatching, L<Catalyst> will match the first most
efba3342 997relevant case, so if you use the C<Consumes> attribute, you should place your
68c372d1 998most accurate matches early in the Chain, and your 'catchall' actions last.
999
1000See L<Catalyst::ActionRole::ConsumesContent> for more.
1001
342d2169 1002=head2 Scheme(...)
1003
1004Allows you to specify a URI scheme for the action or action chain. For example
1005you can required that a given path be C<https> or that it is a websocket endpoint
1006C<ws> or C<wss>. For an action chain you may currently only have one defined
1007Scheme.
1008
1009 package MyApp::Controller::Root;
1010
1011 use base 'Catalyst::Controller';
1012
1013 sub is_http :Path(scheme) Scheme(http) Args(0) {
1014 my ($self, $c) = @_;
1015 $c->response->body("is_http");
1016 }
1017
1018 sub is_https :Path(scheme) Scheme(https) Args(0) {
1019 my ($self, $c) = @_;
1020 $c->response->body("is_https");
1021 }
1022
1023In the above example http://localhost/root/scheme would match the first
1024action (is_http) but https://localhost/root/scheme would match the second.
1025
1026As an added benefit, if an action or action chain defines a Scheme, when using
1027$c->uri_for the scheme of the generated URL will use what you define in the action
1028or action chain (the current behavior is to set the scheme based on the current
1029incoming request). This makes it easier to use uri_for on websites where some
1030paths are secure and others are not. You may also use this to other schemes
1031like websockets.
1032
1033See L<Catalyst::ActionRole::Scheme> for more.
1034
5b41c28c 1035=head1 OPTIONAL METHODS
1036
1037=head2 _parse_[$name]_attr
1038
1039Allows you to customize parsing of subroutine attributes.
1040
1041 sub myaction1 :Path TwoArgs { ... }
1042
1043 sub _parse_TwoArgs_attr {
1044 my ( $self, $c, $name, $value ) = @_;
1045 # $self -> controller instance
1046 #
1047 return(Args => 2);
1048 }
1049
1050Please note that this feature does not let you actually assign new functions
1051to actions via subroutine attributes, but is really more for creating useful
1052aliases to existing core and extended attributes, and transforms based on
1053existing information (like from configuration). Code for actually doing
1054something meaningful with the subroutine attributes will be located in the
1055L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
1056in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
1057called basically once when the application is starting, not per request!
1058
0bf7ab71 1059=head1 AUTHORS
5ee249f2 1060
0bf7ab71 1061Catalyst Contributors, see Catalyst.pm
5ee249f2 1062
1063=head1 COPYRIGHT
1064
536bee89 1065This library is free software. You can redistribute it and/or modify
a269e0c2 1066it under the same terms as Perl itself.
5ee249f2 1067
1068=cut