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 # FIXME - catalyst_component_name is no longer a class accessor, because
192 # 'MyApp as a controller' behavior is removed. But is this call to
193 # catalyst_component_name necessary, or is it always the same as $class?
194 my $component_name = ref($self) ? $self->catalyst_component_name : $self;
197 return $self->$orig if $self->has_action_namespace;
199 return $class->config->{namespace} if exists $class->config->{namespace};
204 $case_s = $appclass->config->{case_sensitive};
206 if ($self->isa('Catalyst')) {
207 $case_s = $class->config->{case_sensitive};
210 $case_s = ref($self->_application)->config->{case_sensitive};
212 confess("Can't figure out case_sensitive setting");
217 my $namespace = Catalyst::Utils::class2prefix($component_name, $case_s) || '';
218 $self->$orig($namespace) if ref($self);
222 #Once again, this is probably better written as a builder method
223 around path_prefix => sub {
227 return $self->$orig if $self->has_path_prefix;
229 return $self->config->{path} if exists $self->config->{path};
231 my $namespace = $self->action_namespace(@_);
232 $self->$orig($namespace) if ref($self);
236 sub get_action_methods {
238 my $meta = find_meta($self) || confess("No metaclass setup for $self");
240 sprintf "Metaclass %s for %s cannot support register_actions.",
241 ref $meta, $meta->name,
242 ) unless $meta->can('get_nearest_methods_with_attributes');
243 my @methods = $meta->get_nearest_methods_with_attributes;
245 # actions specified via config are also action_methods
249 $meta->find_method_by_name($_)
250 || confess( sprintf 'Action "%s" is not available from controller %s',
252 } keys %{ $self->_controller_actions }
254 return uniq @methods;
258 sub register_actions {
259 my ( $self, $c ) = @_;
260 $self->register_action_methods( $c, $self->get_action_methods );
263 sub register_action_methods {
264 my ( $self, $c, @methods ) = @_;
265 my $class = $self->catalyst_component_name;
266 #this is still not correct for some reason.
267 my $namespace = $self->action_namespace($c);
270 if (!blessed($self) && $self eq $c && scalar(@methods)) {
271 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
272 if (scalar(@really_bad_methods)) {
273 $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.");
277 foreach my $method (@methods) {
278 my $name = $method->name;
279 # Horrible hack! All method metaclasses should have an attributes
280 # method, core Moose bug - see r13354.
281 my $attributes = $method->can('attributes') ? $method->attributes : [];
282 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
283 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
284 $c->log->warn( 'Bad action definition "'
285 . join( ' ', @{ $attributes } )
286 . qq/" for "$class->$name"/ )
290 my $reverse = $namespace ? "${namespace}/${name}" : $name;
291 my $action = $self->create_action(
293 code => $method->body,
295 namespace => $namespace,
297 attributes => $attrs,
300 $c->dispatcher->register( $c, $action );
304 sub _apply_action_class_roles {
305 my ($self, $class, @roles) = @_;
307 load_class($_) for @roles;
308 my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
309 superclasses => [$class],
313 $meta->add_method(meta => sub { $meta });
322 my $class = (exists $args{attributes}{ActionClass}
323 ? $args{attributes}{ActionClass}[0]
324 : $self->_action_class);
326 Class::MOP::load_class($class);
334 my $class = $self->action_class(%args);
337 Moose->init_meta(for_class => $class)
338 unless Class::MOP::does_metaclass_exist($class);
340 unless ($args{name} =~ /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/) {
341 my @roles = $self->gather_action_roles(%args);
342 $class = $self->_apply_action_class_roles($class, @roles) if @roles;
348 : $self->config->{action_args}
352 %{ $action_args->{'*'} || {} },
353 %{ $action_args->{ $args{name} } || {} },
356 return $class->new({ %extra_args, %args });
359 sub gather_action_roles {
360 my ($self, %args) = @_;
363 (blessed $self ? $self->_action_roles : ()),
364 @{ $args{attributes}->{Does} || [] },
369 my ( $self, $c, $name, @attrs ) = @_;
373 foreach my $attr (@attrs) {
375 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
377 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
380 if ( defined $value ) {
381 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
383 push( @{ $raw_attributes{$key} }, $value );
387 my ($actions_config, $all_actions_config);
389 $actions_config = $self->_controller_actions;
390 # No, you're not getting actions => { '*' => ... } with actions in MyApp.
391 $all_actions_config = $self->_all_actions_attributes;
393 my $cfg = $self->config;
394 $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
395 $all_actions_config = {};
400 # Note we deep copy array refs here to stop crapping on config
401 # when attributes are parsed. RT#65463
402 exists $actions_config->{$name} ? map { ref($_) eq 'ARRAY' ? [ @$_ ] : $_ } %{ $actions_config->{$name } } : (),
405 # Private actions with additional attributes will raise a warning and then
406 # be ignored. Adding '*' arguments to the default _DISPATCH / etc. methods,
407 # which are Private, will prevent those from being registered. They should
408 # probably be turned into :Actions instead, or we might want to otherwise
409 # disambiguate between those built-in internal actions and user-level
411 %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
412 unless $raw_attributes{Private};
414 my %final_attributes;
416 while (my ($key, $value) = each %raw_attributes){
417 my $new_attrs = $self->_parse_attr($c, $name, $key => $value );
418 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
421 return \%final_attributes;
425 my ($self, $c, $name, $key, $values) = @_;
427 my %final_attributes;
428 foreach my $value (ref($values) eq 'ARRAY' ? @$values : $values) {
429 my $meth = "_parse_${key}_attr";
430 if ( my $code = $self->can($meth) ) {
431 my %new_attrs = $self->$code( $c, $name, $value );
432 while (my ($new_key, $value) = each %new_attrs){
433 my $new_attrs = $key eq $new_key ?
434 { $new_key => [$value] } :
435 $self->_parse_attr($c, $name, $new_key => $value );
436 push @{ $final_attributes{$_} }, @{ $new_attrs->{$_} } for keys %$new_attrs;
440 push( @{ $final_attributes{$key} }, $value );
444 return \%final_attributes;
447 sub _parse_Global_attr {
448 my ( $self, $c, $name, $value ) = @_;
449 # _parse_attr will call _parse_Path_attr for us
450 return Path => "/$name";
453 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
455 sub _parse_Local_attr {
456 my ( $self, $c, $name, $value ) = @_;
457 # _parse_attr will call _parse_Path_attr for us
458 return Path => $name;
461 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
463 sub _parse_Path_attr {
464 my ( $self, $c, $name, $value ) = @_;
465 $value = '' if !defined $value;
466 if ( $value =~ m!^/! ) {
467 return ( 'Path', $value );
469 elsif ( length $value ) {
470 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
473 return ( 'Path', $self->path_prefix($c) );
477 sub _parse_Regex_attr {
478 my ( $self, $c, $name, $value ) = @_;
479 return ( 'Regex', $value );
482 sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
484 sub _parse_LocalRegex_attr {
485 my ( $self, $c, $name, $value ) = @_;
486 unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
488 my $prefix = $self->path_prefix( $c );
489 $prefix .= '/' if length( $prefix );
491 return ( 'Regex', "^${prefix}${value}" );
494 sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
496 sub _parse_Chained_attr {
497 my ($self, $c, $name, $value) = @_;
499 if (defined($value) && length($value)) {
501 $value = '/'.$self->action_namespace($c);
502 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
503 my @parts = split '/', $self->action_namespace($c);
504 my @levels = split '/', $rel;
506 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
507 } elsif ($value !~ m/^\//) {
508 my $action_ns = $self->action_namespace($c);
511 $value = '/'.join('/', $action_ns, $value);
513 $value = '/'.$value; # special case namespace '' (root)
520 return Chained => $value;
523 sub _parse_ChainedParent_attr {
524 my ($self, $c, $name, $value) = @_;
525 return $self->_parse_Chained_attr($c, $name, '../'.$name);
528 sub _parse_PathPrefix_attr {
529 my ( $self, $c ) = @_;
530 return PathPart => $self->path_prefix($c);
533 sub _parse_ActionClass_attr {
534 my ( $self, $c, $name, $value ) = @_;
535 my $appname = $self->_application;
536 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
537 return ( 'ActionClass', $value );
540 sub _parse_MyAction_attr {
541 my ( $self, $c, $name, $value ) = @_;
543 my $appclass = Catalyst::Utils::class2appclass($self);
544 $value = "+${appclass}::Action::${value}";
546 return ( 'ActionClass', $value );
549 sub _parse_Does_attr {
550 my ($self, $app, $name, $value) = @_;
551 return Does => $self->_expand_role_shortname($value);
554 sub _expand_role_shortname {
555 my ($self, @shortnames) = @_;
556 my $app = $self->_application;
558 my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
559 my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
561 return String::RewritePrefix->rewrite(
563 my $loaded = load_first_existing_class(
564 map { "$_$_[0]" } @prefixes
566 return first { $loaded =~ /^$_/ }
567 sort { length $b <=> length $a } @prefixes;
575 __PACKAGE__->meta->make_immutable;
583 Like any other L<Catalyst::Component>, controllers have a config hash,
584 accessible through $self->config from the controller actions. Some
585 settings are in use by the Catalyst framework:
589 This specifies the internal namespace the controller should be bound
590 to. By default the controller is bound to the URI version of the
591 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
592 will be bound to 'foo/bar'. The default Root controller is an example
593 of setting namespace to '' (the null string).
597 Sets 'path_prefix', as described below.
601 Allows you to set the attributes that the dispatcher creates actions out of.
602 This allows you to do 'rails style routes', or override some of the
603 attribute definitions of actions composed from Roles.
604 You can set arguments globally (for all actions of the controller) and
605 specifically (for a single action).
609 '*' => { Chained => 'base', Args => 0 },
610 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
614 In the case above every sub in the package would be made into a Chain
615 endpoint with a URI the same as the sub name for each sub, chained
616 to the sub named C<base>. Ergo dispatch to C</example> would call the
617 C<base> method, then the C<example> method.
621 Allows you to set constructor arguments on your actions. You can set arguments
622 globally and specifically (as above).
623 This is particularly useful when using C<ActionRole>s
624 (L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
628 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
629 'specific_action' => { customarg => 'arg1' },
633 In the case above the action class associated with C<specific_action> would get
634 passed the following arguments, in addition to the normal action constructor
635 arguments, when it is instantiated:
637 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
641 =head2 BUILDARGS ($app, @args)
643 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
644 instance as $self->_application.
646 =head2 $self->action_for('name')
648 Returns the Catalyst::Action object (if any) for a given method name
651 =head2 $self->action_namespace($c)
653 Returns the private namespace for actions in this component. Defaults
654 to a value from the controller name (for
655 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
656 overridden from the "namespace" config key.
659 =head2 $self->path_prefix($c)
661 Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
662 relative :Path actions in this component. Defaults to the action_namespace or
663 can be overridden from the "path" config key.
665 =head2 $self->register_actions($c)
667 Finds all applicable actions for this component, creates
668 Catalyst::Action objects (using $self->create_action) for them and
669 registers them with $c->dispatcher.
671 =head2 $self->get_action_methods()
673 Returns a list of L<Moose::Meta::Method> objects, doing the
674 L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
675 action methods for this package.
677 =head2 $self->register_action_methods($c, @methods)
679 Creates action objects for a set of action methods using C< create_action >,
680 and registers them with the dispatcher.
682 =head2 $self->action_class(%args)
684 Used when a controller is creating an action to determine the correct base
687 =head2 $self->create_action(%args)
689 Called with a hash of data to be use for construction of a new
690 Catalyst::Action (or appropriate sub/alternative class) object.
692 =head2 $self->gather_action_roles(\%action_args)
694 Gathers the list of roles to apply to an action with the given %action_args.
696 =head2 $self->_application
700 Returns the application instance stored by C<new()>
704 Catalyst Contributors, see Catalyst.pm
708 This library is free software. You can redistribute it and/or modify
709 it under the same terms as Perl itself.