Merge branch 'master' into gsoc_breadboard
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
1 package Catalyst::Controller;
2
3 use Moose;
4 use Class::MOP;
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';
11
12 BEGIN { extends qw/Catalyst::Component MooseX::MethodAttributes::Inheritable/; }
13
14 use MooseX::MethodAttributes;
15 use Catalyst::Exception;
16 use Catalyst::Utils;
17
18 with 'Catalyst::Component::ApplicationAttribute';
19
20 has path_prefix => (
21     is        => 'rw',
22     isa       => 'Str',
23     init_arg  => 'path',
24     predicate => 'has_path_prefix',
25 );
26
27 has action_namespace => (
28     is        => 'rw',
29     isa       => 'Str',
30     init_arg  => 'namespace',
31     predicate => 'has_action_namespace',
32 );
33
34 has actions => (
35     accessor => '_controller_actions',
36     isa      => 'HashRef',
37     init_arg => undef,
38 );
39
40 has _action_role_args => (
41     traits     => [qw(Array)],
42     isa        => 'ArrayRef[Str]',
43     init_arg   => 'action_roles',
44     default    => sub { [] },
45     handles    => {
46         _action_role_args => 'elements',
47     },
48 );
49
50 has _action_roles => (
51     traits     => [qw(Array)],
52     isa        => 'ArrayRef[RoleName]',
53     init_arg   => undef,
54     lazy       => 1,
55     builder    => '_build__action_roles',
56     handles    => {
57         _action_roles => 'elements',
58     },
59 );
60
61 has action_args => (is => 'ro');
62
63 # ->config(actions => { '*' => ...
64 has _all_actions_attributes => (
65     is       => 'ro',
66     isa      => 'HashRef',
67     init_arg => undef,
68     lazy     => 1,
69     builder  => '_build__all_actions_attributes',
70 );
71
72 sub BUILD {
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);
78
79     # trigger lazy builder
80     $self->_all_actions_attributes;
81     $self->_action_roles;
82 }
83
84 sub _build__action_roles {
85     my $self = shift;
86     my @roles = $self->_expand_role_shortname($self->_action_role_args);
87     load_class($_) for @roles;
88     return \@roles;
89 }
90
91 sub _build__all_actions_attributes {
92     my ($self) = @_;
93     delete $self->_controller_actions->{'*'} || {};
94 }
95
96 =head1 NAME
97
98 Catalyst::Controller - Catalyst Controller base class
99
100 =head1 SYNOPSIS
101
102   package MyApp::Controller::Search
103   use base qw/Catalyst::Controller/;
104
105   sub foo : Local {
106     my ($self,$c,@args) = @_;
107     ...
108   } # Dispatches to /search/foo
109
110 =head1 DESCRIPTION
111
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.
116
117 =cut
118
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/;
122
123 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
124 __PACKAGE__->_action_class('Catalyst::Action');
125 __PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
126
127
128 sub _DISPATCH : Private {
129     my ( $self, $c ) = @_;
130
131     foreach my $disp ( @{ $self->_dispatch_steps } ) {
132         last unless $c->forward($disp);
133     }
134
135     $c->forward('_END');
136 }
137
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 };
144 }
145
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;
152     }
153     return 1;
154 }
155
156 sub _ACTION : Private {
157     my ( $self, $c ) = @_;
158     if (   ref $c->action
159         && $c->action->can('execute')
160         && defined $c->req->action )
161     {
162         $c->action->dispatch( $c );
163     }
164     return !@{ $c->error };
165 }
166
167 sub _END : Private {
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 };
173 }
174
175 sub action_for {
176     my ( $self, $name ) = @_;
177     my $app = ($self->isa('Catalyst') ? $self : $self->_application);
178     return $app->dispatcher->get_action($name, $self->action_namespace);
179 }
180
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 {
185     my $orig = shift;
186     my ( $self, $c ) = @_;
187
188     my $class = ref($self) || $self;
189     my $appclass = ref($c) || $c;
190
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;
195
196     if( ref($self) ){
197         return $self->$orig if $self->has_action_namespace;
198     } else {
199         return $class->config->{namespace} if exists $class->config->{namespace};
200     }
201
202     my $case_s;
203     if( $c ){
204         $case_s = $appclass->config->{case_sensitive};
205     } else {
206         if ($self->isa('Catalyst')) {
207             $case_s = $class->config->{case_sensitive};
208         } else {
209             if (ref $self) {
210                 $case_s = ref($self->_application)->config->{case_sensitive};
211             } else {
212                 confess("Can't figure out case_sensitive setting");
213             }
214         }
215     }
216
217     my $namespace = Catalyst::Utils::class2prefix($component_name, $case_s) || '';
218     $self->$orig($namespace) if ref($self);
219     return $namespace;
220 };
221
222 #Once again, this is probably better written as a builder method
223 around path_prefix => sub {
224     my $orig = shift;
225     my $self = shift;
226     if( ref($self) ){
227       return $self->$orig if $self->has_path_prefix;
228     } else {
229       return $self->config->{path} if exists $self->config->{path};
230     }
231     my $namespace = $self->action_namespace(@_);
232     $self->$orig($namespace) if ref($self);
233     return $namespace;
234 };
235
236 sub get_action_methods {
237     my $self = shift;
238     my $meta = find_meta($self) || confess("No metaclass setup for $self");
239     confess(
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;
244
245     # actions specified via config are also action_methods
246     push(
247         @methods,
248         map {
249             $meta->find_method_by_name($_)
250                 || confess( sprintf 'Action "%s" is not available from controller %s',
251                             $_, ref $self )
252         } keys %{ $self->_controller_actions }
253     ) if ( ref $self );
254     return uniq @methods;
255 }
256
257
258 sub register_actions {
259     my ( $self, $c ) = @_;
260     $self->register_action_methods( $c, $self->get_action_methods );
261 }
262
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);
268
269     # FIXME - fugly
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.");
274         }
275     }
276
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"/ )
287               if $c->debug;
288             next;
289         }
290         my $reverse = $namespace ? "${namespace}/${name}" : $name;
291         my $action = $self->create_action(
292             name       => $name,
293             code       => $method->body,
294             reverse    => $reverse,
295             namespace  => $namespace,
296             class      => $class,
297             attributes => $attrs,
298         );
299
300         $c->dispatcher->register( $c, $action );
301     }
302 }
303
304 sub _apply_action_class_roles {
305     my ($self, $class, @roles) = @_;
306
307     load_class($_) for @roles;
308     my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
309         superclasses => [$class],
310         roles        => \@roles,
311         cache        => 1,
312     );
313     $meta->add_method(meta => sub { $meta });
314
315     return $meta->name;
316 }
317
318 sub action_class {
319     my $self = shift;
320     my %args = @_;
321
322     my $class = (exists $args{attributes}{ActionClass}
323         ? $args{attributes}{ActionClass}[0]
324         : $self->_action_class);
325
326     Class::MOP::load_class($class);
327     return $class;
328 }
329
330 sub create_action {
331     my $self = shift;
332     my %args = @_;
333
334     my $class = $self->action_class(%args);
335
336     load_class($class);
337     Moose->init_meta(for_class => $class)
338         unless Class::MOP::does_metaclass_exist($class);
339
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;
343     }
344
345     my $action_args = (
346         ref($self)
347             ? $self->action_args
348             : $self->config->{action_args}
349     );
350
351     my %extra_args = (
352         %{ $action_args->{'*'}           || {} },
353         %{ $action_args->{ $args{name} } || {} },
354     );
355
356     return $class->new({ %extra_args, %args });
357 }
358
359 sub gather_action_roles {
360    my ($self, %args) = @_;
361
362    return (
363       (blessed $self ? $self->_action_roles : ()),
364       @{ $args{attributes}->{Does} || [] },
365    );
366 }
367
368 sub _parse_attrs {
369     my ( $self, $c, $name, @attrs ) = @_;
370
371     my %raw_attributes;
372
373     foreach my $attr (@attrs) {
374
375         # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
376
377         if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
378         {
379
380             if ( defined $value ) {
381                 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
382             }
383             push( @{ $raw_attributes{$key} }, $value );
384         }
385     }
386
387     my ($actions_config, $all_actions_config);
388     if( ref($self) ) {
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;
392     } else {
393         my $cfg = $self->config;
394         $actions_config = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
395         $all_actions_config = {};
396     }
397
398     %raw_attributes = (
399         %raw_attributes,
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 } } : (),
403     );
404
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
410     # Private ones.
411     %raw_attributes = (%{ $all_actions_config }, %raw_attributes)
412         unless $raw_attributes{Private};
413
414     my %final_attributes;
415
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;
419     }
420
421     return \%final_attributes;
422 }
423
424 sub _parse_attr {
425     my ($self, $c, $name, $key, $values) = @_;
426
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;
437             }
438         }
439         else {
440             push( @{ $final_attributes{$key} }, $value );
441         }
442     }
443
444     return \%final_attributes;
445 }
446
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";
451 }
452
453 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
454
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;
459 }
460
461 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
462
463 sub _parse_Path_attr {
464     my ( $self, $c, $name, $value ) = @_;
465     $value = '' if !defined $value;
466     if ( $value =~ m!^/! ) {
467         return ( 'Path', $value );
468     }
469     elsif ( length $value ) {
470         return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
471     }
472     else {
473         return ( 'Path', $self->path_prefix($c) );
474     }
475 }
476
477 sub _parse_Regex_attr {
478     my ( $self, $c, $name, $value ) = @_;
479     return ( 'Regex', $value );
480 }
481
482 sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
483
484 sub _parse_LocalRegex_attr {
485     my ( $self, $c, $name, $value ) = @_;
486     unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
487
488     my $prefix = $self->path_prefix( $c );
489     $prefix .= '/' if length( $prefix );
490
491     return ( 'Regex', "^${prefix}${value}" );
492 }
493
494 sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
495
496 sub _parse_Chained_attr {
497     my ($self, $c, $name, $value) = @_;
498
499     if (defined($value) && length($value)) {
500         if ($value eq '.') {
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;
505
506             $value = '/'.join('/', @parts[0 .. $#parts - @levels], $rest);
507         } elsif ($value !~ m/^\//) {
508             my $action_ns = $self->action_namespace($c);
509
510             if ($action_ns) {
511                 $value = '/'.join('/', $action_ns, $value);
512             } else {
513                 $value = '/'.$value; # special case namespace '' (root)
514             }
515         }
516     } else {
517         $value = '/'
518     }
519
520     return Chained => $value;
521 }
522
523 sub _parse_ChainedParent_attr {
524     my ($self, $c, $name, $value) = @_;
525     return $self->_parse_Chained_attr($c, $name, '../'.$name);
526 }
527
528 sub _parse_PathPrefix_attr {
529     my ( $self, $c ) = @_;
530     return PathPart => $self->path_prefix($c);
531 }
532
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 );
538 }
539
540 sub _parse_MyAction_attr {
541     my ( $self, $c, $name, $value ) = @_;
542
543     my $appclass = Catalyst::Utils::class2appclass($self);
544     $value = "+${appclass}::Action::${value}";
545
546     return ( 'ActionClass', $value );
547 }
548
549 sub _parse_Does_attr {
550     my ($self, $app, $name, $value) = @_;
551     return Does => $self->_expand_role_shortname($value);
552 }
553
554 sub _expand_role_shortname {
555     my ($self, @shortnames) = @_;
556     my $app = $self->_application;
557
558     my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
559     my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
560
561     return String::RewritePrefix->rewrite(
562         { ''  => sub {
563             my $loaded = load_first_existing_class(
564                 map { "$_$_[0]" } @prefixes
565             );
566             return first { $loaded =~ /^$_/ }
567               sort { length $b <=> length $a } @prefixes;
568           },
569           '~' => $prefixes[0],
570           '+' => '' },
571         @shortnames,
572     );
573 }
574
575 __PACKAGE__->meta->make_immutable;
576
577 1;
578
579 __END__
580
581 =head1 CONFIGURATION
582
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:
586
587 =head2 namespace
588
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).
594
595 =head2 path
596
597 Sets 'path_prefix', as described below.
598
599 =head2 action
600
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).
606
607     __PACKAGE__->config(
608         action => {
609             '*' => { Chained => 'base', Args => 0  },
610             base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
611         },
612      );
613
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.
618
619 =head2 action_args
620
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.
625
626     __PACKAGE__->config(
627         action_args => {
628             '*' => { globalarg1 => 'hello', globalarg2 => 'goodbye' },
629             'specific_action' => { customarg => 'arg1' },
630         },
631      );
632
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:
636
637   (globalarg1 => 'hello', globalarg2 => 'goodbye', customarg => 'arg1')
638
639 =head1 METHODS
640
641 =head2 BUILDARGS ($app, @args)
642
643 From L<Catalyst::Component::ApplicationAttribute>, stashes the application
644 instance as $self->_application.
645
646 =head2 $self->action_for('name')
647
648 Returns the Catalyst::Action object (if any) for a given method name
649 in this component.
650
651 =head2 $self->action_namespace($c)
652
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.
657
658
659 =head2 $self->path_prefix($c)
660
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.
664
665 =head2 $self->register_actions($c)
666
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.
670
671 =head2 $self->get_action_methods()
672
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.
676
677 =head2 $self->register_action_methods($c, @methods)
678
679 Creates action objects for a set of action methods using C< create_action >,
680 and registers them with the dispatcher.
681
682 =head2 $self->action_class(%args)
683
684 Used when a controller is creating an action to determine the correct base
685 action class to use.
686
687 =head2 $self->create_action(%args)
688
689 Called with a hash of data to be use for construction of a new
690 Catalyst::Action (or appropriate sub/alternative class) object.
691
692 =head2 $self->gather_action_roles(\%action_args)
693
694 Gathers the list of roles to apply to an action with the given %action_args.
695
696 =head2 $self->_application
697
698 =head2 $self->_app
699
700 Returns the application instance stored by C<new()>
701
702 =head1 AUTHORS
703
704 Catalyst Contributors, see Catalyst.pm
705
706 =head1 COPYRIGHT
707
708 This library is free software. You can redistribute it and/or modify
709 it under the same terms as Perl itself.
710
711 =cut