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