1 package Catalyst::Controller;
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';
13 extends qw/Catalyst::Component/;
14 with qw/MooseX::MethodAttributes::Role::AttrContainer::Inheritable/;
17 use MooseX::MethodAttributes;
18 use Catalyst::Exception;
21 with 'Catalyst::Component::ApplicationAttribute';
27 predicate => 'has_path_prefix',
30 has action_namespace => (
33 init_arg => 'namespace',
34 predicate => 'has_action_namespace',
38 accessor => '_controller_actions',
43 has _action_role_args => (
44 traits => [qw(Array)],
45 isa => 'ArrayRef[Str]',
46 init_arg => 'action_roles',
47 default => sub { [] },
49 _action_role_args => 'elements',
53 has _action_roles => (
54 traits => [qw(Array)],
55 isa => 'ArrayRef[RoleName]',
58 builder => '_build__action_roles',
60 _action_roles => 'elements',
64 has action_args => (is => 'ro');
66 # ->config(actions => { '*' => ...
67 has _all_actions_attributes => (
72 builder => '_build__all_actions_attributes',
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);
82 # trigger lazy builder
83 $self->_all_actions_attributes;
87 sub _build__action_roles {
89 my @roles = $self->_expand_role_shortname($self->_action_role_args);
90 load_class($_) for @roles;
94 sub _build__all_actions_attributes {
96 delete $self->_controller_actions->{'*'} || {};
101 Catalyst::Controller - Catalyst Controller base class
105 package MyApp::Controller::Search
106 use base qw/Catalyst::Controller/;
109 my ($self,$c,@args) = @_;
111 } # Dispatches to /search/foo
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.
122 #I think both of these could be attributes. doesn't really seem like they need
123 #to ble class data. i think that attributes +default would work just fine
124 __PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
126 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
127 __PACKAGE__->_action_class('Catalyst::Action');
128 __PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
131 sub _DISPATCH : Private {
132 my ( $self, $c ) = @_;
134 foreach my $disp ( @{ $self->_dispatch_steps } ) {
135 last unless $c->forward($disp);
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 };
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;
159 sub _ACTION : Private {
160 my ( $self, $c ) = @_;
162 && $c->action->can('execute')
163 && defined $c->req->action )
165 $c->action->dispatch( $c );
167 return !@{ $c->error };
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 };
179 my ( $self, $name ) = @_;
180 my $app = ($self->isa('Catalyst') ? $self : $self->_application);
181 return $app->dispatcher->get_action($name, $self->action_namespace);
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 {
189 my ( $self, $c ) = @_;
191 my $class = ref($self) || $self;
192 my $appclass = ref($c) || $c;
194 return $self->$orig if $self->has_action_namespace;
196 return $class->config->{namespace} if exists $class->config->{namespace};
201 $case_s = $appclass->config->{case_sensitive};
203 if ($self->isa('Catalyst')) {
204 $case_s = $class->config->{case_sensitive};
207 $case_s = ref($self->_application)->config->{case_sensitive};
209 confess("Can't figure out case_sensitive setting");
214 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
215 $self->$orig($namespace) if ref($self);
219 #Once again, this is probably better written as a builder method
220 around path_prefix => sub {
224 return $self->$orig if $self->has_path_prefix;
226 return $self->config->{path} if exists $self->config->{path};
228 my $namespace = $self->action_namespace(@_);
229 $self->$orig($namespace) if ref($self);
233 sub get_action_methods {
235 my $meta = find_meta($self) || confess("No metaclass setup for $self");
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;
242 # actions specified via config are also action_methods
246 $meta->find_method_by_name($_)
247 || confess( sprintf 'Action "%s" is not available from controller %s',
249 } keys %{ $self->_controller_actions }
251 return uniq @methods;
255 sub register_actions {
256 my ( $self, $c ) = @_;
257 $self->register_action_methods( $c, $self->get_action_methods );
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);
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.");
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"/ )
287 my $reverse = $namespace ? "${namespace}/${name}" : $name;
288 my $action = $self->create_action(
290 code => $method->body,
292 namespace => $namespace,
294 attributes => $attrs,
297 $c->dispatcher->register( $c, $action );
301 sub _apply_action_class_roles {
302 my ($self, $class, @roles) = @_;
304 load_class($_) for @roles;
305 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
306 superclasses => [$class],
310 $meta->add_method(meta => sub { $meta });
319 my $class = (exists $args{attributes}{ActionClass}
320 ? $args{attributes}{ActionClass}[0]
321 : $self->_action_class);
331 my $class = $self->action_class(%args);
334 Moose->init_meta(for_class => $class)
335 unless Class::MOP::does_metaclass_exist($class);
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);
341 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
347 : $self->config->{action_args}
351 %{ $action_args->{'*'} || {} },
352 %{ $action_args->{ $args{name} } || {} },
355 return $class->new({ %extra_args, %args });
358 sub gather_action_roles {
359 my ($self, %args) = @_;
361 (blessed $self ? $self->_action_roles : ()),
362 @{ $args{attributes}->{Does} || [] },
366 sub gather_default_action_roles {
367 my ($self, %args) = @_;
369 push @roles, 'Catalyst::ActionRole::HTTPMethods'
370 if $args{attributes}->{Method};
375 my ( $self, $c, $name, @attrs ) = @_;
379 foreach my $attr (@attrs) {
381 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
383 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
386 if ( defined $value ) {
387 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
389 push( @{ $raw_attributes{$key} }, $value );
393 my ($actions_config, $all_actions_config);
395 $actions_config = $self->_controller_actions;
396 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
397 $all_actions_config = $self->_all_actions_attributes;
399 my $cfg = $self->config;
400 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
401 $all_actions_config = {};
406 # Note we deep copy array refs here to stop crapping on config
407 # when attributes are parsed. RT#65463
408 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
411 # Private actions with additional attributes will raise a warning and then
412 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
413 # which are Private, will prevent those from being registered. They should
414 # probably be turned into :Actions instead, or we might want to otherwise
415 # disambiguate between those built-in internal actions and user-level
417 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
418 unless $raw_attributes{Private};
420 my %final_attributes;
422 while (my ($key, $value) = each %raw_attributes){
423 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
424 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
427 return \%final_attributes;
431 my ($self, $c, $name, $key, $values) = @_;
433 my %final_attributes;
434 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
435 my $meth = "_parse_${key}_attr";
436 if ( my $code = $self->can($meth) ) {
437 my %new_attrs = $self->$code( $c, $name, $value );
438 while (my ($new_key, $value) = each %new_attrs){
439 my $new_attrs = $key eq $new_key ?
440 { $new_key => [$value] } :
441 $self->_parse_attr($c, $name, $new_key => $value );
442 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
446 push( @{ $final_attributes{$key} }, $value );
450 return \%final_attributes;
453 sub _parse_Global_attr {
454 my ( $self, $c, $name, $value ) = @_;
455 # _parse_attr will call _parse_Path_attr for us
456 return Path => "/$name";
459 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
461 sub _parse_Local_attr {
462 my ( $self, $c, $name, $value ) = @_;
463 # _parse_attr will call _parse_Path_attr for us
464 return Path => $name;
467 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
469 sub _parse_Path_attr {
470 my ( $self, $c, $name, $value ) = @_;
471 $value = '' if !defined $value;
472 if ( $value =~ m!^/! ) {
473 return ( 'Path', $value );
475 elsif ( length $value ) {
476 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
479 return ( 'Path', $self->path_prefix($c) );
483 sub _parse_Chained_attr {
484 my ($self, $c, $name, $value) = @_;
486 if (defined($value) && length($value)) {
488 $value = '/'.$self->action_namespace($c);
489 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
490 my @parts = split '/', $self->action_namespace($c);
491 my @levels = split '/', $rel;
493 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
494 } elsif ($value !~ m/^\//) {
495 my $action_ns = $self->action_namespace($c);
498 $value = '/'.join('/', $action_ns, $value);
500 $value = '/'.$value; # special case namespace '' (root)
507 return Chained => $value;
510 sub _parse_ChainedParent_attr {
511 my ($self, $c, $name, $value) = @_;
512 return $self->_parse_Chained_attr($c, $name, '../'.$name);
515 sub _parse_PathPrefix_attr {
516 my ( $self, $c ) = @_;
517 return PathPart => $self->path_prefix($c);
520 sub _parse_ActionClass_attr {
521 my ( $self, $c, $name, $value ) = @_;
522 my $appname = $self->_application;
523 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
524 return ( 'ActionClass', $value );
527 sub _parse_MyAction_attr {
528 my ( $self, $c, $name, $value ) = @_;
530 my $appclass = Catalyst::Utils::class2appclass($self);
531 $value = "+${appclass}::Action::${value}";
533 return ( 'ActionClass', $value );
536 sub _parse_Does_attr {
537 my ($self, $app, $name, $value) = @_;
538 return Does => $self->_expand_role_shortname($value);
541 sub _parse_GET_attr { Method => 'GET' }
542 sub _parse_POST_attr { Method => 'POST' }
543 sub _parse_PUT_attr { Method => 'PUT' }
544 sub _parse_DELETE_attr { Method => 'DELETE' }
545 sub _parse_OPTION_attr { Method => 'OPTION' }
546 sub _parse_HEAD_attr { Method => 'HEAD' }
548 sub _expand_role_shortname {
549 my ($self, @shortnames) = @_;
550 my $app = $self->_application;
552 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
553 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
555 return String::RewritePrefix->rewrite(
557 my $loaded = load_first_existing_class(
558 map { "$_$_[0]" } @prefixes
560 return first { $loaded =~ /^$_/ }
561 sort { length $b <=> length $a } @prefixes;
569 __PACKAGE__->meta->make_immutable;
577 Like any other L<Catalyst::Component>, controllers have a config hash,
578 accessible through $self->config from the controller actions. Some
579 settings are in use by the Catalyst framework:
583 This specifies the internal namespace the controller should be bound
584 to. By default the controller is bound to the URI version of the
585 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
586 will be bound to 'foo/bar'. The default Root controller is an example
587 of setting namespace to '' (the null string).
591 Sets 'path_prefix', as described below.
595 Allows you to set the attributes that the dispatcher creates actions out of.
596 This allows you to do 'rails style routes', or override some of the
597 attribute definitions of actions composed from Roles.
598 You can set arguments globally (for all actions of the controller) and
599 specifically (for a single action).
603 '*' => { Chained => 'base', Args => 0 },
604 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
608 In the case above every sub in the package would be made into a Chain
609 endpoint with a URI the same as the sub name for each sub, chained
610 to the sub named C<base>. Ergo dispatch to C</example> would call the
611 C<base> method, then the C<example> method.
615 Allows you to set constructor arguments on your actions. You can set arguments
616 globally and specifically (as above).
617 This is particularly useful when using C<ActionRole>s
618 (L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
622 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
623 'specific_action' => { customarg => 'arg1' },
627 In the case above the action class associated with C<specific_action> would get
628 passed the following arguments, in addition to the normal action constructor
629 arguments, when it is instantiated:
631 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
635 =head2 BUILDARGS ($app, @args)
637 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
638 instance as $self->_application.
640 =head2 $self->action_for('name')
642 Returns the Catalyst::Action object (if any) for a given method name
645 =head2 $self->action_namespace($c)
647 Returns the private namespace for actions in this component. Defaults
648 to a value from the controller name (for
649 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
650 overridden from the "namespace" config key.
653 =head2 $self->path_prefix($c)
655 Returns the default path prefix for :PathPrefix, :Local and
656 relative :Path actions in this component. Defaults to the action_namespace or
657 can be overridden from the "path" config key.
659 =head2 $self->register_actions($c)
661 Finds all applicable actions for this component, creates
662 Catalyst::Action objects (using $self->create_action) for them and
663 registers them with $c->dispatcher.
665 =head2 $self->get_action_methods()
667 Returns a list of L<Moose::Meta::Method> objects, doing the
668 L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
669 action methods for this package.
671 =head2 $self->register_action_methods($c, @methods)
673 Creates action objects for a set of action methods using C< create_action >,
674 and registers them with the dispatcher.
676 =head2 $self->action_class(%args)
678 Used when a controller is creating an action to determine the correct base
681 =head2 $self->create_action(%args)
683 Called with a hash of data to be use for construction of a new
684 Catalyst::Action (or appropriate sub/alternative class) object.
686 =head2 $self->gather_action_roles(\%action_args)
688 Gathers the list of roles to apply to an action with the given %action_args.
690 =head2 $self->gather_default_action_roles(\%action_args)
692 returns a list of action roles to be applied based on core, builtin rules.
693 Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
696 =head2 $self->_application
700 Returns the application instance stored by C<new()>
702 =head1 ACTION SUBROUTINE ATTRIBUTES
704 Please see L<Catalyst::Manual::Intro> for more details
706 Think of action attributes as a sort of way to record metadata about an action,
707 similar to how annotations work in other languages you might have heard of.
708 Generally L<Catalyst> uses these to influence how the dispatcher sees your
709 action and when it will run it in response to an incoming request. They can
710 also be used for other things. Here's a summary, but you should refer to the
711 liked manual page for additional help.
715 sub homepage :Global { ... }
717 A global action defined in any controller always runs relative to your root.
718 So the above is the same as:
720 sub myaction :Path("/homepage") { ... }
724 Status: Deprecated alias to L</Global>.
728 Alias to "Path("$action_name"). The following two actions are the same:
730 sub myaction :Local { ... }
731 sub myaction :Path('myaction') { ... }
735 Status: Deprecated alias to L</Local>
739 Handle various types of paths:
741 package MyApp::Controller::Baz {
745 sub myaction1 :Path { ... } # -> /baz
746 sub myaction2 :Path('foo') { ... } # -> /baz/foo
747 sub myaction2 :Path('/bar') { ... } # -> /bar
750 This is a general toolbox for attaching your action to a given path.
757 B<Status: Deprecated.> Use Chained methods or other techniques.
758 If you really depend on this, install the standalone
759 L<Catalyst::DispatchType::Regex> distribution.
761 A global way to match a give regular expression in the incoming request path.
767 B<Status: Deprecated.> Use Chained methods or other techniques.
768 If you really depend on this, install the standalone
769 L<Catalyst::DispatchType::Regex> distribution.
771 Like L</Regex> but scoped under the namespace of the containing controller
783 Please see L<Catalyst::DispatchType::Chained>
787 Set the base class for the action, defaults to L</Catalyst::Action>. It is now
788 preferred to use L</Does>.
792 Set the ActionClass using a custom Action in your project namespace.
794 The following is exactly the same:
796 sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
797 sub foo_action2 : Local MyAction('Bar') { ... }
801 package MyApp::Controller::Zoo;
803 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
804 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
805 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
823 Sets the give action path to match the specified HTTP method, or via one of the
824 broadly accepted methods of overriding the 'true' method (see
825 L<Catalyst::ActionRole::HTTPMethods>).
829 When used with L</Path> indicates the number of arguments expected in
830 the path. However if no Args value is set, assumed to 'slurp' all
831 remaining path pars under this namespace.
833 =head1 OPTIONAL METHODS
835 =head2 _parse_[$name]_attr
837 Allows you to customize parsing of subroutine attributes.
839 sub myaction1 :Path TwoArgs { ... }
841 sub _parse_TwoArgs_attr {
842 my ( $self, $c, $name, $value ) = @_;
843 # $self -> controller instance
848 Please note that this feature does not let you actually assign new functions
849 to actions via subroutine attributes, but is really more for creating useful
850 aliases to existing core and extended attributes, and transforms based on
851 existing information (like from configuration). Code for actually doing
852 something meaningful with the subroutine attributes will be located in the
853 L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
854 in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
855 called basically once when the application is starting, not per request!
859 Catalyst Contributors, see Catalyst.pm
863 This library is free software. You can redistribute it and/or modify
864 it under the same terms as Perl itself.