revert MyApp instantiation
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Controller.pm
1 package Catalyst::Controller;
2
3 #switch to BEGIN { extends qw/ ... /; } ?
4 use MRO::Compat;
5 use mro 'c3';
6 use base qw/Catalyst::Component Catalyst::AttrContainer/;
7 use Moose;
8
9 use Scalar::Util qw/blessed/;
10 use Catalyst::Exception;
11 use Catalyst::Utils;
12 use Class::Inspector;
13
14 has path_prefix =>
15     (
16      is => 'rw',
17      isa => 'Str',
18      init_arg => 'path',
19      predicate => 'has_path_prefix',
20     );
21
22 has action_namespace =>
23     (
24      is => 'rw',
25      isa => 'Str',
26      init_arg => 'namespace',
27      predicate => 'has_action_namespace',
28     );
29
30 has actions =>
31     (
32      is => 'rw',
33      isa => 'HashRef',
34      init_arg => undef,
35     );
36
37 # isa => 'ClassName|Catalyst' ?
38 has _application => (is => 'rw');
39 sub _app{ shift->_application(@_) } 
40
41 sub BUILD {
42     my ($self, $args) = @_;
43     my $action  = delete $args->{action}  || {};
44     my $actions = delete $args->{actions} || {};
45     my $attr_value = $self->merge_config_hashes($actions, $action);
46     $self->actions($attr_value);
47 }
48
49 =head1 NAME
50
51 Catalyst::Controller - Catalyst Controller base class
52
53 =head1 SYNOPSIS
54
55   package MyApp::Controller::Search
56   use base qw/Catalyst::Controller/;
57
58   sub foo : Local { 
59     my ($self,$c,@args) = @_;
60     ... 
61   } # Dispatches to /search/foo
62
63 =head1 DESCRIPTION
64
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.
69
70 =cut
71
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 _action_class/;
75
76 __PACKAGE__->_dispatch_steps( [qw/_BEGIN _AUTO _ACTION/] );
77 __PACKAGE__->_action_class('Catalyst::Action');
78
79
80 sub _DISPATCH : Private {
81     my ( $self, $c ) = @_;
82
83     foreach my $disp ( @{ $self->_dispatch_steps } ) {
84         last unless $c->forward($disp);
85     }
86
87     $c->forward('_END');
88 }
89
90 sub _BEGIN : Private {
91     my ( $self, $c ) = @_;
92     my $begin = ( $c->get_actions( 'begin', $c->namespace ) )[-1];
93     return 1 unless $begin;
94     $begin->dispatch( $c );
95     return !@{ $c->error };
96 }
97
98 sub _AUTO : Private {
99     my ( $self, $c ) = @_;
100     my @auto = $c->get_actions( 'auto', $c->namespace );
101     foreach my $auto (@auto) {
102         $auto->dispatch( $c );
103         return 0 unless $c->state;
104     }
105     return 1;
106 }
107
108 sub _ACTION : Private {
109     my ( $self, $c ) = @_;
110     if (   ref $c->action
111         && $c->action->can('execute')
112         && $c->req->action )
113     {
114         $c->action->dispatch( $c );
115     }
116     return !@{ $c->error };
117 }
118
119 sub _END : Private {
120     my ( $self, $c ) = @_;
121     my $end = ( $c->get_actions( 'end', $c->namespace ) )[-1];
122     return 1 unless $end;
123     $end->dispatch( $c );
124     return !@{ $c->error };
125 }
126
127 sub new {
128     my $self = shift;
129     my $app = $_[0];
130     my $new = $self->next::method(@_);
131     $new->_application( $app );
132     return $new;
133 }
134
135 sub action_for {
136     my ( $self, $name ) = @_;
137     my $app = ($self->isa('Catalyst') ? $self : $self->_application);
138     return $app->dispatcher->get_action($name, $self->action_namespace);
139 }
140
141 #my opinion is that this whole sub really should be a builder method, not 
142 #something that happens on every call. Anyone else disagree?? -- groditi
143 ## -- apparently this is all just waiting for app/ctx split
144 around action_namespace => sub {
145     my $orig = shift;
146     my ( $self, $c ) = @_;
147
148     if( ref($self) ){
149         return $self->$orig if $self->has_action_namespace;
150     } else { 
151         return $self->config->{namespace} if exists $self->config->{namespace};
152     }
153
154     my $case_s;
155     if( $c ){
156         $case_s = $c->config->{case_sensitive};
157     } else {
158         if ($self->isa('Catalyst')) {
159             $case_s = $self->config->{case_sensitive};
160         } else {
161             if (ref $self) {
162                 $case_s = $self->_application->config->{case_sensitive};
163             } else {
164                 confess("Can't figure out case_sensitive setting");
165             }
166         }
167     }
168
169     my $namespace = Catalyst::Utils::class2prefix(ref($self) || $self, $case_s) || '';
170     $self->$orig($namespace) if ref($self);
171     return $namespace;
172 };
173
174 #Once again, this is probably better written as a builder method
175 around path_prefix => sub {
176     my $orig = shift;
177     my $self = shift;
178     if( ref($self) ){
179       return $self->$orig if $self->has_path_prefix;
180     } else {
181       return $self->config->{path} if exists $self->config->{path};
182     }
183     my $namespace = $self->action_namespace(@_);
184     $self->$orig($namespace) if ref($self);
185     return $namespace;
186 };
187
188
189 sub register_actions {
190     my ( $self, $c ) = @_;
191     my $class = ref $self || $self;
192     #this is still not correct for some reason.
193     my $namespace = $self->action_namespace($c);
194     my $meta = $self->meta;
195     my %methods = map{ $_->{code}->body => $_->{name} }
196         grep {$_->{class} ne 'Moose::Object'} #ignore Moose::Object methods
197             $meta->compute_all_applicable_methods;
198
199
200     # Advanced inheritance support for plugins and the like
201     #moose todo: migrate to eliminate CDI compat
202     my @action_cache;
203     for my $isa ( $meta->superclasses, $class ) {
204         if(my $coderef = $isa->can('_action_cache')){
205             push(@action_cache, @{ $isa->$coderef });
206         }
207     }
208
209     foreach my $cache (@action_cache) {
210         my $code   = $cache->[0];
211         my $method = delete $methods{$code}; # avoid dupe registers
212         next unless $method;
213         my $attrs = $self->_parse_attrs( $c, $method, @{ $cache->[1] } );
214         if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
215             $c->log->debug( 'Bad action definition "'
216                   . join( ' ', @{ $cache->[1] } )
217                   . qq/" for "$class->$method"/ )
218               if $c->debug;
219             next;
220         }
221         my $reverse = $namespace ? "${namespace}/${method}" : $method;
222         my $action = $self->create_action(
223             name       => $method,
224             code       => $code,
225             reverse    => $reverse,
226             namespace  => $namespace,
227             class      => $class,
228             attributes => $attrs,
229         );
230
231         $c->dispatcher->register( $c, $action );
232     }
233 }
234
235 sub create_action {
236     my $self = shift;
237     my %args = @_;
238
239     my $class = (exists $args{attributes}{ActionClass}
240                     ? $args{attributes}{ActionClass}[0]
241                     : $self->_action_class);
242
243     Class::MOP::load_class($class);
244     return $class->new( \%args );
245 }
246
247 sub _parse_attrs {
248     my ( $self, $c, $name, @attrs ) = @_;
249
250     my %raw_attributes;
251
252     foreach my $attr (@attrs) {
253
254         # Parse out :Foo(bar) into Foo => bar etc (and arrayify)
255
256         if ( my ( $key, $value ) = ( $attr =~ /^(.*?)(?:\(\s*(.+?)\s*\))?$/ ) )
257         {
258
259             if ( defined $value ) {
260                 ( $value =~ s/^'(.*)'$/$1/ ) || ( $value =~ s/^"(.*)"/$1/ );
261             }
262             push( @{ $raw_attributes{$key} }, $value );
263         }
264     }
265
266     #I know that the original behavior was to ignore action if actions was set
267     # but i actually think this may be a little more sane? we can always remove
268     # the merge behavior quite easily and go back to having actions have
269     # presedence over action by modifying the keys. i honestly think this is
270     # superior while mantaining really high degree of compat
271     my $actions;
272     if( ref($self) ) {
273         $actions = $self->actions;
274     } else {
275         my $cfg = $self->config;
276         $actions = $self->merge_config_hashes($cfg->{actions}, $cfg->{action});
277     }
278
279     %raw_attributes = ((exists $actions->{'*'} ? %{$actions->{'*'}} : ()),
280                        %raw_attributes,
281                        (exists $actions->{$name} ? %{$actions->{$name}} : ()));
282
283
284     my %final_attributes;
285
286     foreach my $key (keys %raw_attributes) {
287
288         my $raw = $raw_attributes{$key};
289
290         foreach my $value (ref($raw) eq 'ARRAY' ? @$raw : $raw) {
291
292             my $meth = "_parse_${key}_attr";
293             if ( my $code = $self->can($meth) ) {
294                 ( $key, $value ) = $self->$code( $c, $name, $value );
295             }
296             push( @{ $final_attributes{$key} }, $value );
297         }
298     }
299
300     return \%final_attributes;
301 }
302
303 sub _parse_Global_attr {
304     my ( $self, $c, $name, $value ) = @_;
305     return $self->_parse_Path_attr( $c, $name, "/$name" );
306 }
307
308 sub _parse_Absolute_attr { shift->_parse_Global_attr(@_); }
309
310 sub _parse_Local_attr {
311     my ( $self, $c, $name, $value ) = @_;
312     return $self->_parse_Path_attr( $c, $name, $name );
313 }
314
315 sub _parse_Relative_attr { shift->_parse_Local_attr(@_); }
316
317 sub _parse_Path_attr {
318     my ( $self, $c, $name, $value ) = @_;
319     $value ||= '';
320     if ( $value =~ m!^/! ) {
321         return ( 'Path', $value );
322     }
323     elsif ( length $value ) {
324         return ( 'Path', join( '/', $self->path_prefix($c), $value ) );
325     }
326     else {
327         return ( 'Path', $self->path_prefix($c) );
328     }
329 }
330
331 sub _parse_Regex_attr {
332     my ( $self, $c, $name, $value ) = @_;
333     return ( 'Regex', $value );
334 }
335
336 sub _parse_Regexp_attr { shift->_parse_Regex_attr(@_); }
337
338 sub _parse_LocalRegex_attr {
339     my ( $self, $c, $name, $value ) = @_;
340     unless ( $value =~ s/^\^// ) { $value = "(?:.*?)$value"; }
341     return ( 'Regex', '^' . $self->path_prefix($c) . "/${value}" );
342 }
343
344 sub _parse_LocalRegexp_attr { shift->_parse_LocalRegex_attr(@_); }
345
346 sub _parse_ActionClass_attr {
347     my ( $self, $c, $name, $value ) = @_;
348     unless ( $value =~ s/^\+// ) {
349       $value = join('::', $self->_action_class, $value );
350     }
351     return ( 'ActionClass', $value );
352 }
353
354 sub _parse_MyAction_attr {
355     my ( $self, $c, $name, $value ) = @_;
356
357     my $appclass = Catalyst::Utils::class2appclass($self);
358     $value = "${appclass}::Action::${value}";
359
360     return ( 'ActionClass', $value );
361 }
362
363 no Moose;
364
365 1;
366
367 __END__
368
369 =head1 CONFIGURATION
370
371 Like any other L<Catalyst::Component>, controllers have a config hash,
372 accessible through $self->config from the controller actions.  Some
373 settings are in use by the Catalyst framework:
374
375 =head2 namespace
376
377 This specifies the internal namespace the controller should be bound
378 to. By default the controller is bound to the URI version of the
379 controller name. For instance controller 'MyApp::Controller::Foo::Bar'
380 will be bound to 'foo/bar'. The default Root controller is an example
381 of setting namespace to '' (the null string).
382
383 =head2 path 
384
385 Sets 'path_prefix', as described below.
386
387 =head1 METHODS
388
389 =head2 $class->new($app, @args)
390
391 Proxies through to NEXT::new and stashes the application instance as
392 $self->_application.
393
394 =head2 $self->action_for('name')
395
396 Returns the Catalyst::Action object (if any) for a given method name
397 in this component.
398
399 =head2 $self->register_actions($c)
400
401 Finds all applicable actions for this component, creates
402 Catalyst::Action objects (using $self->create_action) for them and
403 registers them with $c->dispatcher.
404
405 =head2 $self->action_namespace($c)
406
407 Returns the private namespace for actions in this component. Defaults
408 to a value from the controller name (for
409 e.g. MyApp::Controller::Foo::Bar becomes "foo/bar") or can be
410 overridden from the "namespace" config key.
411
412
413 =head2 $self->path_prefix($c)
414
415 Returns the default path prefix for :Local, :LocalRegex and relative
416 :Path actions in this component. Defaults to the action_namespace or
417 can be overridden from the "path" config key.
418
419 =head2 $self->create_action(%args)
420
421 Called with a hash of data to be use for construction of a new
422 Catalyst::Action (or appropriate sub/alternative class) object.
423
424 Primarily designed for the use of register_actions.
425
426 =head2 $self->_application
427
428 =head2 $self->_app
429
430 Returns the application instance stored by C<new()>
431
432 =head1 AUTHOR
433
434 Sebastian Riedel, C<sri@oook.de>
435 Marcus Ramberg C<mramberg@cpan.org>
436
437 =head1 COPYRIGHT
438
439 This program is free software, you can redistribute it and/or modify
440 it under the same terms as Perl itself.
441
442 =cut