fe8036c6ff7a441d284ff3db209f6515d2c07950
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Setup.pm
1 package Catalyst::Setup;
2
3 use strict;
4 use base qw/Class::Data::Inheritable/;
5 use Catalyst::Exception;
6 use Catalyst::Log;
7 use Catalyst::Utils;
8 use Path::Class;
9 use Text::ASCIITable;
10
11 __PACKAGE__->mk_classdata($_) for qw/arguments dispatcher engine log/;
12
13 =head1 NAME
14
15 Catalyst::Setup - The Catalyst Setup class
16
17 =head1 SYNOPSIS
18
19 See L<Catalyst>.
20
21 =head1 DESCRIPTION
22
23 =head1 METHODS
24
25 =over 4
26
27 =item $c->setup
28
29 Setup.
30
31     $c->setup;
32
33 =cut
34
35 sub setup {
36     my $class = shift;
37
38     # Call plugins setup
39     $class->NEXT::setup;
40
41     # Initialize our data structure
42     $class->components( {} );
43
44     $class->setup_components;
45
46     if ( $class->debug ) {
47         my $t = Text::ASCIITable->new;
48         $t->setOptions( 'hide_HeadRow',  1 );
49         $t->setOptions( 'hide_HeadLine', 1 );
50         $t->setCols('Class');
51         $t->setColWidth( 'Class', 75, 1 );
52         $t->addRow($_) for sort keys %{ $class->components };
53         $class->log->debug( "Loaded components:\n" . $t->draw )
54           if ( @{ $t->{tbl_rows} } );
55     }
56
57     # Add our self to components, since we are also a component
58     $class->components->{$class} = $class;
59
60     $class->setup_actions;
61
62     if ( $class->debug ) {
63         my $name = $class->config->{name} || 'Application';
64         $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
65     }
66 }
67
68 =item $c->setup_components
69
70 Setup components.
71
72 =cut
73
74 sub setup_components {
75     my $class = shift;
76
77     my $callback = sub {
78         my ( $component, $context ) = @_;
79
80         unless ( $component->isa('Catalyst::Base') ) {
81             return $component;
82         }
83
84         my $suffix = Catalyst::Utils::class2classsuffix($component);
85         my $config = $class->config->{$suffix} || {};
86
87         my $instance;
88
89         eval { $instance = $component->new( $context, $config ); };
90
91         if ( my $error = $@ ) {
92
93             chomp $error;
94
95             Catalyst::Exception->throw( 
96                 message => qq/Couldn't instantiate component "$component", "$error"/
97             );
98         }
99
100         return $instance;
101     };
102
103     eval {
104         Module::Pluggable::Fast->import(
105             name   => '_components',
106             search => [
107                 "$class\::Controller", "$class\::C",
108                 "$class\::Model",      "$class\::M",
109                 "$class\::View",       "$class\::V"
110             ],
111             callback => $callback
112         );
113     };
114
115     if ( my $error = $@ ) {
116
117         chomp $error;
118
119         Catalyst::Exception->throw( 
120             message => qq/Couldn't load components "$error"/ 
121         );
122     }
123
124     for my $component ( $class->_components($class) ) {
125         $class->components->{ ref $component || $component } = $component;
126     }
127 }
128
129 =item $c->setup_dispatcher
130
131 =cut
132
133 sub setup_dispatcher {
134     my ( $class, $dispatcher ) = @_;
135
136     if ( $dispatcher ) {
137         $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
138     }
139
140     if ( $ENV{CATALYST_DISPATCHER} ) {
141         $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
142     }
143
144     if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
145         $dispatcher = 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
146     }
147
148     unless ( $dispatcher ) {
149         $dispatcher = 'Catalyst::Dispatcher';
150     }
151
152     $dispatcher->require;
153
154     if ( $@ ) {
155         Catalyst::Exception->throw(
156             message => qq/Couldn't load dispatcher "$dispatcher", "$@"/
157         );
158     }
159
160     {
161         no strict 'refs';
162         push @{"$class\::ISA"}, $dispatcher;
163     }
164
165     $class->dispatcher($dispatcher);
166 }
167
168 =item $c->setup_engine
169
170 =cut
171
172 sub setup_engine {
173     my ( $class, $engine ) = @_;
174
175     if ( $engine ) {
176         $engine = 'Catalyst::Engine::' . $engine;
177     }
178
179     if ( $ENV{CATALYST_ENGINE} ) {
180         $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
181     }
182
183     if ( $ENV{ uc($class) . '_ENGINE' } ) {
184         $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
185     }
186
187     if ( ! $engine && $ENV{MOD_PERL} ) {
188
189         my ( $software, $version ) = $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
190
191         $version =~ s/_//g;
192         $version =~ s/(\.[^.]+)\./$1/g;
193
194         if ( $software eq 'mod_perl') {
195
196             if ( $version >= 1.99922 ) {
197
198                 $engine = 'Catalyst::Engine::Apache::MP20';
199
200                 if ( Apache2::Request->require ) {
201                     $engine = 'Catalyst::Engine::Apache::MP20::Apreq';
202                 }
203             }
204
205             elsif ( $version >= 1.9901 ) {
206
207                 $engine = 'Catalyst::Engine::Apache::MP19';
208
209                 if ( Apache::Request->require ) {
210                     $engine = 'Catalyst::Engine::Apache::MP19::Apreq';
211                 }
212             }
213
214             elsif ( $version >= 1.24 ) {
215
216                 $engine = 'Catalyst::Engine::Apache::MP13';
217
218                 if ( Apache::Request->require ) {
219                     $engine = 'Catalyst::Engine::Apache::MP13::Apreq';
220                 }
221             }
222
223             else {
224                 Catalyst::Exception->throw(
225                     message => qq/Unsupported mod_perl version: $ENV{MOD_PERL}/
226                 );
227             }
228         }
229
230         elsif ( $software eq 'Zeus-Perl' ) {
231             $engine = 'Catalyst::Engine::Zeus';
232         }
233
234         else {
235             Catalyst::Exception->throw(
236                 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/
237             );
238         }
239     }
240
241     unless ( $engine ) {
242         $engine = 'Catalyst::Engine::CGI';
243     }
244
245     $engine->require;
246
247     if ( $@ ) {
248         Catalyst::Exception->throw(
249             message => qq/Couldn't load engine "$engine", "$@"/
250         );
251     }
252
253     {
254         no strict 'refs';
255         push @{"$class\::ISA"}, $engine;
256     }
257
258     $class->engine($engine);
259 }
260
261 =item $c->setup_home
262
263 =cut
264
265 sub setup_home {
266     my ( $class, $home ) = @_;
267
268     if ( $ENV{CATALYST_HOME} ) {
269         $home = $ENV{CATALYST_HOME};
270     }
271
272     if ( $ENV{ uc($class) . '_HOME' } ) {
273         $home = $ENV{ uc($class) . '_HOME' };
274     }
275
276     unless ( $home ) {
277         $home = Catalyst::Utils::home($class);
278     }
279
280     if ( $home ) {
281         $class->config->{home} = $home;
282         $class->config->{root} = dir($home)->subdir('root');
283     }
284 }
285
286 =item $c->setup_log
287
288 =cut
289
290 sub setup_log {
291     my ( $class, $debug ) = @_;
292
293     unless ( $class->log ) {
294         $class->log( Catalyst::Log->new );
295     }
296
297     if ( $ENV{CATALYST_DEBUG} || $ENV{ uc($class) . '_DEBUG' } || $debug ) {
298         no strict 'refs';
299         *{"$class\::debug"} = sub { 1 };
300         $class->log->debug('Debug messages enabled');
301     }
302 }
303
304 =item $c->setup_plugins
305
306 =cut
307
308 sub setup_plugins {
309     my ( $class, $plugins ) = @_;
310
311     for my $plugin ( @$plugins ) {
312
313         $plugin = "Catalyst::Plugin::$plugin";
314
315         $plugin->require;
316
317         if ( $@ ) {
318             Catalyst::Exception->throw(
319                 message => qq/Couldn't load plugin "$plugin", "$@"/
320             );
321         }
322
323         {
324             no strict 'refs';
325             push @{"$class\::ISA"}, $plugin;
326         }
327     }
328 }
329
330 =back
331
332 =head1 AUTHOR
333
334 Sebastian Riedel, C<sri@cpan.org>
335 Christian Hansen, C<ch@ngmedia.com>
336
337 =head1 COPYRIGHT
338
339 This program is free software, you can redistribute it and/or modify 
340 it under the same terms as Perl itself.
341
342 =cut
343
344 1;