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';
12 BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
14 use MooseX::MethodAttributes;
15 use Catalyst::Exception;
18 with 'Catalyst::Component::ApplicationAttribute';
24 predicate => 'has_path_prefix',
27 has action_namespace => (
30 init_arg => 'namespace',
31 predicate => 'has_action_namespace',
35 accessor => '_controller_actions',
40 has _action_role_args => (
41 traits => [qw(Array)],
42 isa => 'ArrayRef[Str]',
43 init_arg => 'action_roles',
44 default => sub { [] },
46 _action_role_args => 'elements',
50 has _action_roles => (
51 traits => [qw(Array)],
52 isa => 'ArrayRef[RoleName]',
55 builder => '_build__action_roles',
57 _action_roles => 'elements',
61 has action_args => (is => 'ro');
63 # ->config(actions => { '*' => ...
64 has _all_actions_attributes => (
69 builder => '_build__all_actions_attributes',
73 my ($self, $args) = @_;
74 my $action = delete $args->{action} || {};
75 my $actions = delete $args->{actions} || {};
76 my $attr_value = $self->merge_config_hashes($actions, $action);
77 $self->_controller_actions($attr_value);
79 # trigger lazy builder
80 $self->_all_actions_attributes;
84 sub _build__action_roles {
86 my @roles = $self->_expand_role_shortname($self->_action_role_args);
87 load_class($_) for @roles;
91 sub _build__all_actions_attributes {
93 delete $self->_controller_actions->{'*'} || {};
98 Catalyst::Controller - Catalyst Controller base class
102 package MyApp::Controller::Search
103 use base qw/Catalyst::Controller/;
106 my ($self,$c,@args) = @_;
108 } # Dispatches to /search/foo
112 Controllers are where the actions in the Catalyst framework
113 reside. Each action is represented by a function with an attribute to
114 identify what kind of action it is. See the L<Catalyst::Dispatcher>
115 for more info about how Catalyst dispatches to actions.
119 #I think both of these could be attributes. doesn't really seem like they need
120 #to ble class data. i think that attributes +default would work just fine
121 __PACKAGE__->mk_classdata($_) for qw/_dispatch_steps _action_class _action_role_prefix/;
123 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
124 __PACKAGE__->_action_class('Catalyst::Action');
125 __PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
128 sub _DISPATCH : Private {
129 my ( $self, $c ) = @_;
131 foreach my $disp ( @{ $self->_dispatch_steps } ) {
132 last unless $c->forward($disp);
138 sub _BEGIN : Private {
139 my ( $self, $c ) = @_;
140 my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
141 return 1 unless $begin;
142 $begin->dispatch( $c );
143 return !@{ $c->error };
146 sub _AUTO : Private {
147 my ( $self, $c ) = @_;
148 my @auto = $c->get_actions( 'auto', $c->namespace );
149 foreach my $auto (@auto) {
150 $auto->dispatch( $c );
151 return 0 unless $c->state;
156 sub _ACTION : Private {
157 my ( $self, $c ) = @_;
159 && $c->action->can('execute')
160 && defined $c->req->action )
162 $c->action->dispatch( $c );
164 return !@{ $c->error };
168 my ( $self, $c ) = @_;
169 my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
170 return 1 unless $end;
171 $end->dispatch( $c );
172 return !@{ $c->error };
176 my ( $self, $name ) = @_;
177 my $app = ($self->isa('Catalyst') ? $self : $self->_application);
178 return $app->dispatcher->get_action($name, $self->action_namespace);
181 #my opinion is that this whole sub really should be a builder method, not
182 #something that happens on every call. Anyone else disagree?? -- groditi
183 ## -- apparently this is all just waiting for app/ctx split
184 around action_namespace => sub {
186 my ( $self, $c ) = @_;
188 my $class = ref($self) || $self;
189 my $appclass = ref($c) || $c;
191 return $self->$orig if $self->has_action_namespace;
193 return $class->config->{namespace} if exists $class->config->{namespace};
198 $case_s = $appclass->config->{case_sensitive};
200 if ($self->isa('Catalyst')) {
201 $case_s = $class->config->{case_sensitive};
204 $case_s = ref($self->_application)->config->{case_sensitive};
206 confess("Can't figure out case_sensitive setting");
211 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
212 $self->$orig($namespace) if ref($self);
216 #Once again, this is probably better written as a builder method
217 around path_prefix => sub {
221 return $self->$orig if $self->has_path_prefix;
223 return $self->config->{path} if exists $self->config->{path};
225 my $namespace = $self->action_namespace(@_);
226 $self->$orig($namespace) if ref($self);
230 sub get_action_methods {
232 my $meta = find_meta($self) || confess("No metaclass setup for $self");
234 sprintf "Metaclass %s for %s cannot support register_actions.",
235 ref $meta, $meta->name,
236 ) unless $meta->can('get_nearest_methods_with_attributes');
237 my @methods = $meta->get_nearest_methods_with_attributes;
239 # actions specified via config are also action_methods
243 $meta->find_method_by_name($_)
244 || confess( sprintf 'Action "%s" is not available from controller %s',
246 } keys %{ $self->_controller_actions }
248 return uniq @methods;
252 sub register_actions {
253 my ( $self, $c ) = @_;
254 $self->register_action_methods( $c, $self->get_action_methods );
257 sub register_action_methods {
258 my ( $self, $c, @methods ) = @_;
259 my $class = $self->catalyst_component_name;
260 #this is still not correct for some reason.
261 my $namespace = $self->action_namespace($c);
264 if (!blessed($self) && $self eq $c && scalar(@methods)) {
265 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
266 if (scalar(@really_bad_methods)) {
267 $c->log->warn("Action methods (" . join(', ', @really_bad_methods) . ") found defined in your application class, $self. This is deprecated, please move them into a Root controller.");
271 foreach my $method (@methods) {
272 my $name = $method->name;
273 # Horrible hack! All method metaclasses should have an attributes
274 # method, core Moose bug - see r13354.
275 my $attributes = $method->can('attributes') ? $method->attributes : [];
276 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
277 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
278 $c->log->warn( 'Bad action definition "'
279 . join( ' ', @{ $attributes } )
280 . qq/" for "$class->$name"/ )
284 my $reverse = $namespace ? "${namespace}/${name}" : $name;
285 my $action = $self->create_action(
287 code => $method->body,
289 namespace => $namespace,
291 attributes => $attrs,
294 $c->dispatcher->register( $c, $action );
298 sub _apply_action_class_roles {
299 my ($self, $class, @roles) = @_;
301 load_class($_) for @roles;
302 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
303 superclasses => [$class],
307 $meta->add_method(meta => sub { $meta });
316 my $class = (exists $args{attributes}{ActionClass}
317 ? $args{attributes}{ActionClass}[0]
318 : $self->_action_class);
320 Class::MOP::load_class($class);
328 my $class = $self->action_class(%args);
331 Moose->init_meta(for_class => $class)
332 unless Class::MOP::does_metaclass_exist($class);
334 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
335 my @roles = $self->gather_action_roles(%args);
336 push @roles, $self->gather_default_action_roles(%args);
338 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
344 : $self->config->{action_args}
348 %{ $action_args->{'*'} || {} },
349 %{ $action_args->{ $args{name} } || {} },
352 return $class->new({ %extra_args, %args });
355 sub gather_action_roles {
356 my ($self, %args) = @_;
358 (blessed $self ? $self->_action_roles : ()),
359 @{ $args{attributes}->{Does} || [] },
363 sub gather_default_action_roles {
364 my ($self, %args) = @_;
366 push @roles, 'Catalyst::ActionRole::HTTPMethods'
367 if $args{attributes}->{Method};
372 my ( $self, $c, $name, @attrs ) = @_;
376 foreach my $attr (@attrs) {
378 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
380 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
383 if ( defined $value ) {
384 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
386 push( @{ $raw_attributes{$key} }, $value );
390 my ($actions_config, $all_actions_config);
392 $actions_config = $self->_controller_actions;
393 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
394 $all_actions_config = $self->_all_actions_attributes;
396 my $cfg = $self->config;
397 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
398 $all_actions_config = {};
403 # Note we deep copy array refs here to stop crapping on config
404 # when attributes are parsed. RT#65463
405 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
408 # Private actions with additional attributes will raise a warning and then
409 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
410 # which are Private, will prevent those from being registered. They should
411 # probably be turned into :Actions instead, or we might want to otherwise
412 # disambiguate between those built-in internal actions and user-level
414 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
415 unless $raw_attributes{Private};
417 my %final_attributes;
419 while (my ($key, $value) = each %raw_attributes){
420 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
421 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
424 return \%final_attributes;
428 my ($self, $c, $name, $key, $values) = @_;
430 my %final_attributes;
431 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
432 my $meth = "_parse_${key}_attr";
433 if ( my $code = $self->can($meth) ) {
434 my %new_attrs = $self->$code( $c, $name, $value );
435 while (my ($new_key, $value) = each %new_attrs){
436 my $new_attrs = $key eq $new_key ?
437 { $new_key => [$value] } :
438 $self->_parse_attr($c, $name, $new_key => $value );
439 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
443 push( @{ $final_attributes{$key} }, $value );
447 return \%final_attributes;
450 sub _parse_Global_attr {
451 my ( $self, $c, $name, $value ) = @_;
452 # _parse_attr will call _parse_Path_attr for us
453 return Path => "/$name";
456 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
458 sub _parse_Local_attr {
459 my ( $self, $c, $name, $value ) = @_;
460 # _parse_attr will call _parse_Path_attr for us
461 return Path => $name;
464 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
466 sub _parse_Path_attr {
467 my ( $self, $c, $name, $value ) = @_;
468 $value = '' if !defined $value;
469 if ( $value =~ m!^/! ) {
470 return ( 'Path', $value );
472 elsif ( length $value ) {
473 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
476 return ( 'Path', $self->path_prefix($c) );
480 sub _parse_Regex_attr {
481 my ( $self, $c, $name, $value ) = @_;
482 return ( 'Regex', $value );
485 sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
487 sub _parse_LocalRegex_attr {
488 my ( $self, $c, $name, $value ) = @_;
489 unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
491 my $prefix = $self->path_prefix( $c );
492 $prefix .= '/' if length( $prefix );
494 return ( 'Regex', "^${prefix}${value}" );
497 sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
499 sub _parse_Chained_attr {
500 my ($self, $c, $name, $value) = @_;
502 if (defined($value) && length($value)) {
504 $value = '/'.$self->action_namespace($c);
505 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
506 my @parts = split '/', $self->action_namespace($c);
507 my @levels = split '/', $rel;
509 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
510 } elsif ($value !~ m/^\//) {
511 my $action_ns = $self->action_namespace($c);
514 $value = '/'.join('/', $action_ns, $value);
516 $value = '/'.$value; # special case namespace '' (root)
523 return Chained => $value;
526 sub _parse_ChainedParent_attr {
527 my ($self, $c, $name, $value) = @_;
528 return $self->_parse_Chained_attr($c, $name, '../'.$name);
531 sub _parse_PathPrefix_attr {
532 my ( $self, $c ) = @_;
533 return PathPart => $self->path_prefix($c);
536 sub _parse_ActionClass_attr {
537 my ( $self, $c, $name, $value ) = @_;
538 my $appname = $self->_application;
539 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
540 return ( 'ActionClass', $value );
543 sub _parse_MyAction_attr {
544 my ( $self, $c, $name, $value ) = @_;
546 my $appclass = Catalyst::Utils::class2appclass($self);
547 $value = "+${appclass}::Action::${value}";
549 return ( 'ActionClass', $value );
552 sub _parse_Does_attr {
553 my ($self, $app, $name, $value) = @_;
554 return Does => $self->_expand_role_shortname($value);
557 sub _parse_GET_attr { Method => 'GET' }
558 sub _parse_POST_attr { Method => 'POST' }
559 sub _parse_PUT_attr { Method => 'PUT' }
560 sub _parse_DELETE_attr { Method => 'DELETE' }
561 sub _parse_OPTION_attr { Method => 'OPTION' }
562 sub _parse_HEAD_attr { Method => 'HEAD' }
564 sub _expand_role_shortname {
565 my ($self, @shortnames) = @_;
566 my $app = $self->_application;
568 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
569 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
571 return String::RewritePrefix->rewrite(
573 my $loaded = load_first_existing_class(
574 map { "$_$_[0]" } @prefixes
576 return first { $loaded =~ /^$_/ }
577 sort { length $b <=> length $a } @prefixes;
585 __PACKAGE__->meta->make_immutable;
593 Like any other L<Catalyst::Component>, controllers have a config hash,
594 accessible through $self->config from the controller actions. Some
595 settings are in use by the Catalyst framework:
599 This specifies the internal namespace the controller should be bound
600 to. By default the controller is bound to the URI version of the
601 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
602 will be bound to 'foo/bar'. The default Root controller is an example
603 of setting namespace to '' (the null string).
607 Sets 'path_prefix', as described below.
611 Allows you to set the attributes that the dispatcher creates actions out of.
612 This allows you to do 'rails style routes', or override some of the
613 attribute definitions of actions composed from Roles.
614 You can set arguments globally (for all actions of the controller) and
615 specifically (for a single action).
619 '*' => { Chained => 'base', Args => 0 },
620 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
624 In the case above every sub in the package would be made into a Chain
625 endpoint with a URI the same as the sub name for each sub, chained
626 to the sub named C<base>. Ergo dispatch to C</example> would call the
627 C<base> method, then the C<example> method.
631 Allows you to set constructor arguments on your actions. You can set arguments
632 globally and specifically (as above).
633 This is particularly useful when using C<ActionRole>s
634 (L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
638 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
639 'specific_action' => { customarg => 'arg1' },
643 In the case above the action class associated with C<specific_action> would get
644 passed the following arguments, in addition to the normal action constructor
645 arguments, when it is instantiated:
647 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
651 =head2 BUILDARGS ($app, @args)
653 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
654 instance as $self->_application.
656 =head2 $self->action_for('name')
658 Returns the Catalyst::Action object (if any) for a given method name
661 =head2 $self->action_namespace($c)
663 Returns the private namespace for actions in this component. Defaults
664 to a value from the controller name (for
665 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
666 overridden from the "namespace" config key.
669 =head2 $self->path_prefix($c)
671 Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
672 relative :Path actions in this component. Defaults to the action_namespace or
673 can be overridden from the "path" config key.
675 =head2 $self->register_actions($c)
677 Finds all applicable actions for this component, creates
678 Catalyst::Action objects (using $self->create_action) for them and
679 registers them with $c->dispatcher.
681 =head2 $self->get_action_methods()
683 Returns a list of L<Moose::Meta::Method> objects, doing the
684 L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
685 action methods for this package.
687 =head2 $self->register_action_methods($c, @methods)
689 Creates action objects for a set of action methods using C< create_action >,
690 and registers them with the dispatcher.
692 =head2 $self->action_class(%args)
694 Used when a controller is creating an action to determine the correct base
697 =head2 $self->create_action(%args)
699 Called with a hash of data to be use for construction of a new
700 Catalyst::Action (or appropriate sub/alternative class) object.
702 =head2 $self->gather_action_roles(\%action_args)
704 Gathers the list of roles to apply to an action with the given %action_args.
706 =head2 $self->gather_default_action_roles(\%action_args)
708 returns a list of action roles to be applied based on core, builtin rules.
709 Currently only the L<Catalyst::ActionRole::HTTPMethods> role is applied
712 =head2 $self->_application
716 Returns the application instance stored by C<new()>
718 =head1 ACTION SUBROUTINE ATTRIBUTES
720 Please see L<Catalyst::Manual::Intro> for more details
722 Think of action attributes as a sort of way to record metadata about an action,
723 similar to how annotations work in other languages you might have heard of.
724 Generally L<Catalyst> uses these to influence how the dispatcher sees your
725 action and when it will run it in response to an incoming request. They can
726 also be used for other things. Here's a summary, but you should refer to the
727 liked manual page for additional help.
731 sub homepage :Global { ... }
733 A global action defined in any controller always runs relative to your root.
734 So the above is the same as:
736 sub myaction :Path("/homepage") { ... }
740 Status: Deprecated alias to L</Global>.
744 Alias to "Path("$action_name"). The following two actions are the same:
746 sub myaction :Local { ... }
747 sub myaction :Path('myaction') { ... }
751 Status: Deprecated alias to L</Local>
755 Handle various types of paths:
757 package MyApp::Controller::Baz {
761 sub myaction1 :Path { ... } # -> /baz
762 sub myaction2 :Path('foo') { ... } # -> /baz/bar
763 sub myaction2 :Path('/bar') { ... } # -> /bar
766 This is a general toolbox for attaching your action to a give path.
773 Status: Deprecated. Use Chained methods or other techniques
775 A global way to match a give regular expression in the incoming request path.
781 Like L</Regex> but scoped under the namespace of the containing controller
793 Please see L<Catalyst::DispatchType::Chained>
797 Set the base class for the action, defaults to L</Catalyst::Action>. It is now
798 preferred to use L</Does>.
802 Set the ActionClass using a custom Action in your project namespace.
804 The following is exactly the same:
806 sub foo_action1 : Local ActionClass('+MyApp::Action::Bar') { ... }
807 sub foo_action2 : Local MyAction('Bar') { ... }
811 package MyApp::Controller::Zoo;
813 sub foo : Local Does('Moo') { ... } # Catalyst::ActionRole::
814 sub bar : Local Does('~Moo') { ... } # MyApp::ActionRole::Moo
815 sub baz : Local Does('+MyApp::ActionRole::Moo') { ... }
833 Sets the give action path to match the specified HTTP method, or via one of the
834 broadly accepted methods of overriding the 'true' method (see
835 L<Catalyst::ActionRole::HTTPMethods>).
839 When used with L</Path> indicates the number of arguments expected in
840 the path. However if no Args value is set, assumed to 'slurp' all
841 remaining path pars under this namespace.
843 =head1 OPTIONAL METHODS
845 =head2 _parse_[$name]_attr
847 Allows you to customize parsing of subroutine attributes.
849 sub myaction1 :Path TwoArgs { ... }
851 sub _parse_TwoArgs_attr {
852 my ( $self, $c, $name, $value ) = @_;
853 # $self -> controller instance
858 Please note that this feature does not let you actually assign new functions
859 to actions via subroutine attributes, but is really more for creating useful
860 aliases to existing core and extended attributes, and transforms based on
861 existing information (like from configuration). Code for actually doing
862 something meaningful with the subroutine attributes will be located in the
863 L<Catalyst::Action> classes (or your subclasses), L<Catalyst::Dispatcher> and
864 in subclasses of L<Catalyst::DispatchType>. Remember these methods only get
865 called basically once when the application is starting, not per request!
869 Catalyst Contributors, see Catalyst.pm
873 This library is free software. You can redistribute it and/or modify
874 it under the same terms as Perl itself.