1 package Catalyst::Controller;
4 use Moose::Util qw/find_meta/;
5 use List::MoreUtils qw/uniq/;
6 use namespace::clean -except => 'meta';
8 BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
10 use MooseX::MethodAttributes;
11 use Catalyst::Exception;
14 with 'Catalyst::Component::ApplicationAttribute';
21 predicate => 'has_path_prefix',
24 has action_namespace =>
28 init_arg => 'namespace',
29 predicate => 'has_action_namespace',
34 accessor => '_controller_actions',
40 my ($self, $args) = @_;
41 my $action = delete $args->{action} || {};
42 my $actions = delete $args->{actions} || {};
43 my $attr_value = $self->merge_config_hashes($actions, $action);
44 $self->_controller_actions($attr_value);
51 Catalyst::Controller - Catalyst Controller base class
55 package MyApp::Controller::Search
56 use base qw/Catalyst::Controller/;
59 my ($self,$c,@args) = @_;
61 } # Dispatches to /search/foo
65 Controllers are where the actions in the Catalyst framework
66 reside. Each action is represented by a function with an attribute to
67 identify what kind of action it is. See the L<Catalyst::Dispatcher>
68 for more info about how Catalyst dispatches to actions.
72 #I think both of these could be attributes. doesn't really seem like they need
73 #to ble class data. i think that attributes +default would work just fine
74 __PACKAGE__->mk_classdata($_) for qw/_dispatch_steps/;
76 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
78 has _action_class => (
80 default => 'Catalyst::Action',
83 sub _DISPATCH : Private {
84 my ( $self, $c ) = @_;
86 foreach my $disp ( @{ $self->_dispatch_steps } ) {
87 last unless $c->forward($disp);
93 sub _BEGIN : Private {
94 my ( $self, $c ) = @_;
95 my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
96 return 1 unless $begin;
97 $begin->dispatch( $c );
98 return !@{ $c->error };
101 sub _AUTO : Private {
102 my ( $self, $c ) = @_;
103 my @auto = $c->get_actions( 'auto', $c->namespace );
104 foreach my $auto (@auto) {
105 $auto->dispatch( $c );
106 return 0 unless $c->state;
111 sub _ACTION : Private {
112 my ( $self, $c ) = @_;
114 && $c->action->can('execute')
115 && defined $c->req->action )
117 $c->action->dispatch( $c );
119 return !@{ $c->error };
123 my ( $self, $c ) = @_;
124 my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
125 return 1 unless $end;
126 $end->dispatch( $c );
127 return !@{ $c->error };
131 my ( $self, $name ) = @_;
132 my $app = ($self->isa('Catalyst') ? $self : $self->_application);
133 return $app->dispatcher->get_action($name, $self->action_namespace);
136 #my opinion is that this whole sub really should be a builder method, not
137 #something that happens on every call. Anyone else disagree?? -- groditi
138 ## -- apparently this is all just waiting for app/ctx split
139 around action_namespace => sub {
141 my ( $self, $c ) = @_;
143 my $class = ref($self) || $self;
144 my $appclass = ref($c) || $c;
146 return $self->$orig if $self->has_action_namespace;
148 return $class->config->{namespace} if exists $class->config->{namespace};
153 $case_s = $appclass->config->{case_sensitive};
155 if ($self->isa('Catalyst')) {
156 $case_s = $class->config->{case_sensitive};
159 $case_s = ref($self->_application)->config->{case_sensitive};
161 confess("Can't figure out case_sensitive setting");
166 my $namespace = Catalyst::Utils::class2prefix($self->catalyst_component_name, $case_s) || '';
167 $self->$orig($namespace) if ref($self);
171 #Once again, this is probably better written as a builder method
172 around path_prefix => sub {
176 return $self->$orig if $self->has_path_prefix;
178 return $self->config->{path} if exists $self->config->{path};
180 my $namespace = $self->action_namespace(@_);
181 $self->$orig($namespace) if ref($self);
185 sub get_action_methods {
187 my $meta = find_meta($self) || confess("No metaclass setup for $self");
189 . ref($meta) . " for "
191 . " cannot support register_actions." )
192 unless $meta->can('get_nearest_methods_with_attributes');
193 my @methods = $meta->get_nearest_methods_with_attributes;
195 # actions specified via config are also action_methods
199 $meta->find_method_by_name($_)
200 || confess( 'Action "'
202 . '" is not available from controller '
204 } keys %{ $self->_controller_actions }
206 return uniq @methods;
210 sub register_actions {
211 my ( $self, $c ) = @_;
212 $self->register_action_methods( $c, $self->get_action_methods );
215 sub register_action_methods {
216 my ( $self, $c, @methods ) = @_;
217 my $class = $self->catalyst_component_name;
218 #this is still not correct for some reason.
219 my $namespace = $self->action_namespace($c);
222 if (!blessed($self) && $self eq $c && scalar(@methods)) {
223 my @really_bad_methods = grep { ! /^_(DISPATCH|BEGIN|AUTO|ACTION|END)$/ } map { $_->name } @methods;
224 if (scalar(@really_bad_methods)) {
225 $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.");
229 foreach my $method (@methods) {
230 my $name = $method->name;
231 my $attributes = $method->attributes;
232 my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
233 if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
234 $c->log->debug( 'Bad action definition "'
235 . join( ' ', @{ $attributes } )
236 . qq/" for "$class->$name"/ )
240 my $reverse = $namespace ? "${namespace}/${name}" : $name;
241 my $action = $self->create_action(
243 code => $method->body,
245 namespace => $namespace,
247 attributes => $attrs,
250 $c->dispatcher->register( $c, $action );
255 my ($self, %args) = @_;
257 my $class = (exists $args{attributes}{ActionClass}
258 ? $args{attributes}{ActionClass}[0]
259 : $self->_action_class);
260 Class::MOP::load_class($class);
268 my $class = $self->action_class(%args);
270 my $action_args = $self->config->{action_args};
272 %{ $action_args->{'*'} || {} },
273 %{ $action_args->{ $args{name} } || {} },
276 return $class->new({ %extra_args, %args });
280 my ( $self, $c, $name, @attrs ) = @_;
284 foreach my $attr (@attrs) {
286 # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
288 if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
291 if ( defined $value ) {
292 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
294 push( @{ $raw_attributes{$key} }, $value );
298 #I know that the original behavior was to ignore action if actions was set
299 # but i actually think this may be a little more sane? we can always remove
300 # the merge behavior quite easily and go back to having actions have
301 # presedence over action by modifying the keys. i honestly think this is
302 # superior while mantaining really high degree of compat
305 $actions = $self->_controller_actions;
307 my $cfg = $self->config;
308 $actions = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
311 %raw_attributes = ((exists $actions->{'*'} ? %{$actions->{'*'}} : ()),
313 (exists $actions->{$name} ? %{$actions->{$name}} : ()));
316 my %final_attributes;
318 foreach my $key (keys %raw_attributes) {
320 my $raw = $raw_attributes{$key};
322 foreach my $value (ref($raw) eq 'ARRAY' ? @$raw : $raw) {
324 my $meth = "_parse_${key}_attr";
325 if ( my $code = $self->can($meth) ) {
326 ( $key, $value ) = $self->$code( $c, $name, $value );
328 push( @{ $final_attributes{$key} }, $value );
332 return \%final_attributes;
335 sub _parse_Global_attr {
336 my ( $self, $c, $name, $value ) = @_;
337 return $self->_parse_Path_attr( $c, $name, "/$name" );
340 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
342 sub _parse_Local_attr {
343 my ( $self, $c, $name, $value ) = @_;
344 return $self->_parse_Path_attr( $c, $name, $name );
347 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
349 sub _parse_Path_attr {
350 my ( $self, $c, $name, $value ) = @_;
351 $value = '' if !defined $value;
352 if ( $value =~ m!^/! ) {
353 return ( 'Path', $value );
355 elsif ( length $value ) {
356 return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
359 return ( 'Path', $self->path_prefix($c) );
363 sub _parse_Regex_attr {
364 my ( $self, $c, $name, $value ) = @_;
365 return ( 'Regex', $value );
368 sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
370 sub _parse_LocalRegex_attr {
371 my ( $self, $c, $name, $value ) = @_;
372 unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
374 my $prefix = $self->path_prefix( $c );
375 $prefix .= '/' if length( $prefix );
377 return ( 'Regex', "^${prefix}${value}" );
380 sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
382 sub _parse_Chained_attr {
383 my ($self, $c, $name, $value) = @_;
385 if (defined($value) && length($value)) {
387 $value = '/'.$self->action_namespace($c);
388 } elsif (my ($rel, $rest) = $value =~ /^((?:\.{2}\/)+)(.*)$/) {
389 my @parts = split '/', $self->action_namespace($c);
390 my @levels = split '/', $rel;
392 $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
393 } elsif ($value !~ m/^\//) {
394 my $action_ns = $self->action_namespace($c);
397 $value = '/'.join('/', $action_ns, $value);
399 $value = '/'.$value; # special case namespace '' (root)
406 return Chained => $value;
409 sub _parse_ChainedParent_attr {
410 my ($self, $c, $name, $value) = @_;
411 return $self->_parse_Chained_attr($c, $name, '../'.$name);
414 sub _parse_PathPrefix_attr {
415 my ( $self, $c ) = @_;
416 return PathPart => $self->path_prefix($c);
419 sub _parse_ActionClass_attr {
420 my ( $self, $c, $name, $value ) = @_;
421 my $appname = $self->_application;
422 $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
423 return ( 'ActionClass', $value );
426 sub _parse_MyAction_attr {
427 my ( $self, $c, $name, $value ) = @_;
429 my $appclass = Catalyst::Utils::class2appclass($self);
430 $value = "${appclass}::Action::${value}";
432 return ( 'ActionClass', $value );
435 __PACKAGE__->meta->make_immutable;
443 Like any other L<Catalyst::Component>, controllers have a config hash,
444 accessible through $self->config from the controller actions. Some
445 settings are in use by the Catalyst framework:
449 This specifies the internal namespace the controller should be bound
450 to. By default the controller is bound to the URI version of the
451 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
452 will be bound to 'foo/bar'. The default Root controller is an example
453 of setting namespace to '' (the null string).
457 Sets 'path_prefix', as described below.
461 Allows you to set the attributes that the dispatcher creates actions out of.
462 This allows you to do 'rails style routes', or override some of the
463 attribute defintions of actions composed from Roles.
464 You can set arguments globally (for all actions of the controller) and
465 specifically (for a single action).
469 '*' => { Chained => 'base', Args => 0 },
470 base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
474 In the case above every sub in the package would be made into a Chain
475 endpoint with a URI the same as the sub name for each sub, chained
476 to the sub named C<base>. Ergo dispatch to C</example> would call the
477 C<base> method, then the C<example> method.
481 Allows you to set constructor arguments on your actions. You can set arguments
482 globally and specifically (as above).
483 This is particularly useful when using C<ActionRole>s
484 (L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.
488 '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
489 'specific_action' => { customarg => 'arg1' },
493 In the case above the action class associated with C<specific_action> would get
494 passed the following arguments, in addition to the normal action constructor
495 arguments, when it is instantiated:
497 (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
501 =head2 BUILDARGS ($app, @args)
503 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
504 instance as $self->_application.
506 =head2 $self->action_for('name')
508 Returns the Catalyst::Action object (if any) for a given method name
511 =head2 $self->action_namespace($c)
513 Returns the private namespace for actions in this component. Defaults
514 to a value from the controller name (for
515 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
516 overridden from the "namespace" config key.
519 =head2 $self->path_prefix($c)
521 Returns the default path prefix for :PathPrefix, :Local, :LocalRegex and
522 relative :Path actions in this component. Defaults to the action_namespace or
523 can be overridden from the "path" config key.
525 =head2 $self->register_actions($c)
527 Finds all applicable actions for this component, creates
528 Catalyst::Action objects (using $self->create_action) for them and
529 registers them with $c->dispatcher.
531 =head2 $self->get_action_methods()
533 Returns a list of L<Moose::Meta::Method> objects, doing the
534 L<MooseX::MethodAttributes::Role::Meta::Method> role, which are the set of
535 action methods for this package.
537 =head2 $self->register_action_methods($c, @methods)
539 Creates action objects for a set of action methods using C< create_action >,
540 and registers them with the dispatcher.
542 =head2 $self->create_action(%args)
544 Called with a hash of data to be use for construction of a new
545 Catalyst::Action (or appropriate sub/alternative class) object.
547 =head2 $self->_application
551 Returns the application instance stored by C<new()>
555 Catalyst Contributors, see Catalyst.pm
559 This library is free software. You can redistribute it and/or modify
560 it under the same terms as Perl itself.