Add setup_finalize as an easy way to hook at the end of setup.
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
CommitLineData
fc7ec1d9 1package Catalyst;
2
a7caa492 3use Moose;
4extends 'Catalyst::Component';
fbcc39ad 5use bytes;
edb20ed3 6use Scope::Upper ();
a2f2cde9 7use Catalyst::Exception;
fc7ec1d9 8use Catalyst::Log;
fbcc39ad 9use Catalyst::Request;
10use Catalyst::Request::Upload;
11use Catalyst::Response;
812a28c9 12use Catalyst::Utils;
31375184 13use Catalyst::Controller;
364d7324 14use Devel::InnerPackage ();
8f62c91a 15use File::stat;
c50f595c 16use Module::Pluggable::Object ();
c50f595c 17use Text::SimpleTable ();
18use Path::Class::Dir ();
19use Path::Class::File ();
fbcc39ad 20use Time::HiRes qw/gettimeofday tv_interval/;
c50f595c 21use URI ();
933ba403 22use URI::http;
23use URI::https;
e7164f21 24use Scalar::Util qw/weaken/;
5513038d 25use Tree::Simple qw/use_weak_refs/;
26use Tree::Simple::Visitor::FindByUID;
261c571e 27use attributes;
5789a3d8 28use utf8;
108201b5 29use Carp qw/croak carp shortmess/;
fc7ec1d9 30
f63c03e4 31BEGIN { require 5.008001; }
32
8a440eba 33has stack => (is => 'ro', default => sub { [] });
6680c772 34has stash => (is => 'rw', default => sub { {} });
35has state => (is => 'rw', default => 0);
b6d4ee6e 36has stats => (is => 'rw');
37has action => (is => 'rw');
6680c772 38has counter => (is => 'rw', default => sub { {} });
39has request => (is => 'rw', default => sub { $_[0]->request_class->new({}) }, required => 1, lazy => 1);
40has response => (is => 'rw', default => sub { $_[0]->response_class->new({}) }, required => 1, lazy => 1);
e63bdf38 41has namespace => (is => 'rw');
42
8767c5a3 43sub depth { scalar @{ shift->stack || [] }; }
0fc2d522 44sub comp { shift->component(@_) }
6680c772 45
46sub req {
47 # carp "the use of req() is deprecated in favour of request()";
48 my $self = shift; return $self->request(@_);
49}
50sub res {
51 # carp "the use of res() is deprecated in favour of response()";
52 my $self = shift; return $self->response(@_);
53}
fbcc39ad 54
55# For backwards compatibility
0fc2d522 56sub finalize_output { shift->finalize_body(@_) };
fbcc39ad 57
58# For statistics
59our $COUNT = 1;
60our $START = time;
61our $RECURSION = 1000;
62our $DETACH = "catalyst_detach\n";
55424863 63our $GO = "catalyst_go\n";
fbcc39ad 64
b6d4ee6e 65#I imagine that very few of these really need to be class variables. if any.
66#maybe we should just make them attributes with a default?
fbcc39ad 67__PACKAGE__->mk_classdata($_)
3cec521a 68 for qw/components arguments dispatcher engine log dispatcher_class
ac5c933b 69 engine_class context_class request_class response_class stats_class
dc5f035e 70 setup_finished/;
cb0354c6 71
3cec521a 72__PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
73__PACKAGE__->engine_class('Catalyst::Engine::CGI');
74__PACKAGE__->request_class('Catalyst::Request');
75__PACKAGE__->response_class('Catalyst::Response');
dc5f035e 76__PACKAGE__->stats_class('Catalyst::Stats');
fbcc39ad 77
6415bb4d 78# Remember to update this in Catalyst::Runtime as well!
79
c905f6c0 80our $VERSION = '5.8000_05';
189e2a51 81
fbcc39ad 82sub import {
83 my ( $class, @arguments ) = @_;
84
85 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
86 # callers @ISA.
87 return unless $class eq 'Catalyst';
88
84ff88cf 89 my $caller = caller();
90 return if $caller eq 'main';
91 my $meta = Moose::Meta::Class->initialize($caller);
92 #Moose->import({ into => $caller }); #do we want to do this?
fbcc39ad 93
94 unless ( $caller->isa('Catalyst') ) {
84ff88cf 95 my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
96 $meta->superclasses(@superclasses);
97 }
98 unless( $meta->has_method('meta') ){
99 $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
fbcc39ad 100 }
101
102 $caller->arguments( [@arguments] );
103 $caller->setup_home;
104}
fc7ec1d9 105
106=head1 NAME
107
108Catalyst - The Elegant MVC Web Application Framework
109
110=head1 SYNOPSIS
111
e7ad3b81 112See the L<Catalyst::Manual> distribution for comprehensive
113documentation and tutorials.
114
86418559 115 # Install Catalyst::Devel for helpers and other development tools
b4b01a8a 116 # use the helper to create a new application
91864987 117 catalyst.pl MyApp
fc7ec1d9 118
119 # add models, views, controllers
2f381252 120 script/myapp_create.pl model MyDatabase DBIC::Schema create=static dbi:SQLite:/path/to/db
cc95842f 121 script/myapp_create.pl view MyTemplate TT
0ef52a96 122 script/myapp_create.pl controller Search
fc7ec1d9 123
e7f1cf73 124 # built in testserver -- use -r to restart automatically on changes
cc95842f 125 # --help to see all available options
ae4e40a7 126 script/myapp_server.pl
fc7ec1d9 127
0ef52a96 128 # command line testing interface
ae4e40a7 129 script/myapp_test.pl /yada
fc7ec1d9 130
b4b01a8a 131 ### in lib/MyApp.pm
0ef52a96 132 use Catalyst qw/-Debug/; # include plugins here as well
ac5c933b 133
85d9fce6 134 ### In lib/MyApp/Controller/Root.pm (autocreated)
0ef52a96 135 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
ae1e6b59 136 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
137 $c->stash->{template} = 'foo.tt'; # set the template
0ef52a96 138 # lookup something from db -- stash vars are passed to TT
ac5c933b 139 $c->stash->{data} =
b4b01a8a 140 $c->model('Database::Foo')->search( { country => $args[0] } );
0ef52a96 141 if ( $c->req->params->{bar} ) { # access GET or POST parameters
142 $c->forward( 'bar' ); # process another action
ac5c933b 143 # do something else after forward returns
0ef52a96 144 }
145 }
ac5c933b 146
ae1e6b59 147 # The foo.tt TT template can use the stash data from the database
0ef52a96 148 [% WHILE (item = data.next) %]
149 [% item.foo %]
150 [% END %]
ac5c933b 151
0ef52a96 152 # called for /bar/of/soap, /bar/of/soap/10, etc.
153 sub bar : Path('/bar/of/soap') { ... }
fc7ec1d9 154
ae1e6b59 155 # called for all actions, from the top-most controller downwards
ac5c933b 156 sub auto : Private {
0ef52a96 157 my ( $self, $c ) = @_;
b4b01a8a 158 if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication
0ef52a96 159 $c->res->redirect( '/login' ); # require login
160 return 0; # abort request and go immediately to end()
161 }
ae1e6b59 162 return 1; # success; carry on to next action
0ef52a96 163 }
ac5c933b 164
ae1e6b59 165 # called after all actions are finished
ac5c933b 166 sub end : Private {
5a8ed4fe 167 my ( $self, $c ) = @_;
0ef52a96 168 if ( scalar @{ $c->error } ) { ... } # handle errors
169 return if $c->res->body; # already have a response
170 $c->forward( 'MyApp::View::TT' ); # render template
5a8ed4fe 171 }
172
0ef52a96 173 ### in MyApp/Controller/Foo.pm
174 # called for /foo/bar
175 sub bar : Local { ... }
ac5c933b 176
5400c668 177 # called for /blargle
178 sub blargle : Global { ... }
ac5c933b 179
5400c668 180 # an index action matches /foo, but not /foo/1, etc.
181 sub index : Private { ... }
ac5c933b 182
0ef52a96 183 ### in MyApp/Controller/Foo/Bar.pm
184 # called for /foo/bar/baz
185 sub baz : Local { ... }
ac5c933b 186
b4b01a8a 187 # first Root auto is called, then Foo auto, then this
0ef52a96 188 sub auto : Private { ... }
ac5c933b 189
0ef52a96 190 # powerful regular expression paths are also possible
191 sub details : Regex('^product/(\w+)/details$') {
5a8ed4fe 192 my ( $self, $c ) = @_;
0ef52a96 193 # extract the (\w+) from the URI
2982e768 194 my $product = $c->req->captures->[0];
5a8ed4fe 195 }
fc7ec1d9 196
0ef52a96 197See L<Catalyst::Manual::Intro> for additional information.
3803e98f 198
fc7ec1d9 199=head1 DESCRIPTION
200
86418559 201Catalyst is a modern framework for making web applications without the
202pain usually associated with this process. This document is a reference
203to the main Catalyst application. If you are a new user, we suggest you
204start with L<Catalyst::Manual::Tutorial> or L<Catalyst::Manual::Intro>.
fc7ec1d9 205
206See L<Catalyst::Manual> for more documentation.
207
ae1e6b59 208Catalyst plugins can be loaded by naming them as arguments to the "use
209Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
210plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
211C<My::Module>.
fc7ec1d9 212
0ef52a96 213 use Catalyst qw/My::Module/;
fc7ec1d9 214
836e1134 215If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
216fully qualify the name by using a unary plus:
217
218 use Catalyst qw/
219 My::Module
220 +Fully::Qualified::Plugin::Name
221 /;
222
ae1e6b59 223Special flags like C<-Debug> and C<-Engine> can also be specified as
224arguments when Catalyst is loaded:
fc7ec1d9 225
226 use Catalyst qw/-Debug My::Module/;
227
ae1e6b59 228The position of plugins and flags in the chain is important, because
86418559 229they are loaded in the order in which they appear.
fc7ec1d9 230
23f9d934 231The following flags are supported:
232
b5ecfcf0 233=head2 -Debug
23f9d934 234
f8ad6ea5 235Enables debug output. You can also force this setting from the system
86418559 236environment with CATALYST_DEBUG or <MYAPP>_DEBUG. The environment
237settings override the application, with <MYAPP>_DEBUG having the highest
238priority.
fc7ec1d9 239
b5ecfcf0 240=head2 -Engine
fc7ec1d9 241
ae1e6b59 242Forces Catalyst to use a specific engine. Omit the
243C<Catalyst::Engine::> prefix of the engine name, i.e.:
fc7ec1d9 244
0ef52a96 245 use Catalyst qw/-Engine=CGI/;
fc7ec1d9 246
b5ecfcf0 247=head2 -Home
fbcc39ad 248
ae1e6b59 249Forces Catalyst to use a specific home directory, e.g.:
250
86418559 251 use Catalyst qw[-Home=/usr/mst];
fbcc39ad 252
cc95842f 253This can also be done in the shell environment by setting either the
254C<CATALYST_HOME> environment variable or C<MYAPP_HOME>; where C<MYAPP>
255is replaced with the uppercased name of your application, any "::" in
256the name will be replaced with underscores, e.g. MyApp::Web should use
257MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
258
b5ecfcf0 259=head2 -Log
fbcc39ad 260
0fa676a7 261 use Catalyst '-Log=warn,fatal,error';
262
263Specifies a comma-delimited list of log levels.
fbcc39ad 264
dc5f035e 265=head2 -Stats
266
267Enables statistics collection and reporting. You can also force this setting
268from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
269environment settings override the application, with <MYAPP>_STATS having the
270highest priority.
271
ac5c933b 272e.g.
dc5f035e 273
274 use Catalyst qw/-Stats=1/
275
23f9d934 276=head1 METHODS
277
f7b672ef 278=head2 INFORMATION ABOUT THE CURRENT REQUEST
0ef52a96 279
b5ecfcf0 280=head2 $c->action
66e28e3f 281
ae1e6b59 282Returns a L<Catalyst::Action> object for the current action, which
283stringifies to the action name. See L<Catalyst::Action>.
0ef52a96 284
b5ecfcf0 285=head2 $c->namespace
0ef52a96 286
86418559 287Returns the namespace of the current action, i.e., the URI prefix
ae1e6b59 288corresponding to the controller of the current action. For example:
289
290 # in Controller::Foo::Bar
291 $c->namespace; # returns 'foo/bar';
0ef52a96 292
b5ecfcf0 293=head2 $c->request
0ef52a96 294
b5ecfcf0 295=head2 $c->req
0ef52a96 296
86418559 297Returns the current L<Catalyst::Request> object, giving access to
298information about the current client request (including parameters,
299cookies, HTTP headers, etc.). See L<Catalyst::Request>.
0ef52a96 300
b4b01a8a 301=head2 REQUEST FLOW HANDLING
0ef52a96 302
b5ecfcf0 303=head2 $c->forward( $action [, \@arguments ] )
0ef52a96 304
b5ecfcf0 305=head2 $c->forward( $class, $method, [, \@arguments ] )
0ef52a96 306
86418559 307Forwards processing to another action, by its private name. If you give a
b4b01a8a 308class name but no method, C<process()> is called. You may also optionally
309pass arguments in an arrayref. The action will receive the arguments in
cc95842f 310C<@_> and C<< $c->req->args >>. Upon returning from the function,
311C<< $c->req->args >> will be restored to the previous values.
0ef52a96 312
3b984c64 313Any data C<return>ed from the action forwarded to, will be returned by the
d759db1e 314call to forward.
3b984c64 315
316 my $foodata = $c->forward('/foo');
0ef52a96 317 $c->forward('index');
e112461a 318 $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/);
0ef52a96 319 $c->forward('MyApp::View::TT');
320
86418559 321Note that forward implies an C<<eval { }>> around the call (actually
322C<execute> does), thus de-fatalizing all 'dies' within the called
323action. If you want C<die> to propagate you need to do something like:
f3e6a8c0 324
325 $c->forward('foo');
326 die $c->error if $c->error;
327
86418559 328Or make sure to always return true values from your actions and write
329your code like this:
f3e6a8c0 330
331 $c->forward('foo') || return;
332
0ef52a96 333=cut
334
6680c772 335sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $c, @_ ) }
0ef52a96 336
b5ecfcf0 337=head2 $c->detach( $action [, \@arguments ] )
0ef52a96 338
b5ecfcf0 339=head2 $c->detach( $class, $method, [, \@arguments ] )
0ef52a96 340
264bac8c 341=head2 $c->detach()
342
ac5c933b 343The same as C<forward>, but doesn't return to the previous action when
344processing is finished.
0ef52a96 345
264bac8c 346When called with no arguments it escapes the processing chain entirely.
347
0ef52a96 348=cut
349
350sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
351
ae0e35ee 352=head2 $c->visit( $action [, \@arguments ] )
353
354=head2 $c->visit( $class, $method, [, \@arguments ] )
355
356Almost the same as C<forward>, but does a full dispatch, instead of just
357calling the new C<$action> / C<$class-E<gt>$method>. This means that C<begin>,
358C<auto> and the method you go to are called, just like a new request.
359
360C<$c-E<gt>stash> is kept unchanged.
361
362In effect, C<visit> allows you to "wrap" another action, just as it
363would have been called by dispatching from a URL, while the analogous
364C<go> allows you to transfer control to another action as if it had
365been reached directly from a URL.
366
367=cut
368
369sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) }
370
2f381252 371=head2 $c->go( $action [, \@arguments ] )
372
373=head2 $c->go( $class, $method, [, \@arguments ] )
374
ae0e35ee 375Almost the same as C<detach>, but does a full dispatch like C<visit>,
376instead of just calling the new C<$action> /
377C<$class-E<gt>$method>. This means that C<begin>, C<auto> and the
378method you visit are called, just like a new request.
2f381252 379
380C<$c-E<gt>stash> is kept unchanged.
381
382=cut
383
384sub go { my $c = shift; $c->dispatcher->go( $c, @_ ) }
385
b4b01a8a 386=head2 $c->response
387
388=head2 $c->res
389
cc95842f 390Returns the current L<Catalyst::Response> object, see there for details.
b4b01a8a 391
392=head2 $c->stash
393
394Returns a hashref to the stash, which may be used to store data and pass
395it between components during a request. You can also set hash keys by
396passing arguments. The stash is automatically sent to the view. The
397stash is cleared at the end of a request; it cannot be used for
86418559 398persistent storage (for this you must use a session; see
399L<Catalyst::Plugin::Session> for a complete system integrated with
400Catalyst).
b4b01a8a 401
402 $c->stash->{foo} = $bar;
403 $c->stash( { moose => 'majestic', qux => 0 } );
404 $c->stash( bar => 1, gorch => 2 ); # equivalent to passing a hashref
ac5c933b 405
b4b01a8a 406 # stash is automatically passed to the view for use in a template
cc95842f 407 $c->forward( 'MyApp::View::TT' );
b4b01a8a 408
409=cut
410
4090e3bb 411around stash => sub {
412 my $orig = shift;
b4b01a8a 413 my $c = shift;
4090e3bb 414 my $stash = $orig->($c);
b4b01a8a 415 if (@_) {
4090e3bb 416 my $new_stash = @_ > 1 ? {@_} : $_[0];
417 croak('stash takes a hash or hashref') unless ref $new_stash;
418 foreach my $key ( keys %$new_stash ) {
419 $stash->{$key} = $new_stash->{$key};
b4b01a8a 420 }
421 }
0fc2d522 422
4090e3bb 423 return $stash;
424};
0fc2d522 425
b4b01a8a 426
b5ecfcf0 427=head2 $c->error
0ef52a96 428
b5ecfcf0 429=head2 $c->error($error, ...)
0ef52a96 430
b5ecfcf0 431=head2 $c->error($arrayref)
0ef52a96 432
83a8fcac 433Returns an arrayref containing error messages. If Catalyst encounters an
434error while processing a request, it stores the error in $c->error. This
e7ad3b81 435method should only be used to store fatal error messages.
0ef52a96 436
437 my @error = @{ $c->error };
438
439Add a new error.
440
441 $c->error('Something bad happened');
442
0ef52a96 443=cut
444
445sub error {
446 my $c = shift;
447 if ( $_[0] ) {
448 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
9ce44430 449 croak @$error unless ref $c;
0ef52a96 450 push @{ $c->{error} }, @$error;
451 }
452 elsif ( defined $_[0] ) { $c->{error} = undef }
453 return $c->{error} || [];
454}
455
b4b01a8a 456
457=head2 $c->state
458
459Contains the return value of the last executed action.
460
ca81eb67 461=head2 $c->clear_errors
462
463Clear errors. You probably don't want to clear the errors unless you are
464implementing a custom error screen.
465
466This is equivalent to running
467
468 $c->error(0);
469
470=cut
471
472sub clear_errors {
473 my $c = shift;
474 $c->error(0);
475}
476
2f381252 477# search components given a name and some prefixes
478sub _comp_search_prefixes {
479 my ( $c, $name, @prefixes ) = @_;
480 my $appclass = ref $c || $c;
481 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
0ef52a96 482
2f381252 483 # map the original component name to the sub part that we will search against
484 my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; }
485 grep { /$filter/ } keys %{ $c->components };
0756fe3b 486
2f381252 487 # undef for a name will return all
488 return keys %eligible if !defined $name;
0756fe3b 489
2f381252 490 my $query = ref $name ? $name : qr/^$name$/i;
491 my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
0756fe3b 492
2f381252 493 return map { $c->components->{ $_ } } @result if @result;
0756fe3b 494
2f381252 495 # if we were given a regexp to search against, we're done.
496 return if ref $name;
0756fe3b 497
2f381252 498 # regexp fallback
499 $query = qr/$name/i;
500 @result = map { $c->components->{ $_ } } grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
0756fe3b 501
2f381252 502 # no results? try against full names
503 if( !@result ) {
504 @result = map { $c->components->{ $_ } } grep { m{$query} } keys %eligible;
505 }
0756fe3b 506
2f381252 507 # don't warn if we didn't find any results, it just might not exist
508 if( @result ) {
108201b5 509 my $msg = "Used regexp fallback for \$c->model('${name}'), which found '" .
510 (join '", "', @result) . "'. Relying on regexp fallback behavior for " .
511 "component resolution is unreliable and unsafe.";
512 my $short = $result[0];
513 $short =~ s/.*?Model:://;
514 my $shortmess = Carp::shortmess('');
515 if ($shortmess =~ m#Catalyst/Plugin#) {
516 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
517 "plugin's config";
518 } elsif ($shortmess =~ m#Catalyst/lib/(View|Controller)#) {
519 $msg .= " You probably need to set '$short' instead of '${name}' in this " .
520 "component's config";
521 } else {
522 $msg .= " You probably meant \$c->model('$short') instead of \$c->model{'${name}'}, " .
523 "but if you really wanted to search, pass in a regexp as the argument " .
524 "like so: \$c->model(qr/${name}/)";
525 }
526 $c->log->warn( "${msg}$shortmess" );
2f381252 527 }
0756fe3b 528
2f381252 529 return @result;
0756fe3b 530}
531
ac5c933b 532# Find possible names for a prefix
3b88a455 533sub _comp_names {
534 my ( $c, @prefixes ) = @_;
3b88a455 535 my $appclass = ref $c || $c;
536
2f381252 537 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
3b88a455 538
2f381252 539 my @names = map { s{$filter}{}; $_; } $c->_comp_search_prefixes( undef, @prefixes );
3b88a455 540 return @names;
541}
542
197bd788 543# Filter a component before returning by calling ACCEPT_CONTEXT if available
544sub _filter_component {
545 my ( $c, $comp, @args ) = @_;
2f381252 546
8abaac85 547 if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
197bd788 548 return $comp->ACCEPT_CONTEXT( $c, @args );
549 }
2f381252 550
551 return $comp;
197bd788 552}
553
f7b672ef 554=head2 COMPONENT ACCESSORS
0ef52a96 555
b5ecfcf0 556=head2 $c->controller($name)
af3ff00e 557
0ef52a96 558Gets a L<Catalyst::Controller> instance by name.
af3ff00e 559
560 $c->controller('Foo')->do_stuff;
561
86418559 562If the name is omitted, will return the controller for the dispatched
563action.
649fd1fa 564
2f381252 565If you want to search for controllers, pass in a regexp as the argument.
566
567 # find all controllers that start with Foo
568 my @foo_controllers = $c->controller(qr{^Foo});
569
570
af3ff00e 571=cut
572
573sub controller {
197bd788 574 my ( $c, $name, @args ) = @_;
2f381252 575
576 if( $name ) {
577 my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ );
578 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
579 return $c->_filter_component( $result[ 0 ], @args );
580 }
581
197bd788 582 return $c->component( $c->action->class );
af3ff00e 583}
584
b5ecfcf0 585=head2 $c->model($name)
fc7ec1d9 586
0ef52a96 587Gets a L<Catalyst::Model> instance by name.
588
589 $c->model('Foo')->do_stuff;
fc7ec1d9 590
72f87c4b 591Any extra arguments are directly passed to ACCEPT_CONTEXT.
592
ac5c933b 593If the name is omitted, it will look for
2f381252 594 - a model object in $c->stash->{current_model_instance}, then
a3b71f0f 595 - a model name in $c->stash->{current_model}, then
596 - a config setting 'default_model', or
597 - check if there is only one model, and return it if that's the case.
649fd1fa 598
2f381252 599If you want to search for models, pass in a regexp as the argument.
600
601 # find all models that start with Foo
602 my @foo_models = $c->model(qr{^Foo});
603
fc7ec1d9 604=cut
605
0ef52a96 606sub model {
197bd788 607 my ( $c, $name, @args ) = @_;
2f381252 608
609 if( $name ) {
610 my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
611 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
612 return $c->_filter_component( $result[ 0 ], @args );
613 }
614
a3b71f0f 615 if (ref $c) {
ac5c933b 616 return $c->stash->{current_model_instance}
a3b71f0f 617 if $c->stash->{current_model_instance};
618 return $c->model( $c->stash->{current_model} )
619 if $c->stash->{current_model};
a3b71f0f 620 }
72f87c4b 621 return $c->model( $c->config->{default_model} )
622 if $c->config->{default_model};
3b88a455 623
2f381252 624 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
3b88a455 625
2f381252 626 if( $rest ) {
108201b5 627 $c->log->warn( Carp::shortmess('Calling $c->model() will return a random model unless you specify one of:') );
2f381252 628 $c->log->warn( '* $c->config->{default_model} # the name of the default model to use' );
629 $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
630 $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
11c270bd 631 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
2f381252 632 }
3b88a455 633
2f381252 634 return $c->_filter_component( $comp );
3b88a455 635}
636
b4b01a8a 637
b5ecfcf0 638=head2 $c->view($name)
0ef52a96 639
640Gets a L<Catalyst::View> instance by name.
fc7ec1d9 641
0ef52a96 642 $c->view('Foo')->do_stuff;
fc7ec1d9 643
72f87c4b 644Any extra arguments are directly passed to ACCEPT_CONTEXT.
645
ac5c933b 646If the name is omitted, it will look for
2f381252 647 - a view object in $c->stash->{current_view_instance}, then
a3b71f0f 648 - a view name in $c->stash->{current_view}, then
649 - a config setting 'default_view', or
650 - check if there is only one view, and return it if that's the case.
649fd1fa 651
2f381252 652If you want to search for views, pass in a regexp as the argument.
653
654 # find all views that start with Foo
655 my @foo_views = $c->view(qr{^Foo});
656
fc7ec1d9 657=cut
658
0ef52a96 659sub view {
197bd788 660 my ( $c, $name, @args ) = @_;
2f381252 661
662 if( $name ) {
663 my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
664 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
665 return $c->_filter_component( $result[ 0 ], @args );
666 }
667
a3b71f0f 668 if (ref $c) {
ac5c933b 669 return $c->stash->{current_view_instance}
a3b71f0f 670 if $c->stash->{current_view_instance};
671 return $c->view( $c->stash->{current_view} )
672 if $c->stash->{current_view};
a3b71f0f 673 }
72f87c4b 674 return $c->view( $c->config->{default_view} )
675 if $c->config->{default_view};
2f381252 676
677 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
678
679 if( $rest ) {
680 $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
681 $c->log->warn( '* $c->config->{default_view} # the name of the default view to use' );
682 $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
683 $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
11c270bd 684 $c->log->warn( 'NB: in version 5.81, the "random" behavior will not work at all.' );
2f381252 685 }
686
687 return $c->_filter_component( $comp );
688}
689
690=head2 $c->controllers
691
692Returns the available names which can be passed to $c->controller
693
694=cut
695
696sub controllers {
697 my ( $c ) = @_;
698 return $c->_comp_names(qw/Controller C/);
0ef52a96 699}
fbcc39ad 700
b4b01a8a 701=head2 $c->models
702
703Returns the available names which can be passed to $c->model
704
705=cut
706
707sub models {
708 my ( $c ) = @_;
709 return $c->_comp_names(qw/Model M/);
710}
711
712
3b88a455 713=head2 $c->views
714
715Returns the available names which can be passed to $c->view
716
717=cut
718
719sub views {
720 my ( $c ) = @_;
721 return $c->_comp_names(qw/View V/);
722}
723
b4b01a8a 724=head2 $c->comp($name)
725
726=head2 $c->component($name)
727
cc95842f 728Gets a component object by name. This method is not recommended,
b4b01a8a 729unless you want to get a specific component by full
cc95842f 730class. C<< $c->controller >>, C<< $c->model >>, and C<< $c->view >>
b4b01a8a 731should be used instead.
732
2f381252 733If C<$name> is a regexp, a list of components matched against the full
734component name will be returned.
735
b4b01a8a 736=cut
737
738sub component {
2f381252 739 my ( $c, $name, @args ) = @_;
b4b01a8a 740
2f381252 741 if( $name ) {
742 my $comps = $c->components;
b4b01a8a 743
2f381252 744 if( !ref $name ) {
745 # is it the exact name?
746 return $c->_filter_component( $comps->{ $name }, @args )
747 if exists $comps->{ $name };
b4b01a8a 748
2f381252 749 # perhaps we just omitted "MyApp"?
750 my $composed = ( ref $c || $c ) . "::${name}";
751 return $c->_filter_component( $comps->{ $composed }, @args )
752 if exists $comps->{ $composed };
b4b01a8a 753
2f381252 754 # search all of the models, views and controllers
755 my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
756 return $c->_filter_component( $comp, @args ) if $comp;
757 }
758
759 # This is here so $c->comp( '::M::' ) works
760 my $query = ref $name ? $name : qr{$name}i;
b4b01a8a 761
2f381252 762 my @result = grep { m{$query} } keys %{ $c->components };
763 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
b4b01a8a 764
2f381252 765 if( $result[ 0 ] ) {
108201b5 766 $c->log->warn( Carp::shortmess(qq(Found results for "${name}" using regexp fallback)) );
2f381252 767 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
768 $c->log->warn( 'is unreliable and unsafe. You have been warned' );
769 return $c->_filter_component( $result[ 0 ], @args );
770 }
771
772 # I would expect to return an empty list here, but that breaks back-compat
b4b01a8a 773 }
774
2f381252 775 # fallback
b4b01a8a 776 return sort keys %{ $c->components };
777}
778
b4b01a8a 779=head2 CLASS DATA AND HELPER CLASSES
fbcc39ad 780
b5ecfcf0 781=head2 $c->config
fbcc39ad 782
0ef52a96 783Returns or takes a hashref containing the application's configuration.
784
61b1d329 785 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
81557adf 786
cc95842f 787You can also use a C<YAML>, C<XML> or C<Config::General> config file
788like myapp.yml in your applications home directory. See
789L<Catalyst::Plugin::ConfigLoader>.
a6ad13b6 790
791 ---
792 db: dsn:SQLite:foo.db
793
b4b01a8a 794
3643e890 795=cut
796
4090e3bb 797around config => sub {
798 my $orig = shift;
3643e890 799 my $c = shift;
800
801 $c->log->warn("Setting config after setup has been run is not a good idea.")
802 if ( @_ and $c->setup_finished );
803
4090e3bb 804 $c->$orig(@_);
805};
3643e890 806
b5ecfcf0 807=head2 $c->log
0ef52a96 808
86418559 809Returns the logging object instance. Unless it is already set, Catalyst
810sets this up with a L<Catalyst::Log> object. To use your own log class,
811set the logger with the C<< __PACKAGE__->log >> method prior to calling
9e7673af 812C<< __PACKAGE__->setup >>.
813
814 __PACKAGE__->log( MyLogger->new );
815 __PACKAGE__->setup;
816
817And later:
0ef52a96 818
ae1e6b59 819 $c->log->info( 'Now logging with my own logger!' );
0ef52a96 820
86418559 821Your log class should implement the methods described in
822L<Catalyst::Log>.
af3ff00e 823
b4b01a8a 824
825=head2 $c->debug
826
827Overload to enable debug messages (same as -Debug option).
828
e80e8542 829Note that this is a static method, not an accessor and should be overloaded
830by declaring "sub debug { 1 }" in your MyApp.pm, not by calling $c->debug(1).
831
af3ff00e 832=cut
833
b4b01a8a 834sub debug { 0 }
835
836=head2 $c->dispatcher
837
838Returns the dispatcher instance. Stringifies to class name. See
839L<Catalyst::Dispatcher>.
840
841=head2 $c->engine
842
843Returns the engine instance. Stringifies to the class name. See
844L<Catalyst::Engine>.
845
846
f7b672ef 847=head2 UTILITY METHODS
66e28e3f 848
b5ecfcf0 849=head2 $c->path_to(@path)
01033d73 850
cc95842f 851Merges C<@path> with C<< $c->config->{home} >> and returns a
afbb9aa3 852L<Path::Class::Dir> object.
01033d73 853
854For example:
855
856 $c->path_to( 'db', 'sqlite.db' );
857
858=cut
859
860sub path_to {
861 my ( $c, @path ) = @_;
a738ab68 862 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
01033d73 863 if ( -d $path ) { return $path }
a738ab68 864 else { return Path::Class::File->new( $c->config->{home}, @path ) }
01033d73 865}
866
b5ecfcf0 867=head2 $c->plugin( $name, $class, @args )
0ef52a96 868
ae1e6b59 869Helper method for plugins. It creates a classdata accessor/mutator and
870loads and instantiates the given class.
0ef52a96 871
872 MyApp->plugin( 'prototype', 'HTML::Prototype' );
873
874 $c->prototype->define_javascript_functions;
6b2a933b 875
876B<Note:> This method of adding plugins is deprecated. The ability
877to add plugins like this B<will be removed> in a Catalyst 5.9.
878Please do not use this functionality in new code.
0ef52a96 879
880=cut
881
882sub plugin {
883 my ( $class, $name, $plugin, @args ) = @_;
6b2a933b 884
885 # See block comment in t/unit_core_plugin.t
886 $class->log->debug(qq/Adding plugin using the ->plugin method is deprecated, and will be removed in Catalyst 5.9/);
887
97b58e17 888 $class->_register_plugin( $plugin, 1 );
0ef52a96 889
890 eval { $plugin->import };
891 $class->mk_classdata($name);
892 my $obj;
893 eval { $obj = $plugin->new(@args) };
894
895 if ($@) {
896 Catalyst::Exception->throw( message =>
897 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
898 }
899
900 $class->$name($obj);
901 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
902 if $class->debug;
903}
904
b5ecfcf0 905=head2 MyApp->setup
fbcc39ad 906
e7f1cf73 907Initializes the dispatcher and engine, loads any plugins, and loads the
ae1e6b59 908model, view, and controller components. You may also specify an array
909of plugins to load here, if you choose to not load them in the C<use
910Catalyst> line.
fbcc39ad 911
0ef52a96 912 MyApp->setup;
913 MyApp->setup( qw/-Debug/ );
fbcc39ad 914
915=cut
916
917sub setup {
0319a12c 918 my ( $class, @arguments ) = @_;
5168a5fc 919 $class->log->warn("Running setup twice is not a good idea.")
920 if ( $class->setup_finished );
921
fbcc39ad 922 unless ( $class->isa('Catalyst') ) {
953b0e15 923
fbcc39ad 924 Catalyst::Exception->throw(
925 message => qq/'$class' does not inherit from Catalyst/ );
1c99e125 926 }
0319a12c 927
fbcc39ad 928 if ( $class->arguments ) {
929 @arguments = ( @arguments, @{ $class->arguments } );
930 }
931
932 # Process options
933 my $flags = {};
934
935 foreach (@arguments) {
936
937 if (/^-Debug$/) {
938 $flags->{log} =
939 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
940 }
941 elsif (/^-(\w+)=?(.*)$/) {
942 $flags->{ lc $1 } = $2;
943 }
944 else {
945 push @{ $flags->{plugins} }, $_;
946 }
947 }
948
99f187d6 949 $class->setup_home( delete $flags->{home} );
950
fbcc39ad 951 $class->setup_log( delete $flags->{log} );
952 $class->setup_plugins( delete $flags->{plugins} );
953 $class->setup_dispatcher( delete $flags->{dispatcher} );
954 $class->setup_engine( delete $flags->{engine} );
dc5f035e 955 $class->setup_stats( delete $flags->{stats} );
fbcc39ad 956
957 for my $flag ( sort keys %{$flags} ) {
958
959 if ( my $code = $class->can( 'setup_' . $flag ) ) {
960 &$code( $class, delete $flags->{$flag} );
961 }
962 else {
963 $class->log->warn(qq/Unknown flag "$flag"/);
964 }
965 }
966
0eb4af72 967 eval { require Catalyst::Devel; };
968 if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
969 $class->log->warn(<<"EOF");
4ff0d824 970You are running an old script!
971
34a83d89 972 Please update by running (this will overwrite existing files):
973 catalyst.pl -force -scripts $class
974
975 or (this will not overwrite existing files):
976 catalyst.pl -scripts $class
1cf0345b 977
4ff0d824 978EOF
0eb4af72 979 }
ac5c933b 980
fbcc39ad 981 if ( $class->debug ) {
6601f2ad 982 my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins;
fbcc39ad 983
984 if (@plugins) {
34d28dfd 985 my $t = Text::SimpleTable->new(74);
8c113188 986 $t->row($_) for @plugins;
1cf0345b 987 $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
fbcc39ad 988 }
989
990 my $dispatcher = $class->dispatcher;
991 my $engine = $class->engine;
992 my $home = $class->config->{home};
993
01ce7075 994 $class->log->debug(sprintf(q/Loaded dispatcher "%s"/, blessed($dispatcher)));
995 $class->log->debug(sprintf(q/Loaded engine "%s"/, blessed($engine)));
fbcc39ad 996
997 $home
998 ? ( -d $home )
999 ? $class->log->debug(qq/Found home "$home"/)
1000 : $class->log->debug(qq/Home "$home" doesn't exist/)
1001 : $class->log->debug(q/Couldn't find home/);
1002 }
1003
54f4bfef 1004 # Call plugins setup, this is stupid and evil.
fbcc39ad 1005 {
1006 no warnings qw/redefine/;
1007 local *setup = sub { };
1008 $class->setup;
1009 }
1010
1011 # Initialize our data structure
1012 $class->components( {} );
1013
1014 $class->setup_components;
1015
1016 if ( $class->debug ) {
34d28dfd 1017 my $t = Text::SimpleTable->new( [ 63, 'Class' ], [ 8, 'Type' ] );
684d10ed 1018 for my $comp ( sort keys %{ $class->components } ) {
1019 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
1020 $t->row( $comp, $type );
1021 }
1cf0345b 1022 $class->log->debug( "Loaded components:\n" . $t->draw . "\n" )
8c113188 1023 if ( keys %{ $class->components } );
fbcc39ad 1024 }
1025
1026 # Add our self to components, since we are also a component
96d8d513 1027 if( $class->isa('Catalyst::Controller') ){
1028 $class->components->{$class} = $class;
1029 }
fbcc39ad 1030
1031 $class->setup_actions;
1032
1033 if ( $class->debug ) {
1034 my $name = $class->config->{name} || 'Application';
1035 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
1036 }
1037 $class->log->_flush() if $class->log->can('_flush');
3643e890 1038
3d041c32 1039 # Make sure that the application class becomes immutable at this point,
1040 # which ensures that it gets an inlined constructor. This means that it
1041 # works even if the user has added a plugin which contains a new method.
1042 # Note however that we have to do the work on scope end, so that method
1043 # modifiers work correctly in MyApp (as you have to call setup _before_
1044 # applying modifiers).
edb20ed3 1045 Scope::Upper::reap(sub {
e106a59f 1046 my $meta = Class::MOP::get_metaclass_by_name($class);
3d041c32 1047 $meta->make_immutable unless $meta->is_immutable;
d134bcca 1048 }, Scope::Upper::SCOPE(1));
3d041c32 1049
a5d07d29 1050 $class->setup_finalize;
1051}
1052
1053sub setup_finalize {
1054 my ($class) = @_;
3643e890 1055 $class->setup_finished(1);
fbcc39ad 1056}
1057
8a27f860 1058=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? )
1059
73664287 1060=head2 $c->uri_for( $path, @args?, \%query_values? )
fbcc39ad 1061
8a27f860 1062=over
fbcc39ad 1063
8a27f860 1064=item $action
8dc69021 1065
8a27f860 1066A Catalyst::Action object representing the Catalyst action you want to
1067create a URI for. To get one for an action in the current controller,
1068use C<< $c->action('someactionname') >>. To get one from different
1069controller, fetch the controller using C<< $c->controller() >>, then
1070call C<action_for> on it.
ea0e58d9 1071
9df7c5d9 1072You can maintain the arguments captured by an action (e.g.: Regex, Chained)
1073using C<< $c->req->captures >>.
1074
1075 # For the current action
1076 $c->uri_for($c->action, $c->req->captures);
1077
1078 # For the Foo action in the Bar controller
1079 $c->uri_for($c->controller->('Bar')->action_for('Foo'), $c->req->captures);
1080
d5e3d528 1081=back
1082
4cf1dd00 1083=cut
1084
fbcc39ad 1085sub uri_for {
00e6a2b7 1086 my ( $c, $path, @args ) = @_;
00e6a2b7 1087
ea0e58d9 1088 if ( Scalar::Util::blessed($path) ) { # action object
1089 my $captures = ( scalar @args && ref $args[0] eq 'ARRAY'
1090 ? shift(@args)
1091 : [] );
1092 $path = $c->dispatcher->uri_for_action($path, $captures);
1093 return undef unless defined($path);
81e75875 1094 $path = '/' if $path eq '';
ea0e58d9 1095 }
1096
51674a63 1097 undef($path) if (defined $path && $path eq '');
00e6a2b7 1098
97b58e17 1099 my $params =
1100 ( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
8327e2e2 1101
cbb93105 1102 carp "uri_for called with undef argument" if grep { ! defined $_ } @args;
51674a63 1103 s/([^$URI::uric])/$URI::Escape::escapes{$1}/go for @args;
1104
1105 unshift(@args, $path);
1106
1107 unless (defined $path && $path =~ s!^/!!) { # in-place strip
1108 my $namespace = $c->namespace;
1109 if (defined $path) { # cheesy hack to handle path '../foo'
1110 $namespace =~ s{(?:^|/)[^/]+$}{} while $args[0] =~ s{^\.\./}{};
6601f2ad 1111 }
51674a63 1112 unshift(@args, $namespace || '');
1113 }
ac5c933b 1114
189e2a51 1115 # join args with '/', or a blank string
51674a63 1116 my $args = join('/', grep { defined($_) } @args);
1117 $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
7a2295bc 1118 $args =~ s!^/+!!;
51674a63 1119 my $base = $c->req->base;
1120 my $class = ref($base);
1121 $base =~ s{(?<!/)$}{/};
1122
1123 my $query = '';
1124
1125 if (my @keys = keys %$params) {
1126 # somewhat lifted from URI::_query's query_form
1127 $query = '?'.join('&', map {
2f381252 1128 my $val = $params->{$_};
51674a63 1129 s/([;\/?:@&=+,\$\[\]%])/$URI::Escape::escapes{$1}/go;
1130 s/ /+/g;
1131 my $key = $_;
51674a63 1132 $val = '' unless defined $val;
1133 (map {
1134 $_ = "$_";
0ce485e9 1135 utf8::encode( $_ ) if utf8::is_utf8($_);
51674a63 1136 # using the URI::Escape pattern here so utf8 chars survive
1137 s/([^A-Za-z0-9\-_.!~*'() ])/$URI::Escape::escapes{$1}/go;
1138 s/ /+/g;
1139 "${key}=$_"; } ( ref $val eq 'ARRAY' ? @$val : $val ));
1140 } @keys);
1141 }
1142
1143 my $res = bless(\"${base}${args}${query}", $class);
d3e7a648 1144 $res;
fbcc39ad 1145}
1146
b5ecfcf0 1147=head2 $c->welcome_message
ab2374d3 1148
1149Returns the Catalyst welcome HTML page.
1150
1151=cut
1152
1153sub welcome_message {
bf1f2c60 1154 my $c = shift;
1155 my $name = $c->config->{name};
1156 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
1157 my $prefix = Catalyst::Utils::appprefix( ref $c );
80cdbbff 1158 $c->response->content_type('text/html; charset=utf-8');
ab2374d3 1159 return <<"EOF";
80cdbbff 1160<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
1161 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1162<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
ab2374d3 1163 <head>
85d9fce6 1164 <meta http-equiv="Content-Language" content="en" />
1165 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
ab2374d3 1166 <title>$name on Catalyst $VERSION</title>
1167 <style type="text/css">
1168 body {
ab2374d3 1169 color: #000;
1170 background-color: #eee;
1171 }
1172 div#content {
1173 width: 640px;
80cdbbff 1174 margin-left: auto;
1175 margin-right: auto;
ab2374d3 1176 margin-top: 10px;
1177 margin-bottom: 10px;
1178 text-align: left;
1179 background-color: #ccc;
1180 border: 1px solid #aaa;
ab2374d3 1181 }
d84c4dab 1182 p, h1, h2 {
ab2374d3 1183 margin-left: 20px;
1184 margin-right: 20px;
16215972 1185 font-family: verdana, tahoma, sans-serif;
ab2374d3 1186 }
d84c4dab 1187 a {
1188 font-family: verdana, tahoma, sans-serif;
1189 }
d114e033 1190 :link, :visited {
1191 text-decoration: none;
1192 color: #b00;
1193 border-bottom: 1px dotted #bbb;
1194 }
1195 :link:hover, :visited:hover {
d114e033 1196 color: #555;
1197 }
ab2374d3 1198 div#topbar {
1199 margin: 0px;
1200 }
3e82a295 1201 pre {
3e82a295 1202 margin: 10px;
1203 padding: 8px;
1204 }
ab2374d3 1205 div#answers {
1206 padding: 8px;
1207 margin: 10px;
d114e033 1208 background-color: #fff;
ab2374d3 1209 border: 1px solid #aaa;
ab2374d3 1210 }
1211 h1 {
33108eaf 1212 font-size: 0.9em;
1213 font-weight: normal;
ab2374d3 1214 text-align: center;
1215 }
1216 h2 {
1217 font-size: 1.0em;
1218 }
1219 p {
1220 font-size: 0.9em;
1221 }
ae7c5252 1222 p img {
1223 float: right;
1224 margin-left: 10px;
1225 }
9619f23c 1226 span#appname {
1227 font-weight: bold;
33108eaf 1228 font-size: 1.6em;
ab2374d3 1229 }
1230 </style>
1231 </head>
1232 <body>
1233 <div id="content">
1234 <div id="topbar">
9619f23c 1235 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
d84c4dab 1236 $VERSION</h1>
ab2374d3 1237 </div>
1238 <div id="answers">
ae7c5252 1239 <p>
80cdbbff 1240 <img src="$logo" alt="Catalyst Logo" />
ae7c5252 1241 </p>
596aaffe 1242 <p>Welcome to the world of Catalyst.
f92fd545 1243 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
1244 framework will make web development something you had
60dd6e1d 1245 never expected it to be: Fun, rewarding, and quick.</p>
ab2374d3 1246 <h2>What to do now?</h2>
4b8cb778 1247 <p>That really depends on what <b>you</b> want to do.
ab2374d3 1248 We do, however, provide you with a few starting points.</p>
1249 <p>If you want to jump right into web development with Catalyst
2f381252 1250 you might want to start with a tutorial.</p>
b607f8a0 1251<pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
596aaffe 1252</pre>
1253<p>Afterwards you can go on to check out a more complete look at our features.</p>
1254<pre>
b607f8a0 1255<code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
1256<!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
1257</code></pre>
ab2374d3 1258 <h2>What to do next?</h2>
f5681c92 1259 <p>Next it's time to write an actual application. Use the
80cdbbff 1260 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&amp;mode=all">controllers</a>,
60dd6e1d 1261 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&amp;mode=all">models</a>, and
1262 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&amp;mode=all">views</a>;
bf1f2c60 1263 they can save you a lot of work.</p>
1264 <pre><code>script/${prefix}_create.pl -help</code></pre>
1265 <p>Also, be sure to check out the vast and growing
60dd6e1d 1266 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&amp;mode=all">plugins for Catalyst on CPAN</a>;
bf1f2c60 1267 you are likely to find what you need there.
f5681c92 1268 </p>
1269
82245cc4 1270 <h2>Need help?</h2>
f5681c92 1271 <p>Catalyst has a very active community. Here are the main places to
1272 get in touch with us.</p>
16215972 1273 <ul>
1274 <li>
2b9a7d76 1275 <a href="http://dev.catalyst.perl.org">Wiki</a>
16215972 1276 </li>
1277 <li>
6d4c3368 1278 <a href="http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst">Mailing-List</a>
16215972 1279 </li>
1280 <li>
4eaf7c88 1281 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
16215972 1282 </li>
1283 </ul>
ab2374d3 1284 <h2>In conclusion</h2>
ac5c933b 1285 <p>The Catalyst team hopes you will enjoy using Catalyst as much
f5681c92 1286 as we enjoyed making it. Please contact us if you have ideas
1287 for improvement or other feedback.</p>
ab2374d3 1288 </div>
1289 </div>
1290 </body>
1291</html>
1292EOF
1293}
1294
fbcc39ad 1295=head1 INTERNAL METHODS
1296
ae1e6b59 1297These methods are not meant to be used by end users.
1298
b5ecfcf0 1299=head2 $c->components
fbcc39ad 1300
e7f1cf73 1301Returns a hash of components.
fbcc39ad 1302
b5ecfcf0 1303=head2 $c->context_class
1f9cb7c1 1304
e7f1cf73 1305Returns or sets the context class.
1f9cb7c1 1306
b5ecfcf0 1307=head2 $c->counter
fbcc39ad 1308
ae1e6b59 1309Returns a hashref containing coderefs and execution counts (needed for
1310deep recursion detection).
fbcc39ad 1311
b5ecfcf0 1312=head2 $c->depth
fbcc39ad 1313
e7f1cf73 1314Returns the number of actions on the current internal execution stack.
fbcc39ad 1315
b5ecfcf0 1316=head2 $c->dispatch
fbcc39ad 1317
e7f1cf73 1318Dispatches a request to actions.
fbcc39ad 1319
1320=cut
1321
1322sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
1323
b5ecfcf0 1324=head2 $c->dispatcher_class
1f9cb7c1 1325
e7f1cf73 1326Returns or sets the dispatcher class.
1f9cb7c1 1327
b5ecfcf0 1328=head2 $c->dump_these
7f92deef 1329
ae1e6b59 1330Returns a list of 2-element array references (name, structure) pairs
1331that will be dumped on the error page in debug mode.
7f92deef 1332
1333=cut
1334
1335sub dump_these {
1336 my $c = shift;
ac5c933b 1337 [ Request => $c->req ],
1338 [ Response => $c->res ],
052a2d89 1339 [ Stash => $c->stash ],
1340 [ Config => $c->config ];
7f92deef 1341}
1342
b5ecfcf0 1343=head2 $c->engine_class
1f9cb7c1 1344
e7f1cf73 1345Returns or sets the engine class.
1f9cb7c1 1346
b5ecfcf0 1347=head2 $c->execute( $class, $coderef )
fbcc39ad 1348
0ef52a96 1349Execute a coderef in given class and catch exceptions. Errors are available
1350via $c->error.
fbcc39ad 1351
1352=cut
1353
1354sub execute {
1355 my ( $c, $class, $code ) = @_;
858828dd 1356 $class = $c->component($class) || $class;
fbcc39ad 1357 $c->state(0);
a0eca838 1358
197bd788 1359 if ( $c->depth >= $RECURSION ) {
f3414019 1360 my $action = $code->reverse();
91d08727 1361 $action = "/$action" unless $action =~ /->/;
f3414019 1362 my $error = qq/Deep recursion detected calling "${action}"/;
1627551a 1363 $c->log->error($error);
1364 $c->error($error);
1365 $c->state(0);
1366 return $c->state;
1367 }
1368
dc5f035e 1369 my $stats_info = $c->_stats_start_execute( $code ) if $c->use_stats;
22247e54 1370
8767c5a3 1371 push( @{ $c->stack }, $code );
ac5c933b 1372
f3414019 1373 eval { $c->state( $code->execute( $class, $c, @{ $c->req->args } ) || 0 ) };
22247e54 1374
dc5f035e 1375 $c->_stats_finish_execute( $stats_info ) if $c->use_stats and $stats_info;
ac5c933b 1376
a6724a82 1377 my $last = pop( @{ $c->stack } );
fbcc39ad 1378
1379 if ( my $error = $@ ) {
2f381252 1380 if ( !ref($error) and $error eq $DETACH ) {
1381 die $DETACH if($c->depth > 1);
1382 }
55424863 1383 elsif ( !ref($error) and $error eq $GO ) {
1384 die $GO if($c->depth > 0);
1385 }
fbcc39ad 1386 else {
1387 unless ( ref $error ) {
91d08727 1388 no warnings 'uninitialized';
fbcc39ad 1389 chomp $error;
f59def82 1390 my $class = $last->class;
1391 my $name = $last->name;
1392 $error = qq/Caught exception in $class->$name "$error"/;
fbcc39ad 1393 }
fbcc39ad 1394 $c->error($error);
1395 $c->state(0);
1396 }
1397 }
1398 return $c->state;
1399}
1400
7a7d7af5 1401sub _stats_start_execute {
1402 my ( $c, $code ) = @_;
1403
a6724a82 1404 return if ( ( $code->name =~ /^_.*/ )
1405 && ( !$c->config->{show_internal_actions} ) );
7a7d7af5 1406
f3414019 1407 my $action_name = $code->reverse();
1408 $c->counter->{$action_name}++;
7a7d7af5 1409
f3414019 1410 my $action = $action_name;
a6724a82 1411 $action = "/$action" unless $action =~ /->/;
1412
7a7d7af5 1413 # determine if the call was the result of a forward
1414 # this is done by walking up the call stack and looking for a calling
1415 # sub of Catalyst::forward before the eval
1416 my $callsub = q{};
1417 for my $index ( 2 .. 11 ) {
1418 last
1419 if ( ( caller($index) )[0] eq 'Catalyst'
1420 && ( caller($index) )[3] eq '(eval)' );
1421
1422 if ( ( caller($index) )[3] =~ /forward$/ ) {
1423 $callsub = ( caller($index) )[3];
1424 $action = "-> $action";
1425 last;
1426 }
1427 }
1428
f3414019 1429 my $uid = $action_name . $c->counter->{$action_name};
74efc144 1430
a6724a82 1431 # is this a root-level call or a forwarded call?
1432 if ( $callsub =~ /forward$/ ) {
1433
1434 # forward, locate the caller
1435 if ( my $parent = $c->stack->[-1] ) {
69d8f33c 1436 $c->stats->profile(
ac5c933b 1437 begin => $action,
69d8f33c 1438 parent => "$parent" . $c->counter->{"$parent"},
1439 uid => $uid,
1440 );
7a7d7af5 1441 }
1442 else {
1443
a6724a82 1444 # forward with no caller may come from a plugin
69d8f33c 1445 $c->stats->profile(
1446 begin => $action,
1447 uid => $uid,
1448 );
7a7d7af5 1449 }
1450 }
a6724a82 1451 else {
ac5c933b 1452
a6724a82 1453 # root-level call
69d8f33c 1454 $c->stats->profile(
1455 begin => $action,
1456 uid => $uid,
1457 );
a6724a82 1458 }
dc5f035e 1459 return $action;
7a7d7af5 1460
7a7d7af5 1461}
1462
1463sub _stats_finish_execute {
1464 my ( $c, $info ) = @_;
69d8f33c 1465 $c->stats->profile( end => $info );
7a7d7af5 1466}
1467
3d0d6d21 1468=head2 $c->_localize_fields( sub { }, \%keys );
1469
1470=cut
1471
e63bdf38 1472#Why does this exist? This is no longer safe and WILL NOT WORK.
1473# it doesnt seem to be used anywhere. can we remove it?
3d0d6d21 1474sub _localize_fields {
1475 my ( $c, $localized, $code ) = ( @_ );
1476
1477 my $request = delete $localized->{request} || {};
1478 my $response = delete $localized->{response} || {};
ac5c933b 1479
3d0d6d21 1480 local @{ $c }{ keys %$localized } = values %$localized;
1481 local @{ $c->request }{ keys %$request } = values %$request;
1482 local @{ $c->response }{ keys %$response } = values %$response;
1483
1484 $code->();
1485}
1486
b5ecfcf0 1487=head2 $c->finalize
fbcc39ad 1488
e7f1cf73 1489Finalizes the request.
fbcc39ad 1490
1491=cut
1492
1493sub finalize {
1494 my $c = shift;
1495
369c09bc 1496 for my $error ( @{ $c->error } ) {
1497 $c->log->error($error);
1498 }
1499
5050d7a7 1500 # Allow engine to handle finalize flow (for POE)
e63bdf38 1501 my $engine = $c->engine;
1502 if ( my $code = $engine->can('finalize') ) {
1503 $engine->$code($c);
fbcc39ad 1504 }
5050d7a7 1505 else {
fbcc39ad 1506
5050d7a7 1507 $c->finalize_uploads;
fbcc39ad 1508
5050d7a7 1509 # Error
1510 if ( $#{ $c->error } >= 0 ) {
1511 $c->finalize_error;
1512 }
1513
1514 $c->finalize_headers;
fbcc39ad 1515
5050d7a7 1516 # HEAD request
1517 if ( $c->request->method eq 'HEAD' ) {
1518 $c->response->body('');
1519 }
1520
1521 $c->finalize_body;
1522 }
ac5c933b 1523
1524 if ($c->use_stats) {
596677b6 1525 my $elapsed = sprintf '%f', $c->stats->elapsed;
12bf12c0 1526 my $av = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed;
908e3d9e 1527 $c->log->info(
ac5c933b 1528 "Request took ${elapsed}s ($av/s)\n" . $c->stats->report . "\n" );
908e3d9e 1529 }
fbcc39ad 1530
1531 return $c->response->status;
1532}
1533
b5ecfcf0 1534=head2 $c->finalize_body
fbcc39ad 1535
e7f1cf73 1536Finalizes body.
fbcc39ad 1537
1538=cut
1539
1540sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
1541
b5ecfcf0 1542=head2 $c->finalize_cookies
fbcc39ad 1543
e7f1cf73 1544Finalizes cookies.
fbcc39ad 1545
1546=cut
1547
147821ea 1548sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
fbcc39ad 1549
b5ecfcf0 1550=head2 $c->finalize_error
fbcc39ad 1551
e7f1cf73 1552Finalizes error.
fbcc39ad 1553
1554=cut
1555
1556sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
1557
b5ecfcf0 1558=head2 $c->finalize_headers
fbcc39ad 1559
e7f1cf73 1560Finalizes headers.
fbcc39ad 1561
1562=cut
1563
1564sub finalize_headers {
1565 my $c = shift;
1566
e63bdf38 1567 my $response = $c->response; #accessor calls can add up?
1568
fbcc39ad 1569 # Check if we already finalized headers
6680c772 1570 return if $response->finalized_headers;
fbcc39ad 1571
1572 # Handle redirects
e63bdf38 1573 if ( my $location = $response->redirect ) {
fbcc39ad 1574 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
e63bdf38 1575 $response->header( Location => $location );
a7caa492 1576
02570318 1577 if ( !$response->has_body ) {
39655cdc 1578 # Add a default body if none is already present
e63bdf38 1579 $response->body(
e422816e 1580 qq{<html><body><p>This item has moved <a href="$location">here</a>.</p></body></html>}
39655cdc 1581 );
1582 }
fbcc39ad 1583 }
1584
1585 # Content-Length
e63bdf38 1586 if ( $response->body && !$response->content_length ) {
775878ac 1587
8f62c91a 1588 # get the length from a filehandle
e63bdf38 1589 if ( blessed( $response->body ) && $response->body->can('read') )
197bd788 1590 {
e63bdf38 1591 my $stat = stat $response->body;
3b6a1db1 1592 if ( $stat && $stat->size > 0 ) {
e63bdf38 1593 $response->content_length( $stat->size );
8f62c91a 1594 }
1595 else {
775878ac 1596 $c->log->warn('Serving filehandle without a content-length');
8f62c91a 1597 }
1598 }
1599 else {
b5d7a61f 1600 # everything should be bytes at this point, but just in case
e63bdf38 1601 $response->content_length( bytes::length( $response->body ) );
8f62c91a 1602 }
fbcc39ad 1603 }
1604
1605 # Errors
e63bdf38 1606 if ( $response->status =~ /^(1\d\d|[23]04)$/ ) {
1607 $response->headers->remove_header("Content-Length");
1608 $response->body('');
fbcc39ad 1609 }
1610
1611 $c->finalize_cookies;
1612
1613 $c->engine->finalize_headers( $c, @_ );
1614
1615 # Done
6680c772 1616 $response->finalized_headers(1);
fbcc39ad 1617}
1618
b5ecfcf0 1619=head2 $c->finalize_output
fbcc39ad 1620
1621An alias for finalize_body.
1622
b5ecfcf0 1623=head2 $c->finalize_read
fbcc39ad 1624
e7f1cf73 1625Finalizes the input after reading is complete.
fbcc39ad 1626
1627=cut
1628
1629sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1630
b5ecfcf0 1631=head2 $c->finalize_uploads
fbcc39ad 1632
ae1e6b59 1633Finalizes uploads. Cleans up any temporary files.
fbcc39ad 1634
1635=cut
1636
1637sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1638
b5ecfcf0 1639=head2 $c->get_action( $action, $namespace )
fbcc39ad 1640
e7f1cf73 1641Gets an action in a given namespace.
fbcc39ad 1642
1643=cut
1644
684d10ed 1645sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
fbcc39ad 1646
b5ecfcf0 1647=head2 $c->get_actions( $action, $namespace )
a9dc674c 1648
ae1e6b59 1649Gets all actions of a given name in a namespace and all parent
1650namespaces.
a9dc674c 1651
1652=cut
1653
1654sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1655
f7b672ef 1656=head2 $c->handle_request( $class, @arguments )
fbcc39ad 1657
e7f1cf73 1658Called to handle each HTTP request.
fbcc39ad 1659
1660=cut
1661
1662sub handle_request {
1663 my ( $class, @arguments ) = @_;
1664
1665 # Always expect worst case!
1666 my $status = -1;
1667 eval {
dea1884f 1668 if ($class->debug) {
908e3d9e 1669 my $secs = time - $START || 1;
1670 my $av = sprintf '%.3f', $COUNT / $secs;
1671 my $time = localtime time;
1672 $class->log->info("*** Request $COUNT ($av/s) [$$] [$time] ***");
dea1884f 1673 }
908e3d9e 1674
1675 my $c = $class->prepare(@arguments);
1676 $c->dispatch;
ac5c933b 1677 $status = $c->finalize;
fbcc39ad 1678 };
1679
1680 if ( my $error = $@ ) {
1681 chomp $error;
1682 $class->log->error(qq/Caught exception in engine "$error"/);
1683 }
1684
1685 $COUNT++;
6680c772 1686
1687 if(my $coderef = $class->log->can('_flush')){
1688 $class->log->$coderef();
1689 }
fbcc39ad 1690 return $status;
1691}
1692
b5ecfcf0 1693=head2 $c->prepare( @arguments )
fbcc39ad 1694
ae1e6b59 1695Creates a Catalyst context from an engine-specific request (Apache, CGI,
1696etc.).
fbcc39ad 1697
1698=cut
1699
1700sub prepare {
1701 my ( $class, @arguments ) = @_;
1702
6680c772 1703 # XXX
1704 # After the app/ctxt split, this should become an attribute based on something passed
1705 # into the application.
3cec521a 1706 $class->context_class( ref $class || $class ) unless $class->context_class;
6680c772 1707
1708 my $c = $class->context_class->new({});
1709
1710 # For on-demand data
1711 $c->request->_context($c);
1712 $c->response->_context($c);
fbcc39ad 1713
b6d4ee6e 1714 #surely this is not the most efficient way to do things...
dc5f035e 1715 $c->stats($class->stats_class->new)->enable($c->use_stats);
908e3d9e 1716 if ( $c->debug ) {
ac5c933b 1717 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
908e3d9e 1718 }
1719
e63bdf38 1720 #XXX reuse coderef from can
5050d7a7 1721 # Allow engine to direct the prepare flow (for POE)
1722 if ( $c->engine->can('prepare') ) {
1723 $c->engine->prepare( $c, @arguments );
1724 }
1725 else {
1726 $c->prepare_request(@arguments);
1727 $c->prepare_connection;
1728 $c->prepare_query_parameters;
1729 $c->prepare_headers;
1730 $c->prepare_cookies;
1731 $c->prepare_path;
1732
878b821c 1733 # Prepare the body for reading, either by prepare_body
1734 # or the user, if they are using $c->read
1735 $c->prepare_read;
ac5c933b 1736
878b821c 1737 # Parse the body unless the user wants it on-demand
1738 unless ( $c->config->{parse_on_demand} ) {
1739 $c->prepare_body;
1740 }
5050d7a7 1741 }
fbcc39ad 1742
fbcc39ad 1743 my $method = $c->req->method || '';
2f381252 1744 my $path = $c->req->path;
1745 $path = '/' unless length $path;
fbcc39ad 1746 my $address = $c->req->address || '';
1747
e3a13771 1748 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
fbcc39ad 1749 if $c->debug;
1750
e3a13771 1751 $c->prepare_action;
1752
fbcc39ad 1753 return $c;
1754}
1755
b5ecfcf0 1756=head2 $c->prepare_action
fbcc39ad 1757
b4b01a8a 1758Prepares action. See L<Catalyst::Dispatcher>.
fbcc39ad 1759
1760=cut
1761
1762sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1763
b5ecfcf0 1764=head2 $c->prepare_body
fbcc39ad 1765
e7f1cf73 1766Prepares message body.
fbcc39ad 1767
1768=cut
1769
1770sub prepare_body {
1771 my $c = shift;
1772
0f56bbcf 1773 return if $c->request->_has_body;
fbcc39ad 1774
1775 # Initialize on-demand data
1776 $c->engine->prepare_body( $c, @_ );
1777 $c->prepare_parameters;
1778 $c->prepare_uploads;
1779
1780 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
34d28dfd 1781 my $t = Text::SimpleTable->new( [ 35, 'Parameter' ], [ 36, 'Value' ] );
fbcc39ad 1782 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1783 my $param = $c->req->body_parameters->{$key};
1784 my $value = defined($param) ? $param : '';
8c113188 1785 $t->row( $key,
fbcc39ad 1786 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1787 }
1788 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1789 }
1790}
1791
b5ecfcf0 1792=head2 $c->prepare_body_chunk( $chunk )
4bd82c41 1793
e7f1cf73 1794Prepares a chunk of data before sending it to L<HTTP::Body>.
4bd82c41 1795
b4b01a8a 1796See L<Catalyst::Engine>.
1797
4bd82c41 1798=cut
1799
4f5ebacd 1800sub prepare_body_chunk {
1801 my $c = shift;
4bd82c41 1802 $c->engine->prepare_body_chunk( $c, @_ );
1803}
1804
b5ecfcf0 1805=head2 $c->prepare_body_parameters
fbcc39ad 1806
e7f1cf73 1807Prepares body parameters.
fbcc39ad 1808
1809=cut
1810
1811sub prepare_body_parameters {
1812 my $c = shift;
1813 $c->engine->prepare_body_parameters( $c, @_ );
1814}
1815
b5ecfcf0 1816=head2 $c->prepare_connection
fbcc39ad 1817
e7f1cf73 1818Prepares connection.
fbcc39ad 1819
1820=cut
1821
1822sub prepare_connection {
1823 my $c = shift;
1824 $c->engine->prepare_connection( $c, @_ );
1825}
1826
b5ecfcf0 1827=head2 $c->prepare_cookies
fbcc39ad 1828
e7f1cf73 1829Prepares cookies.
fbcc39ad 1830
1831=cut
1832
1833sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1834
b5ecfcf0 1835=head2 $c->prepare_headers
fbcc39ad 1836
e7f1cf73 1837Prepares headers.
fbcc39ad 1838
1839=cut
1840
1841sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1842
b5ecfcf0 1843=head2 $c->prepare_parameters
fbcc39ad 1844
e7f1cf73 1845Prepares parameters.
fbcc39ad 1846
1847=cut
1848
1849sub prepare_parameters {
1850 my $c = shift;
1851 $c->prepare_body_parameters;
1852 $c->engine->prepare_parameters( $c, @_ );
1853}
1854
b5ecfcf0 1855=head2 $c->prepare_path
fbcc39ad 1856
e7f1cf73 1857Prepares path and base.
fbcc39ad 1858
1859=cut
1860
1861sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1862
b5ecfcf0 1863=head2 $c->prepare_query_parameters
fbcc39ad 1864
e7f1cf73 1865Prepares query parameters.
fbcc39ad 1866
1867=cut
1868
1869sub prepare_query_parameters {
1870 my $c = shift;
1871
1872 $c->engine->prepare_query_parameters( $c, @_ );
1873
1874 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
34d28dfd 1875 my $t = Text::SimpleTable->new( [ 35, 'Parameter' ], [ 36, 'Value' ] );
fbcc39ad 1876 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1877 my $param = $c->req->query_parameters->{$key};
1878 my $value = defined($param) ? $param : '';
8c113188 1879 $t->row( $key,
fbcc39ad 1880 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1881 }
1882 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1883 }
1884}
1885
b5ecfcf0 1886=head2 $c->prepare_read
fbcc39ad 1887
e7f1cf73 1888Prepares the input for reading.
fbcc39ad 1889
1890=cut
1891
1892sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1893
b5ecfcf0 1894=head2 $c->prepare_request
fbcc39ad 1895
e7f1cf73 1896Prepares the engine request.
fbcc39ad 1897
1898=cut
1899
1900sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1901
b5ecfcf0 1902=head2 $c->prepare_uploads
fbcc39ad 1903
e7f1cf73 1904Prepares uploads.
fbcc39ad 1905
1906=cut
1907
1908sub prepare_uploads {
1909 my $c = shift;
1910
1911 $c->engine->prepare_uploads( $c, @_ );
1912
1913 if ( $c->debug && keys %{ $c->request->uploads } ) {
8c113188 1914 my $t = Text::SimpleTable->new(
34d28dfd 1915 [ 12, 'Parameter' ],
1916 [ 26, 'Filename' ],
8c113188 1917 [ 18, 'Type' ],
1918 [ 9, 'Size' ]
1919 );
fbcc39ad 1920 for my $key ( sort keys %{ $c->request->uploads } ) {
1921 my $upload = $c->request->uploads->{$key};
1922 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
8c113188 1923 $t->row( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1924 }
1925 }
1926 $c->log->debug( "File Uploads are:\n" . $t->draw );
1927 }
1928}
1929
b5ecfcf0 1930=head2 $c->prepare_write
fbcc39ad 1931
e7f1cf73 1932Prepares the output for writing.
fbcc39ad 1933
1934=cut
1935
1936sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1937
b5ecfcf0 1938=head2 $c->request_class
1f9cb7c1 1939
e7f1cf73 1940Returns or sets the request class.
1f9cb7c1 1941
b5ecfcf0 1942=head2 $c->response_class
1f9cb7c1 1943
e7f1cf73 1944Returns or sets the response class.
1f9cb7c1 1945
b5ecfcf0 1946=head2 $c->read( [$maxlength] )
fbcc39ad 1947
ae1e6b59 1948Reads a chunk of data from the request body. This method is designed to
1949be used in a while loop, reading C<$maxlength> bytes on every call.
1950C<$maxlength> defaults to the size of the request if not specified.
fbcc39ad 1951
cc95842f 1952You have to set C<< MyApp->config->{parse_on_demand} >> to use this
ae1e6b59 1953directly.
fbcc39ad 1954
878b821c 1955Warning: If you use read(), Catalyst will not process the body,
1956so you will not be able to access POST parameters or file uploads via
1957$c->request. You must handle all body parsing yourself.
1958
fbcc39ad 1959=cut
1960
1961sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1962
b5ecfcf0 1963=head2 $c->run
fbcc39ad 1964
1965Starts the engine.
1966
1967=cut
1968
1969sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1970
b5ecfcf0 1971=head2 $c->set_action( $action, $code, $namespace, $attrs )
fbcc39ad 1972
e7f1cf73 1973Sets an action in a given namespace.
fbcc39ad 1974
1975=cut
1976
1977sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1978
b5ecfcf0 1979=head2 $c->setup_actions($component)
fbcc39ad 1980
e7f1cf73 1981Sets up actions for a component.
fbcc39ad 1982
1983=cut
1984
1985sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1986
b5ecfcf0 1987=head2 $c->setup_components
fbcc39ad 1988
86418559 1989Sets up components. Specify a C<setup_components> config option to pass
1990additional options directly to L<Module::Pluggable>. To add additional
1991search paths, specify a key named C<search_extra> as an array
1992reference. Items in the array beginning with C<::> will have the
18de900e 1993application class name prepended to them.
fbcc39ad 1994
2f381252 1995All components found will also have any
1996L<Devel::InnerPackage|inner packages> loaded and set up as components.
1997Note, that modules which are B<not> an I<inner package> of the main
1998file namespace loaded will not be instantiated as components.
1999
fbcc39ad 2000=cut
2001
2002sub setup_components {
2003 my $class = shift;
2004
18de900e 2005 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
2006 my $config = $class->config->{ setup_components };
2007 my $extra = delete $config->{ search_extra } || [];
ac5c933b 2008
18de900e 2009 push @paths, @$extra;
ac5c933b 2010
364d7324 2011 my $locator = Module::Pluggable::Object->new(
18de900e 2012 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
2013 %$config
364d7324 2014 );
b94b200c 2015
2016 my @comps = sort { length $a <=> length $b } $locator->plugins;
2017 my %comps = map { $_ => 1 } @comps;
ac5c933b 2018
b94b200c 2019 for my $component ( @comps ) {
dd91afb5 2020
2021 # We pass ignore_loaded here so that overlay files for (e.g.)
2022 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
2023 # we know M::P::O found a file on disk so this is safe
2024
f5a4863c 2025 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
2026 #Class::MOP::load_class($component);
364d7324 2027
2028 my $module = $class->setup_component( $component );
2029 my %modules = (
2030 $component => $module,
2031 map {
2032 $_ => $class->setup_component( $_ )
ac5c933b 2033 } grep {
b94b200c 2034 not exists $comps{$_}
364d7324 2035 } Devel::InnerPackage::list_packages( $component )
2036 );
ac5c933b 2037
364d7324 2038 for my $key ( keys %modules ) {
2039 $class->components->{ $key } = $modules{ $key };
fbcc39ad 2040 }
364d7324 2041 }
2042}
fbcc39ad 2043
364d7324 2044=head2 $c->setup_component
fbcc39ad 2045
364d7324 2046=cut
fbcc39ad 2047
364d7324 2048sub setup_component {
2049 my( $class, $component ) = @_;
fbcc39ad 2050
364d7324 2051 unless ( $component->can( 'COMPONENT' ) ) {
2052 return $component;
2053 }
fbcc39ad 2054
364d7324 2055 my $suffix = Catalyst::Utils::class2classsuffix( $component );
2056 my $config = $class->config->{ $suffix } || {};
fbcc39ad 2057
364d7324 2058 my $instance = eval { $component->COMPONENT( $class, $config ); };
fbcc39ad 2059
2060 if ( my $error = $@ ) {
fbcc39ad 2061 chomp $error;
fbcc39ad 2062 Catalyst::Exception->throw(
364d7324 2063 message => qq/Couldn't instantiate component "$component", "$error"/
2064 );
fbcc39ad 2065 }
2066
364d7324 2067 Catalyst::Exception->throw(
2068 message =>
2069 qq/Couldn't instantiate component "$component", "COMPONENT() didn't return an object-like value"/
84ff88cf 2070 ) unless blessed($instance);
364d7324 2071
2072 return $instance;
fbcc39ad 2073}
2074
b5ecfcf0 2075=head2 $c->setup_dispatcher
fbcc39ad 2076
ae1e6b59 2077Sets up dispatcher.
2078
fbcc39ad 2079=cut
2080
2081sub setup_dispatcher {
2082 my ( $class, $dispatcher ) = @_;
2083
2084 if ($dispatcher) {
2085 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
2086 }
2087
cb69249e 2088 if ( my $env = Catalyst::Utils::env_value( $class, 'DISPATCHER' ) ) {
2089 $dispatcher = 'Catalyst::Dispatcher::' . $env;
fbcc39ad 2090 }
2091
2092 unless ($dispatcher) {
cb0354c6 2093 $dispatcher = $class->dispatcher_class;
fbcc39ad 2094 }
2095
e63bdf38 2096 Class::MOP::load_class($dispatcher);
fbcc39ad 2097
2098 # dispatcher instance
2099 $class->dispatcher( $dispatcher->new );
2100}
2101
b5ecfcf0 2102=head2 $c->setup_engine
fbcc39ad 2103
ae1e6b59 2104Sets up engine.
2105
fbcc39ad 2106=cut
2107
2108sub setup_engine {
2109 my ( $class, $engine ) = @_;
2110
2111 if ($engine) {
2112 $engine = 'Catalyst::Engine::' . $engine;
2113 }
2114
cb69249e 2115 if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
2116 $engine = 'Catalyst::Engine::' . $env;
fbcc39ad 2117 }
2118
9b0a3e0f 2119 if ( $ENV{MOD_PERL} ) {
e106a59f 2120 my $meta = Class::MOP::get_metaclass_by_name($class);
74c89dea 2121
fbcc39ad 2122 # create the apache method
74c89dea 2123 $meta->add_method('apache' => sub { shift->engine->apache });
fbcc39ad 2124
2125 my ( $software, $version ) =
2126 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
2127
2128 $version =~ s/_//g;
2129 $version =~ s/(\.[^.]+)\./$1/g;
2130
2131 if ( $software eq 'mod_perl' ) {
2132
9b0a3e0f 2133 if ( !$engine ) {
22247e54 2134
9b0a3e0f 2135 if ( $version >= 1.99922 ) {
2136 $engine = 'Catalyst::Engine::Apache2::MP20';
2137 }
22247e54 2138
9b0a3e0f 2139 elsif ( $version >= 1.9901 ) {
2140 $engine = 'Catalyst::Engine::Apache2::MP19';
2141 }
22247e54 2142
9b0a3e0f 2143 elsif ( $version >= 1.24 ) {
2144 $engine = 'Catalyst::Engine::Apache::MP13';
2145 }
22247e54 2146
9b0a3e0f 2147 else {
2148 Catalyst::Exception->throw( message =>
2149 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
2150 }
fbcc39ad 2151
fbcc39ad 2152 }
2153
2154 # install the correct mod_perl handler
2155 if ( $version >= 1.9901 ) {
2156 *handler = sub : method {
2157 shift->handle_request(@_);
2158 };
2159 }
2160 else {
2161 *handler = sub ($$) { shift->handle_request(@_) };
2162 }
2163
2164 }
2165
2166 elsif ( $software eq 'Zeus-Perl' ) {
2167 $engine = 'Catalyst::Engine::Zeus';
2168 }
2169
2170 else {
2171 Catalyst::Exception->throw(
2172 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
2173 }
2174 }
2175
2176 unless ($engine) {
cb0354c6 2177 $engine = $class->engine_class;
fbcc39ad 2178 }
2179
e63bdf38 2180 Class::MOP::load_class($engine);
0e7f5826 2181
d54484bf 2182 # check for old engines that are no longer compatible
2183 my $old_engine;
0e7f5826 2184 if ( $engine->isa('Catalyst::Engine::Apache')
2185 && !Catalyst::Engine::Apache->VERSION )
d54484bf 2186 {
2187 $old_engine = 1;
2188 }
0e7f5826 2189
d54484bf 2190 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 2191 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 2192 {
2193 $old_engine = 1;
2194 }
0e7f5826 2195
2196 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
2197 && $engine->VERSION eq '0.01' )
d54484bf 2198 {
2199 $old_engine = 1;
2200 }
0e7f5826 2201
2202 elsif ($engine->isa('Catalyst::Engine::Zeus')
2203 && $engine->VERSION eq '0.01' )
d54484bf 2204 {
2205 $old_engine = 1;
2206 }
fbcc39ad 2207
d54484bf 2208 if ($old_engine) {
2209 Catalyst::Exception->throw( message =>
0e7f5826 2210 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 2211 );
2212 }
0e7f5826 2213
fbcc39ad 2214 # engine instance
2215 $class->engine( $engine->new );
2216}
2217
b5ecfcf0 2218=head2 $c->setup_home
fbcc39ad 2219
ae1e6b59 2220Sets up the home directory.
2221
fbcc39ad 2222=cut
2223
2224sub setup_home {
2225 my ( $class, $home ) = @_;
2226
cb69249e 2227 if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
2228 $home = $env;
fbcc39ad 2229 }
2230
b6d4ee6e 2231 $home ||= Catalyst::Utils::home($class);
fbcc39ad 2232
2233 if ($home) {
e63bdf38 2234 #I remember recently being scolded for assigning config values like this
fbcc39ad 2235 $class->config->{home} ||= $home;
a738ab68 2236 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
fbcc39ad 2237 }
2238}
2239
b5ecfcf0 2240=head2 $c->setup_log
fbcc39ad 2241
0fa676a7 2242Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
2243passing it to C<log()>. Pass in a comma-delimited list of levels to set the
2244log to.
2245
2246This method also installs a C<debug> method that returns a true value into the
2247catalyst subclass if the "debug" level is passed in the comma-delimited list,
2248or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
2249
2250Note that if the log has already been setup, by either a previous call to
2251C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
5baa3bbc 2252that this method won't actually set up the log object.
ae1e6b59 2253
fbcc39ad 2254=cut
2255
2256sub setup_log {
0fa676a7 2257 my ( $class, $levels ) = @_;
fbcc39ad 2258
5baa3bbc 2259 $levels ||= '';
2260 $levels =~ s/^\s+//;
2261 $levels =~ s/\s+$//;
2262 my %levels = map { $_ => 1 } split /\s*,\s*/, $levels || '';
2263
fbcc39ad 2264 unless ( $class->log ) {
0fa676a7 2265 $class->log( Catalyst::Log->new(keys %levels) );
fbcc39ad 2266 }
af3ff00e 2267
cb69249e 2268 my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
0fa676a7 2269 if ( defined($env_debug) or $levels{debug} ) {
e106a59f 2270 Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
fbcc39ad 2271 $class->log->debug('Debug messages enabled');
2272 }
2273}
2274
b5ecfcf0 2275=head2 $c->setup_plugins
fbcc39ad 2276
ae1e6b59 2277Sets up plugins.
2278
fbcc39ad 2279=cut
2280
dc5f035e 2281=head2 $c->setup_stats
2282
2283Sets up timing statistics class.
2284
2285=cut
2286
2287sub setup_stats {
2288 my ( $class, $stats ) = @_;
2289
2290 Catalyst::Utils::ensure_class_loaded($class->stats_class);
2291
2292 my $env = Catalyst::Utils::env_value( $class, 'STATS' );
2293 if ( defined($env) ? $env : ($stats || $class->debug ) ) {
e106a59f 2294 Class::MOP::get_metaclass_by_name($class)->add_method('use_stats' => sub { 1 });
b01f0c69 2295 $class->log->debug('Statistics enabled');
dc5f035e 2296 }
2297}
2298
2299
ac5c933b 2300=head2 $c->registered_plugins
836e1134 2301
2302Returns a sorted list of the plugins which have either been stated in the
2303import list or which have been added via C<< MyApp->plugin(@args); >>.
2304
2305If passed a given plugin name, it will report a boolean value indicating
2306whether or not that plugin is loaded. A fully qualified name is required if
2307the plugin name does not begin with C<Catalyst::Plugin::>.
2308
2309 if ($c->registered_plugins('Some::Plugin')) {
2310 ...
2311 }
2312
2313=cut
fbcc39ad 2314
836e1134 2315{
97b58e17 2316
2317 sub registered_plugins {
836e1134 2318 my $proto = shift;
197bd788 2319 return sort keys %{ $proto->_plugins } unless @_;
836e1134 2320 my $plugin = shift;
d0d4d785 2321 return 1 if exists $proto->_plugins->{$plugin};
2322 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
836e1134 2323 }
fbcc39ad 2324
836e1134 2325 sub _register_plugin {
2326 my ( $proto, $plugin, $instant ) = @_;
2327 my $class = ref $proto || $proto;
fbcc39ad 2328
dd91afb5 2329 # no ignore_loaded here, the plugin may already have been
2330 # defined in memory and we don't want to error on "no file" if so
2331
b6d4ee6e 2332 Class::MOP::load_class( $plugin );
fbcc39ad 2333
197bd788 2334 $proto->_plugins->{$plugin} = 1;
836e1134 2335 unless ($instant) {
fbcc39ad 2336 no strict 'refs';
e106a59f 2337 if ( my $meta = Class::MOP::get_metaclass_by_name($class) ) {
74c89dea 2338 my @superclasses = ($plugin, $meta->superclasses );
2339 $meta->superclasses(@superclasses);
5fb67d52 2340 } else {
2341 unshift @{"$class\::ISA"}, $plugin;
2342 }
fbcc39ad 2343 }
836e1134 2344 return $class;
2345 }
2346
2347 sub setup_plugins {
2348 my ( $class, $plugins ) = @_;
2349
d0d4d785 2350 $class->_plugins( {} ) unless $class->_plugins;
836e1134 2351 $plugins ||= [];
2352 for my $plugin ( reverse @$plugins ) {
2353
2354 unless ( $plugin =~ s/\A\+// ) {
2355 $plugin = "Catalyst::Plugin::$plugin";
2356 }
2357
2358 $class->_register_plugin($plugin);
2359 }
fbcc39ad 2360 }
2361}
2362
b5ecfcf0 2363=head2 $c->stack
8767c5a3 2364
86418559 2365Returns an arrayref of the internal execution stack (actions that are
2366currently executing).
8767c5a3 2367
dc5f035e 2368=head2 $c->stats_class
2369
2370Returns or sets the stats (timing statistics) class.
2371
2372=head2 $c->use_stats
2373
2374Returns 1 when stats collection is enabled. Stats collection is enabled
2375when the -Stats options is set, debug is on or when the <MYAPP>_STATS
2376environment variable is set.
2377
2378Note that this is a static method, not an accessor and should be overloaded
2379by declaring "sub use_stats { 1 }" in your MyApp.pm, not by calling $c->use_stats(1).
2380
2381=cut
2382
2383sub use_stats { 0 }
2384
2385
b5ecfcf0 2386=head2 $c->write( $data )
fbcc39ad 2387
ae1e6b59 2388Writes $data to the output stream. When using this method directly, you
2389will need to manually set the C<Content-Length> header to the length of
2390your output data, if known.
fbcc39ad 2391
2392=cut
2393
4f5ebacd 2394sub write {
2395 my $c = shift;
2396
2397 # Finalize headers if someone manually writes output
2398 $c->finalize_headers;
2399
2400 return $c->engine->write( $c, @_ );
2401}
fbcc39ad 2402
b5ecfcf0 2403=head2 version
bf88a181 2404
ae1e6b59 2405Returns the Catalyst version number. Mostly useful for "powered by"
2406messages in template systems.
bf88a181 2407
2408=cut
2409
2410sub version { return $Catalyst::VERSION }
2411
b0bb11ec 2412=head1 INTERNAL ACTIONS
2413
ae1e6b59 2414Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
2415C<_ACTION>, and C<_END>. These are by default not shown in the private
3e705254 2416action table, but you can make them visible with a config parameter.
b0bb11ec 2417
2418 MyApp->config->{show_internal_actions} = 1;
2419
d2ee9760 2420=head1 CASE SENSITIVITY
2421
3e705254 2422By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> is
ae1e6b59 2423mapped to C</foo/bar>. You can activate case sensitivity with a config
3e705254 2424parameter.
d2ee9760 2425
2426 MyApp->config->{case_sensitive} = 1;
2427
3e705254 2428This causes C<MyApp::C::Foo::Bar> to map to C</Foo/Bar>.
fbcc39ad 2429
2430=head1 ON-DEMAND PARSER
2431
2432The request body is usually parsed at the beginning of a request,
878b821c 2433but if you want to handle input yourself, you can enable on-demand
2434parsing with a config parameter.
fbcc39ad 2435
2436 MyApp->config->{parse_on_demand} = 1;
ac5c933b 2437
fbcc39ad 2438=head1 PROXY SUPPORT
2439
ae1e6b59 2440Many production servers operate using the common double-server approach,
2441with a lightweight frontend web server passing requests to a larger
2442backend server. An application running on the backend server must deal
2443with two problems: the remote user always appears to be C<127.0.0.1> and
2444the server's hostname will appear to be C<localhost> regardless of the
2445virtual host that the user connected through.
fbcc39ad 2446
ae1e6b59 2447Catalyst will automatically detect this situation when you are running
2448the frontend and backend servers on the same machine. The following
2449changes are made to the request.
fbcc39ad 2450
ac5c933b 2451 $c->req->address is set to the user's real IP address, as read from
ae1e6b59 2452 the HTTP X-Forwarded-For header.
ac5c933b 2453
ae1e6b59 2454 The host value for $c->req->base and $c->req->uri is set to the real
2455 host, as read from the HTTP X-Forwarded-Host header.
fbcc39ad 2456
3e705254 2457Obviously, your web server must support these headers for this to work.
fbcc39ad 2458
ae1e6b59 2459In a more complex server farm environment where you may have your
2460frontend proxy server(s) on different machines, you will need to set a
2461configuration option to tell Catalyst to read the proxied data from the
2462headers.
fbcc39ad 2463
2464 MyApp->config->{using_frontend_proxy} = 1;
ac5c933b 2465
fbcc39ad 2466If you do not wish to use the proxy support at all, you may set:
d1a31ac6 2467
fbcc39ad 2468 MyApp->config->{ignore_frontend_proxy} = 1;
2469
2470=head1 THREAD SAFETY
2471
86418559 2472Catalyst has been tested under Apache 2's threading C<mpm_worker>,
2473C<mpm_winnt>, and the standalone forking HTTP server on Windows. We
2474believe the Catalyst core to be thread-safe.
fbcc39ad 2475
2476If you plan to operate in a threaded environment, remember that all other
3e705254 2477modules you are using must also be thread-safe. Some modules, most notably
2478L<DBD::SQLite>, are not thread-safe.
d1a31ac6 2479
3cb1db8c 2480=head1 SUPPORT
2481
2482IRC:
2483
4eaf7c88 2484 Join #catalyst on irc.perl.org.
3cb1db8c 2485
3e705254 2486Mailing Lists:
3cb1db8c 2487
6d4c3368 2488 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
2489 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
1985c30b 2490
432d507d 2491Web:
2492
2493 http://catalyst.perl.org
2494
0ef52a96 2495Wiki:
2496
2497 http://dev.catalyst.perl.org
2498
fc7ec1d9 2499=head1 SEE ALSO
2500
829a28ca 2501=head2 L<Task::Catalyst> - All you need to start with Catalyst
2502
b5ecfcf0 2503=head2 L<Catalyst::Manual> - The Catalyst Manual
e7f1cf73 2504
b5ecfcf0 2505=head2 L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
61b1e958 2506
b5ecfcf0 2507=head2 L<Catalyst::Engine> - Core engine
61b1e958 2508
b5ecfcf0 2509=head2 L<Catalyst::Log> - Log class.
61b1e958 2510
b5ecfcf0 2511=head2 L<Catalyst::Request> - Request object
61b1e958 2512
b5ecfcf0 2513=head2 L<Catalyst::Response> - Response object
61b1e958 2514
b5ecfcf0 2515=head2 L<Catalyst::Test> - The test suite.
fc7ec1d9 2516
2f381252 2517=head1 PROJECT FOUNDER
2518
2519sri: Sebastian Riedel <sri@cpan.org>
fc7ec1d9 2520
2f381252 2521=head1 CONTRIBUTORS
15f0b5b7 2522
2f381252 2523abw: Andy Wardley
fbcc39ad 2524
2f381252 2525acme: Leon Brocard <leon@astray.com>
33108eaf 2526
f4a57de4 2527Andrew Bramble
2528
15f0b5b7 2529Andrew Ford
2530
2531Andrew Ruthven
2532
2f381252 2533andyg: Andy Grundman <andy@hybridized.org>
fbcc39ad 2534
2f381252 2535audreyt: Audrey Tang
15f0b5b7 2536
2f381252 2537bricas: Brian Cassidy <bricas@cpan.org>
0cf56dbc 2538
e31b525c 2539Caelum: Rafael Kitover <rkitover@io.com>
2540
2f381252 2541chansen: Christian Hansen
6aaa1c60 2542
2f381252 2543chicks: Christopher Hicks
15f0b5b7 2544
0fa676a7 2545David E. Wheeler
2546
2f381252 2547dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
15f0b5b7 2548
2f381252 2549Drew Taylor
15f0b5b7 2550
2f381252 2551esskar: Sascha Kiefer
0ef52a96 2552
2f381252 2553fireartist: Carl Franks <cfranks@cpan.org>
15f0b5b7 2554
2f381252 2555gabb: Danijel Milicevic
61bef238 2556
15f0b5b7 2557Gary Ashton Jones
2558
2559Geoff Richards
2560
e4cc83b2 2561ilmari: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
2562
2f381252 2563jcamacho: Juan Camacho
fbcc39ad 2564
108201b5 2565jhannah: Jay Hannah <jay@jays.net>
2566
15f0b5b7 2567Jody Belka
2568
2569Johan Lindstrom
2570
2f381252 2571jon: Jon Schutz <jjschutz@cpan.org>
15f0b5b7 2572
2f381252 2573marcus: Marcus Ramberg <mramberg@cpan.org>
15f0b5b7 2574
2f381252 2575miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
15f0b5b7 2576
2f381252 2577mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
15f0b5b7 2578
2f381252 2579mugwump: Sam Vilain
71c3bcc3 2580
2f381252 2581naughton: David Naughton
a727119f 2582
2f381252 2583ningu: David Kamholz <dkamholz@cpan.org>
1cf1c56a 2584
2f381252 2585nothingmuch: Yuval Kogman <nothingmuch@woobling.org>
9c71d51d 2586
2f381252 2587numa: Dan Sully <daniel@cpan.org>
fc7ec1d9 2588
2f381252 2589obra: Jesse Vincent
2590
2591omega: Andreas Marienborg
51f0308d 2592
2f381252 2593phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
bdcb95ef 2594
6dae3eef 2595rafl: Florian Ragwitz <rafl@debian.org>
2596
2f381252 2597sky: Arthur Bergman
2598
2599the_jester: Jesse Sheidlower
2600
bb33cb06 2601t0m: Tomas Doran <bobtfish@bobtfish.net>
2602
2f381252 2603Ulf Edvinsson
51f0308d 2604
2f381252 2605willert: Sebastian Willert <willert@cpan.org>
51f0308d 2606
fc7ec1d9 2607=head1 LICENSE
2608
9ce5ab63 2609This library is free software, you can redistribute it and/or modify it under
41ca9ba7 2610the same terms as Perl itself.
fc7ec1d9 2611
2612=cut
2613
4090e3bb 2614no Moose;
2615
46d0346d 2616__PACKAGE__->meta->make_immutable;
2617
fc7ec1d9 26181;