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