4 use base 'Catalyst::Component';
6 use UNIVERSAL::require;
7 use Catalyst::Exception;
10 use Catalyst::Request::Upload;
11 use Catalyst::Response;
13 use Catalyst::Controller;
16 use Text::SimpleTable;
18 use Path::Class::File;
19 use Time::HiRes qw/gettimeofday tv_interval/;
21 use Scalar::Util qw/weaken blessed/;
22 use Tree::Simple qw/use_weak_refs/;
23 use Tree::Simple::Visitor::FindByUID;
27 __PACKAGE__->mk_accessors(
28 qw/counter request response state action stack namespace/
31 attributes->import( __PACKAGE__, \&namespace, 'lvalue' );
33 sub depth { scalar @{ shift->stack || [] }; }
40 # For backwards compatibility
41 *finalize_output = \&finalize_body;
46 our $RECURSION = 1000;
47 our $DETACH = "catalyst_detach\n";
49 require Module::Pluggable::Fast;
51 # Helper script generation
52 our $CATALYST_SCRIPT_GEN = 27;
54 __PACKAGE__->mk_classdata($_)
55 for qw/components arguments dispatcher engine log dispatcher_class
56 engine_class context_class request_class response_class setup_finished/;
58 __PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
59 __PACKAGE__->engine_class('Catalyst::Engine::CGI');
60 __PACKAGE__->request_class('Catalyst::Request');
61 __PACKAGE__->response_class('Catalyst::Response');
63 our $VERSION = '5.66';
66 my ( $class, @arguments ) = @_;
68 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
70 return unless $class eq 'Catalyst';
72 my $caller = caller(0);
74 unless ( $caller->isa('Catalyst') ) {
76 push @{"$caller\::ISA"}, $class, 'Catalyst::Controller';
79 $caller->arguments( [@arguments] );
85 Catalyst - The Elegant MVC Web Application Framework
89 # use the helper to start a new application
92 # add models, views, controllers
93 script/myapp_create.pl model Database DBIC dbi:SQLite:/path/to/db
94 script/myapp_create.pl view TT TT
95 script/myapp_create.pl controller Search
97 # built in testserver -- use -r to restart automatically on changes
98 script/myapp_server.pl
100 # command line testing interface
101 script/myapp_test.pl /yada
104 use Catalyst qw/-Debug/; # include plugins here as well
106 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
107 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
108 $c->stash->{template} = 'foo.tt'; # set the template
109 # lookup something from db -- stash vars are passed to TT
111 MyApp::Model::Database::Foo->search( { country => $args[0] } );
112 if ( $c->req->params->{bar} ) { # access GET or POST parameters
113 $c->forward( 'bar' ); # process another action
114 # do something else after forward returns
118 # The foo.tt TT template can use the stash data from the database
119 [% WHILE (item = data.next) %]
123 # called for /bar/of/soap, /bar/of/soap/10, etc.
124 sub bar : Path('/bar/of/soap') { ... }
126 # called for all actions, from the top-most controller downwards
128 my ( $self, $c ) = @_;
130 $c->res->redirect( '/login' ); # require login
131 return 0; # abort request and go immediately to end()
133 return 1; # success; carry on to next action
136 # called after all actions are finished
138 my ( $self, $c ) = @_;
139 if ( scalar @{ $c->error } ) { ... } # handle errors
140 return if $c->res->body; # already have a response
141 $c->forward( 'MyApp::View::TT' ); # render template
144 ### in MyApp/Controller/Foo.pm
145 # called for /foo/bar
146 sub bar : Local { ... }
148 # called for /blargle
149 sub blargle : Global { ... }
151 # an index action matches /foo, but not /foo/1, etc.
152 sub index : Private { ... }
154 ### in MyApp/Controller/Foo/Bar.pm
155 # called for /foo/bar/baz
156 sub baz : Local { ... }
158 # first MyApp auto is called, then Foo auto, then this
159 sub auto : Private { ... }
161 # powerful regular expression paths are also possible
162 sub details : Regex('^product/(\w+)/details$') {
163 my ( $self, $c ) = @_;
164 # extract the (\w+) from the URI
165 my $product = $c->req->snippets->[0];
168 See L<Catalyst::Manual::Intro> for additional information.
172 The key concept of Catalyst is DRY (Don't Repeat Yourself).
174 See L<Catalyst::Manual> for more documentation.
176 Catalyst plugins can be loaded by naming them as arguments to the "use
177 Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
178 plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
181 use Catalyst qw/My::Module/;
183 If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
184 fully qualify the name by using a unary plus:
188 +Fully::Qualified::Plugin::Name
191 Special flags like C<-Debug> and C<-Engine> can also be specified as
192 arguments when Catalyst is loaded:
194 use Catalyst qw/-Debug My::Module/;
196 The position of plugins and flags in the chain is important, because
197 they are loaded in exactly the order in which they appear.
199 The following flags are supported:
203 Enables debug output.
207 Forces Catalyst to use a specific engine. Omit the
208 C<Catalyst::Engine::> prefix of the engine name, i.e.:
210 use Catalyst qw/-Engine=CGI/;
214 Forces Catalyst to use a specific home directory, e.g.:
216 use Catalyst qw[-Home=/usr/sri];
224 =head2 INFORMATION ABOUT THE CURRENT REQUEST
228 Returns a L<Catalyst::Action> object for the current action, which
229 stringifies to the action name. See L<Catalyst::Action>.
233 Returns the namespace of the current action, i.e., the uri prefix
234 corresponding to the controller of the current action. For example:
236 # in Controller::Foo::Bar
237 $c->namespace; # returns 'foo/bar';
243 Returns the current L<Catalyst::Request> object. See
244 L<Catalyst::Request>.
246 =head2 PROCESSING AND RESPONSE TO THE CURRENT REQUEST
248 =head2 $c->forward( $action [, \@arguments ] )
250 =head2 $c->forward( $class, $method, [, \@arguments ] )
252 Forwards processing to a private action. If you give a class name but no
253 method, C<process()> is called. You may also optionally pass arguments
254 in an arrayref. The action will receive the arguments in C<@_> and
255 C<$c-E<gt>req-E<gt>args>. Upon returning from the function,
256 C<$c-E<gt>req-E<gt>args> will be restored to the previous values.
258 Any data C<return>ed from the action forwarded to, will be returned by the
261 my $foodata = $c->forward('/foo');
262 $c->forward('index');
263 $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/);
264 $c->forward('MyApp::View::TT');
268 sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
270 =head2 $c->detach( $action [, \@arguments ] )
272 =head2 $c->detach( $class, $method, [, \@arguments ] )
274 The same as C<forward>, but doesn't return.
278 sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
282 =head2 $c->error($error, ...)
284 =head2 $c->error($arrayref)
286 Returns an arrayref containing error messages. If Catalyst encounters an
287 error while processing a request, it stores the error in $c->error. This
288 method should not be used to store non-fatal error messages.
290 my @error = @{ $c->error };
294 $c->error('Something bad happened');
301 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
302 croak @$error unless ref $c;
303 push @{ $c->{error} }, @$error;
305 elsif ( defined $_[0] ) { $c->{error} = undef }
306 return $c->{error} || [];
309 =head2 $c->clear_errors
311 Clear errors. You probably don't want to clear the errors unless you are
312 implementing a custom error screen.
314 This is equivalent to running
329 Returns the current L<Catalyst::Response> object.
333 Returns a hashref to the stash, which may be used to store data and pass
334 it between components during a request. You can also set hash keys by
335 passing arguments. The stash is automatically sent to the view. The
336 stash is cleared at the end of a request; it cannot be used for
339 $c->stash->{foo} = $bar;
340 $c->stash( { moose => 'majestic', qux => 0 } );
341 $c->stash( bar => 1, gorch => 2 ); # equivalent to passing a hashref
343 # stash is automatically passed to the view for use in a template
344 $c->forward( 'MyApp::V::TT' );
351 my $stash = @_ > 1 ? {@_} : $_[0];
352 while ( my ( $key, $val ) = each %$stash ) {
353 $c->{stash}->{$key} = $val;
361 Contains the return value of the last executed action.
367 my ( $c, @names ) = @_;
369 foreach my $name (@names) {
370 foreach my $component ( keys %{ $c->components } ) {
371 return $c->components->{$component} if $component =~ /$name/i;
378 # try explicit component names
380 my ( $c, @names ) = @_;
382 foreach my $try (@names) {
383 return $c->components->{$try} if ( exists $c->components->{$try} );
389 # like component, but try just these prefixes before regex searching,
390 # and do not try to return "sort keys %{ $c->components }"
392 my ( $c, $name, @prefixes ) = @_;
394 my $appclass = ref $c || $c;
396 my @names = map { "${appclass}::${_}::${name}" } @prefixes;
398 my $comp = $c->_comp_explicit(@names);
399 return $comp if defined($comp);
400 $comp = $c->_comp_search($name);
404 # Find possible names for a prefix
407 my ( $c, @prefixes ) = @_;
409 my $appclass = ref $c || $c;
411 my @pre = map { "${appclass}::${_}::" } @prefixes;
415 COMPONENT: foreach my $comp ($c->component) {
416 foreach my $p (@pre) {
417 if ($comp =~ s/^$p//) {
427 # Return a component if only one matches.
429 my ( $c, @prefixes ) = @_;
431 my $appclass = ref $c || $c;
433 my ( $comp, $rest ) =
434 map { $c->_comp_search("^${appclass}::${_}::") } @prefixes;
435 return $comp unless $rest;
438 # Filter a component before returning by calling ACCEPT_CONTEXT if available
439 sub _filter_component {
440 my ( $c, $comp, @args ) = @_;
441 if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
442 return $comp->ACCEPT_CONTEXT( $c, @args );
444 else { return $comp }
447 =head2 COMPONENT ACCESSORS
449 =head2 $c->comp($name)
451 =head2 $c->component($name)
453 Gets a component object by name. This method is no longer recommended,
454 unless you want to get a specific component by full
455 class. C<$c-E<gt>controller>, C<$c-E<gt>model>, and C<$c-E<gt>view>
456 should be used instead.
467 my $appclass = ref $c || $c;
470 $name, "${appclass}::${name}",
471 map { "${appclass}::${_}::${name}" }
472 qw/Model M Controller C View V/
475 my $comp = $c->_comp_explicit(@names);
476 return $c->_filter_component( $comp, @_ ) if defined($comp);
478 $comp = $c->_comp_search($name);
479 return $c->_filter_component( $comp, @_ ) if defined($comp);
482 return sort keys %{ $c->components };
485 =head2 $c->controller($name)
487 Gets a L<Catalyst::Controller> instance by name.
489 $c->controller('Foo')->do_stuff;
491 If name is omitted, will return the controller for the dispatched action.
496 my ( $c, $name, @args ) = @_;
497 return $c->_filter_component( $c->_comp_prefixes( $name, qw/Controller C/ ),
500 return $c->component( $c->action->class );
503 =head2 $c->controllers
505 Returns the available names which can be passed to $c->controller
511 return $c->_comp_names(qw/Controller C/);
514 =head2 $c->model($name)
516 Gets a L<Catalyst::Model> instance by name.
518 $c->model('Foo')->do_stuff;
520 If the name is omitted, it will look for a config setting 'default_model',
521 or check if there is only one model, and forward to it if that's the case.
526 my ( $c, $name, @args ) = @_;
527 return $c->_filter_component( $c->_comp_prefixes( $name, qw/Model M/ ),
530 return $c->component( $c->config->{default_model} )
531 if $c->config->{default_model};
532 return $c->_filter_component( $c->_comp_singular(qw/Model M/), @args );
538 Returns the available names which can be passed to $c->model
544 return $c->_comp_names(qw/Model M/);
547 =head2 $c->view($name)
549 Gets a L<Catalyst::View> instance by name.
551 $c->view('Foo')->do_stuff;
553 If the name is omitted, it will look for a config setting 'default_view',
554 or check if there is only one view, and forward to it if that's the case.
559 my ( $c, $name, @args ) = @_;
560 return $c->_filter_component( $c->_comp_prefixes( $name, qw/View V/ ),
563 return $c->component( $c->config->{default_view} )
564 if $c->config->{default_view};
565 return $c->_filter_component( $c->_comp_singular(qw/View V/) );
570 Returns the available names which can be passed to $c->view
576 return $c->_comp_names(qw/View V/);
579 =head2 Class data and helper classes
583 Returns or takes a hashref containing the application's configuration.
585 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
587 You can also use a L<YAML> config file like myapp.yml in your
588 applications home directory.
591 db: dsn:SQLite:foo.db
598 $c->log->warn("Setting config after setup has been run is not a good idea.")
599 if ( @_ and $c->setup_finished );
601 $c->NEXT::config(@_);
606 Overload to enable debug messages (same as -Debug option).
612 =head2 $c->dispatcher
614 Returns the dispatcher instance. Stringifies to class name. See
615 L<Catalyst::Dispatcher>.
619 Returns the engine instance. Stringifies to the class name. See
624 Returns the logging object instance. Unless it is already set, Catalyst sets
625 this up with a L<Catalyst::Log> object. To use your own log class, set the
626 logger with the C<< __PACKAGE__->log >> method prior to calling
627 C<< __PACKAGE__->setup >>.
629 __PACKAGE__->log( MyLogger->new );
634 $c->log->info( 'Now logging with my own logger!' );
636 Your log class should implement the methods described in the
637 L<Catalyst::Log> man page.
641 =head2 UTILITY METHODS
643 =head2 $c->path_to(@path)
645 Merges C<@path> with C<$c-E<gt>config-E<gt>{home}> and returns a
646 L<Path::Class> object.
650 $c->path_to( 'db', 'sqlite.db' );
655 my ( $c, @path ) = @_;
656 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
657 if ( -d $path ) { return $path }
658 else { return Path::Class::File->new( $c->config->{home}, @path ) }
661 =head2 $c->plugin( $name, $class, @args )
663 Helper method for plugins. It creates a classdata accessor/mutator and
664 loads and instantiates the given class.
666 MyApp->plugin( 'prototype', 'HTML::Prototype' );
668 $c->prototype->define_javascript_functions;
673 my ( $class, $name, $plugin, @args ) = @_;
674 $class->_register_plugin( $plugin, 1 );
676 eval { $plugin->import };
677 $class->mk_classdata($name);
679 eval { $obj = $plugin->new(@args) };
682 Catalyst::Exception->throw( message =>
683 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
687 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
693 Initializes the dispatcher and engine, loads any plugins, and loads the
694 model, view, and controller components. You may also specify an array
695 of plugins to load here, if you choose to not load them in the C<use
699 MyApp->setup( qw/-Debug/ );
704 my ( $class, @arguments ) = @_;
706 unless ( $class->isa('Catalyst') ) {
708 Catalyst::Exception->throw(
709 message => qq/'$class' does not inherit from Catalyst/ );
712 if ( $class->arguments ) {
713 @arguments = ( @arguments, @{ $class->arguments } );
719 foreach (@arguments) {
723 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
725 elsif (/^-(\w+)=?(.*)$/) {
726 $flags->{ lc $1 } = $2;
729 push @{ $flags->{plugins} }, $_;
733 $class->setup_home( delete $flags->{home} );
735 $class->setup_log( delete $flags->{log} );
736 $class->setup_plugins( delete $flags->{plugins} );
737 $class->setup_dispatcher( delete $flags->{dispatcher} );
738 $class->setup_engine( delete $flags->{engine} );
740 for my $flag ( sort keys %{$flags} ) {
742 if ( my $code = $class->can( 'setup_' . $flag ) ) {
743 &$code( $class, delete $flags->{$flag} );
746 $class->log->warn(qq/Unknown flag "$flag"/);
751 <<"EOF") if ( $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::CATALYST_SCRIPT_GEN ) );
752 You are running an old script!
754 Please update by running (this will overwrite existing files):
755 catalyst.pl -force -scripts $class
757 or (this will not overwrite existing files):
758 catalyst.pl -scripts $class
761 if ( $class->debug ) {
768 map { $_ . ' ' . ( $_->VERSION || '' ) }
769 grep { /^Catalyst::Plugin/ } @{"$class\::ISA"};
773 my $t = Text::SimpleTable->new(76);
774 $t->row($_) for @plugins;
775 $class->log->debug( "Loaded plugins:\n" . $t->draw );
778 my $dispatcher = $class->dispatcher;
779 my $engine = $class->engine;
780 my $home = $class->config->{home};
782 $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
783 $class->log->debug(qq/Loaded engine "$engine"/);
787 ? $class->log->debug(qq/Found home "$home"/)
788 : $class->log->debug(qq/Home "$home" doesn't exist/)
789 : $class->log->debug(q/Couldn't find home/);
794 no warnings qw/redefine/;
795 local *setup = sub { };
799 # Initialize our data structure
800 $class->components( {} );
802 $class->setup_components;
804 if ( $class->debug ) {
805 my $t = Text::SimpleTable->new( [ 65, 'Class' ], [ 8, 'Type' ] );
806 for my $comp ( sort keys %{ $class->components } ) {
807 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
808 $t->row( $comp, $type );
810 $class->log->debug( "Loaded components:\n" . $t->draw )
811 if ( keys %{ $class->components } );
814 # Add our self to components, since we are also a component
815 $class->components->{$class} = $class;
817 $class->setup_actions;
819 if ( $class->debug ) {
820 my $name = $class->config->{name} || 'Application';
821 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
823 $class->log->_flush() if $class->log->can('_flush');
825 $class->setup_finished(1);
828 =head2 $c->uri_for( $path, @args?, \%query_values? )
830 Merges path with C<$c-E<gt>request-E<gt>base> for absolute uri's and
831 with C<$c-E<gt>namespace> for relative uri's, then returns a
832 normalized L<URI> object. If any args are passed, they are added at the
833 end of the path. If the last argument to uri_for is a hash reference,
834 it is assumed to contain GET parameter key/value pairs, which will be
835 appended to the URI in standard fashion.
840 my ( $c, $path, @args ) = @_;
841 my $base = $c->request->base->clone;
842 my $basepath = $base->path;
843 $basepath =~ s/\/$//;
845 my $namespace = $c->namespace;
847 # massage namespace, empty if absolute path
848 $namespace =~ s/^\///;
849 $namespace .= '/' if $namespace;
851 $namespace = '' if $path =~ /^\//;
855 ( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
857 # join args with '/', or a blank string
858 my $args = ( scalar @args ? '/' . join( '/', @args ) : '' );
859 $args =~ s/^\/// unless $path;
861 URI->new_abs( URI->new_abs( "$path$args", "$basepath$namespace" ), $base )
863 $res->query_form(%$params);
867 =head2 $c->welcome_message
869 Returns the Catalyst welcome HTML page.
873 sub welcome_message {
875 my $name = $c->config->{name};
876 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
877 my $prefix = Catalyst::Utils::appprefix( ref $c );
878 $c->response->content_type('text/html; charset=utf-8');
880 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
881 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
882 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
884 <meta http-equiv="Content-Language" content="en" />
885 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
886 <title>$name on Catalyst $VERSION</title>
887 <style type="text/css">
890 background-color: #eee;
899 background-color: #ccc;
900 border: 1px solid #aaa;
901 -moz-border-radius: 10px;
906 font-family: verdana, tahoma, sans-serif;
909 font-family: verdana, tahoma, sans-serif;
912 text-decoration: none;
914 border-bottom: 1px dotted #bbb;
916 :link:hover, :visited:hover {
929 background-color: #fff;
930 border: 1px solid #aaa;
931 -moz-border-radius: 10px;
957 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
962 <img src="$logo" alt="Catalyst Logo" />
964 <p>Welcome to the wonderful world of Catalyst.
965 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
966 framework will make web development something you had
967 never expected it to be: Fun, rewarding, and quick.</p>
968 <h2>What to do now?</h2>
969 <p>That really depends on what <b>you</b> want to do.
970 We do, however, provide you with a few starting points.</p>
971 <p>If you want to jump right into web development with Catalyst
972 you might want to check out the documentation.</p>
973 <pre><code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
974 perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
975 perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
976 <h2>What to do next?</h2>
977 <p>Next it's time to write an actual application. Use the
978 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
979 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a>, and
980 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>;
981 they can save you a lot of work.</p>
982 <pre><code>script/${prefix}_create.pl -help</code></pre>
983 <p>Also, be sure to check out the vast and growing
984 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&mode=all">plugins for Catalyst on CPAN</a>;
985 you are likely to find what you need there.
989 <p>Catalyst has a very active community. Here are the main places to
990 get in touch with us.</p>
993 <a href="http://dev.catalyst.perl.org">Wiki</a>
996 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
999 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
1002 <h2>In conclusion</h2>
1003 <p>The Catalyst team hopes you will enjoy using Catalyst as much
1004 as we enjoyed making it. Please contact us if you have ideas
1005 for improvement or other feedback.</p>
1013 =head1 INTERNAL METHODS
1015 These methods are not meant to be used by end users.
1017 =head2 $c->components
1019 Returns a hash of components.
1021 =head2 $c->context_class
1023 Returns or sets the context class.
1027 Returns a hashref containing coderefs and execution counts (needed for
1028 deep recursion detection).
1032 Returns the number of actions on the current internal execution stack.
1036 Dispatches a request to actions.
1040 sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
1042 =head2 $c->dispatcher_class
1044 Returns or sets the dispatcher class.
1046 =head2 $c->dump_these
1048 Returns a list of 2-element array references (name, structure) pairs
1049 that will be dumped on the error page in debug mode.
1055 [ Request => $c->req ], [ Response => $c->res ], [ Stash => $c->stash ],;
1058 =head2 $c->engine_class
1060 Returns or sets the engine class.
1062 =head2 $c->execute( $class, $coderef )
1064 Execute a coderef in given class and catch exceptions. Errors are available
1070 my ( $c, $class, $code ) = @_;
1071 $class = $c->component($class) || $class;
1074 if ( $c->depth >= $RECURSION ) {
1075 my $action = "$code";
1076 $action = "/$action" unless $action =~ /\-\>/;
1077 my $error = qq/Deep recursion detected calling "$action"/;
1078 $c->log->error($error);
1085 my $action = "$code";
1086 $action = "/$action" unless $action =~ /\-\>/;
1087 $c->counter->{"$code"}++;
1089 # determine if the call was the result of a forward
1090 # this is done by walking up the call stack and looking for a calling
1091 # sub of Catalyst::forward before the eval
1093 for my $index ( 1 .. 10 ) {
1095 if ( ( caller($index) )[0] eq 'Catalyst'
1096 && ( caller($index) )[3] eq '(eval)' );
1098 if ( ( caller($index) )[3] =~ /forward$/ ) {
1099 $callsub = ( caller($index) )[3];
1100 $action = "-> $action";
1105 my $node = Tree::Simple->new(
1108 elapsed => undef, # to be filled in later
1111 $node->setUID( "$code" . $c->counter->{"$code"} );
1113 unless ( ( $code->name =~ /^_.*/ )
1114 && ( !$c->config->{show_internal_actions} ) )
1117 # is this a root-level call or a forwarded call?
1118 if ( $callsub =~ /forward$/ ) {
1120 # forward, locate the caller
1121 if ( my $parent = $c->stack->[-1] ) {
1122 my $visitor = Tree::Simple::Visitor::FindByUID->new;
1123 $visitor->searchForUID(
1124 "$parent" . $c->counter->{"$parent"} );
1125 $c->{stats}->accept($visitor);
1126 if ( my $result = $visitor->getResult ) {
1127 $result->addChild($node);
1132 # forward with no caller may come from a plugin
1133 $c->{stats}->addChild($node);
1139 $c->{stats}->addChild($node);
1144 push( @{ $c->stack }, $code );
1147 $start = [gettimeofday] if $c->debug;
1148 eval { $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 ) };
1149 $elapsed = tv_interval($start) if $c->debug;
1152 unless ( ( $code->name =~ /^_.*/ )
1153 && ( !$c->config->{show_internal_actions} ) )
1156 # FindByUID uses an internal die, so we save the existing error
1159 # locate the node in the tree and update the elapsed time
1160 my $visitor = Tree::Simple::Visitor::FindByUID->new;
1161 $visitor->searchForUID( "$code" . $c->counter->{"$code"} );
1162 $c->{stats}->accept($visitor);
1163 if ( my $result = $visitor->getResult ) {
1164 my $value = $result->getNodeValue;
1165 $value->{elapsed} = sprintf( '%fs', $elapsed );
1166 $result->setNodeValue($value);
1170 $@ = $error || undef;
1173 my $last = ${ $c->stack }[-1];
1174 pop( @{ $c->stack } );
1176 if ( my $error = $@ ) {
1177 if ( $error eq $DETACH ) { die $DETACH if $c->depth > 1 }
1179 unless ( ref $error ) {
1181 my $class = $last->class;
1182 my $name = $last->name;
1183 $error = qq/Caught exception in $class->$name "$error"/;
1194 Finalizes the request.
1201 for my $error ( @{ $c->error } ) {
1202 $c->log->error($error);
1205 # Allow engine to handle finalize flow (for POE)
1206 if ( $c->engine->can('finalize') ) {
1207 $c->engine->finalize( $c );
1211 $c->finalize_uploads;
1214 if ( $#{ $c->error } >= 0 ) {
1218 $c->finalize_headers;
1221 if ( $c->request->method eq 'HEAD' ) {
1222 $c->response->body('');
1228 return $c->response->status;
1231 =head2 $c->finalize_body
1237 sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
1239 =head2 $c->finalize_cookies
1245 sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
1247 =head2 $c->finalize_error
1253 sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
1255 =head2 $c->finalize_headers
1261 sub finalize_headers {
1264 # Check if we already finalized headers
1265 return if $c->response->{_finalized_headers};
1268 if ( my $location = $c->response->redirect ) {
1269 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
1270 $c->response->header( Location => $location );
1274 if ( $c->response->body && !$c->response->content_length ) {
1276 # get the length from a filehandle
1277 if ( blessed( $c->response->body ) && $c->response->body->can('read') )
1279 if ( my $stat = stat $c->response->body ) {
1280 $c->response->content_length( $stat->size );
1283 $c->log->warn('Serving filehandle without a content-length');
1287 $c->response->content_length( bytes::length( $c->response->body ) );
1292 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
1293 $c->response->headers->remove_header("Content-Length");
1294 $c->response->body('');
1297 $c->finalize_cookies;
1299 $c->engine->finalize_headers( $c, @_ );
1302 $c->response->{_finalized_headers} = 1;
1305 =head2 $c->finalize_output
1307 An alias for finalize_body.
1309 =head2 $c->finalize_read
1311 Finalizes the input after reading is complete.
1315 sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1317 =head2 $c->finalize_uploads
1319 Finalizes uploads. Cleans up any temporary files.
1323 sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1325 =head2 $c->get_action( $action, $namespace )
1327 Gets an action in a given namespace.
1331 sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
1333 =head2 $c->get_actions( $action, $namespace )
1335 Gets all actions of a given name in a namespace and all parent
1340 sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1342 =head2 $c->handle_request( $class, @arguments )
1344 Called to handle each HTTP request.
1348 sub handle_request {
1349 my ( $class, @arguments ) = @_;
1351 # Always expect worst case!
1354 my $stats = ( $class->debug ) ? Tree::Simple->new: q{};
1357 my $c = $class->prepare(@arguments);
1358 $c->{stats} = $stats;
1360 return $c->finalize;
1363 if ( $class->debug ) {
1364 my $start = [gettimeofday];
1365 $status = &$handler;
1366 my $elapsed = tv_interval $start;
1367 $elapsed = sprintf '%f', $elapsed;
1368 my $av = sprintf '%.3f',
1369 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
1370 my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] );
1375 my $stat = $action->getNodeValue;
1376 $t->row( ( q{ } x $action->getDepth ) . $stat->{action},
1377 $stat->{elapsed} || '??' );
1382 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
1384 else { $status = &$handler }
1388 if ( my $error = $@ ) {
1390 $class->log->error(qq/Caught exception in engine "$error"/);
1394 $class->log->_flush() if $class->log->can('_flush');
1398 =head2 $c->prepare( @arguments )
1400 Creates a Catalyst context from an engine-specific request (Apache, CGI,
1406 my ( $class, @arguments ) = @_;
1408 $class->context_class( ref $class || $class ) unless $class->context_class;
1409 my $c = $class->context_class->new(
1413 request => $class->request_class->new(
1416 body_parameters => {},
1418 headers => HTTP::Headers->new,
1420 query_parameters => {},
1426 response => $class->response_class->new(
1430 headers => HTTP::Headers->new(),
1439 # For on-demand data
1440 $c->request->{_context} = $c;
1441 $c->response->{_context} = $c;
1442 weaken( $c->request->{_context} );
1443 weaken( $c->response->{_context} );
1446 my $secs = time - $START || 1;
1447 my $av = sprintf '%.3f', $COUNT / $secs;
1448 $c->log->debug('**********************************');
1449 $c->log->debug("* Request $COUNT ($av/s) [$$]");
1450 $c->log->debug('**********************************');
1451 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1454 # Allow engine to direct the prepare flow (for POE)
1455 if ( $c->engine->can('prepare') ) {
1456 $c->engine->prepare( $c, @arguments );
1459 $c->prepare_request(@arguments);
1460 $c->prepare_connection;
1461 $c->prepare_query_parameters;
1462 $c->prepare_headers;
1463 $c->prepare_cookies;
1467 $c->prepare_body unless $c->config->{parse_on_demand};
1470 my $method = $c->req->method || '';
1471 my $path = $c->req->path || '';
1472 my $address = $c->req->address || '';
1474 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
1482 =head2 $c->prepare_action
1488 sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1490 =head2 $c->prepare_body
1492 Prepares message body.
1499 # Do we run for the first time?
1500 return if defined $c->request->{_body};
1502 # Initialize on-demand data
1503 $c->engine->prepare_body( $c, @_ );
1504 $c->prepare_parameters;
1505 $c->prepare_uploads;
1507 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
1508 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
1509 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1510 my $param = $c->req->body_parameters->{$key};
1511 my $value = defined($param) ? $param : '';
1513 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1515 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1519 =head2 $c->prepare_body_chunk( $chunk )
1521 Prepares a chunk of data before sending it to L<HTTP::Body>.
1525 sub prepare_body_chunk {
1527 $c->engine->prepare_body_chunk( $c, @_ );
1530 =head2 $c->prepare_body_parameters
1532 Prepares body parameters.
1536 sub prepare_body_parameters {
1538 $c->engine->prepare_body_parameters( $c, @_ );
1541 =head2 $c->prepare_connection
1543 Prepares connection.
1547 sub prepare_connection {
1549 $c->engine->prepare_connection( $c, @_ );
1552 =head2 $c->prepare_cookies
1558 sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1560 =head2 $c->prepare_headers
1566 sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1568 =head2 $c->prepare_parameters
1570 Prepares parameters.
1574 sub prepare_parameters {
1576 $c->prepare_body_parameters;
1577 $c->engine->prepare_parameters( $c, @_ );
1580 =head2 $c->prepare_path
1582 Prepares path and base.
1586 sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1588 =head2 $c->prepare_query_parameters
1590 Prepares query parameters.
1594 sub prepare_query_parameters {
1597 $c->engine->prepare_query_parameters( $c, @_ );
1599 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
1600 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
1601 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1602 my $param = $c->req->query_parameters->{$key};
1603 my $value = defined($param) ? $param : '';
1605 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1607 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1611 =head2 $c->prepare_read
1613 Prepares the input for reading.
1617 sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1619 =head2 $c->prepare_request
1621 Prepares the engine request.
1625 sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1627 =head2 $c->prepare_uploads
1633 sub prepare_uploads {
1636 $c->engine->prepare_uploads( $c, @_ );
1638 if ( $c->debug && keys %{ $c->request->uploads } ) {
1639 my $t = Text::SimpleTable->new(
1645 for my $key ( sort keys %{ $c->request->uploads } ) {
1646 my $upload = $c->request->uploads->{$key};
1647 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
1648 $t->row( $key, $u->filename, $u->type, $u->size );
1651 $c->log->debug( "File Uploads are:\n" . $t->draw );
1655 =head2 $c->prepare_write
1657 Prepares the output for writing.
1661 sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1663 =head2 $c->request_class
1665 Returns or sets the request class.
1667 =head2 $c->response_class
1669 Returns or sets the response class.
1671 =head2 $c->read( [$maxlength] )
1673 Reads a chunk of data from the request body. This method is designed to
1674 be used in a while loop, reading C<$maxlength> bytes on every call.
1675 C<$maxlength> defaults to the size of the request if not specified.
1677 You have to set C<MyApp-E<gt>config-E<gt>{parse_on_demand}> to use this
1682 sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1690 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1692 =head2 $c->set_action( $action, $code, $namespace, $attrs )
1694 Sets an action in a given namespace.
1698 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1700 =head2 $c->setup_actions($component)
1702 Sets up actions for a component.
1706 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1708 =head2 $c->setup_components
1714 sub setup_components {
1717 my $callback = sub {
1718 my ( $component, $context ) = @_;
1720 unless ( $component->can('COMPONENT') ) {
1724 my $suffix = Catalyst::Utils::class2classsuffix($component);
1725 my $config = $class->config->{$suffix} || {};
1729 eval { $instance = $component->COMPONENT( $context, $config ); };
1731 if ( my $error = $@ ) {
1735 Catalyst::Exception->throw( message =>
1736 qq/Couldn't instantiate component "$component", "$error"/ );
1739 Catalyst::Exception->throw( message =>
1740 qq/Couldn't instantiate component "$component", "COMPONENT() didn't return a object"/
1742 unless ref $instance;
1746 eval "package $class;\n" . q!Module::Pluggable::Fast->import(
1747 name => '_catalyst_components',
1749 "$class\::Controller", "$class\::C",
1750 "$class\::Model", "$class\::M",
1751 "$class\::View", "$class\::V"
1753 callback => $callback
1757 if ( my $error = $@ ) {
1761 Catalyst::Exception->throw(
1762 message => qq/Couldn't load components "$error"/ );
1765 for my $component ( $class->_catalyst_components($class) ) {
1766 $class->components->{ ref $component || $component } = $component;
1770 =head2 $c->setup_dispatcher
1776 sub setup_dispatcher {
1777 my ( $class, $dispatcher ) = @_;
1780 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1783 if ( $ENV{CATALYST_DISPATCHER} ) {
1784 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1787 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1789 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1792 unless ($dispatcher) {
1793 $dispatcher = $class->dispatcher_class;
1796 $dispatcher->require;
1799 Catalyst::Exception->throw(
1800 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1803 # dispatcher instance
1804 $class->dispatcher( $dispatcher->new );
1807 =head2 $c->setup_engine
1814 my ( $class, $engine ) = @_;
1817 $engine = 'Catalyst::Engine::' . $engine;
1820 if ( $ENV{CATALYST_ENGINE} ) {
1821 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1824 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1825 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1828 if ( $ENV{MOD_PERL} ) {
1830 # create the apache method
1833 *{"$class\::apache"} = sub { shift->engine->apache };
1836 my ( $software, $version ) =
1837 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1840 $version =~ s/(\.[^.]+)\./$1/g;
1842 if ( $software eq 'mod_perl' ) {
1846 if ( $version >= 1.99922 ) {
1847 $engine = 'Catalyst::Engine::Apache2::MP20';
1850 elsif ( $version >= 1.9901 ) {
1851 $engine = 'Catalyst::Engine::Apache2::MP19';
1854 elsif ( $version >= 1.24 ) {
1855 $engine = 'Catalyst::Engine::Apache::MP13';
1859 Catalyst::Exception->throw( message =>
1860 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1865 # install the correct mod_perl handler
1866 if ( $version >= 1.9901 ) {
1867 *handler = sub : method {
1868 shift->handle_request(@_);
1872 *handler = sub ($$) { shift->handle_request(@_) };
1877 elsif ( $software eq 'Zeus-Perl' ) {
1878 $engine = 'Catalyst::Engine::Zeus';
1882 Catalyst::Exception->throw(
1883 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1888 $engine = $class->engine_class;
1894 Catalyst::Exception->throw( message =>
1895 qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1899 # check for old engines that are no longer compatible
1901 if ( $engine->isa('Catalyst::Engine::Apache')
1902 && !Catalyst::Engine::Apache->VERSION )
1907 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
1908 && Catalyst::Engine::Server->VERSION le '0.02' )
1913 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1914 && $engine->VERSION eq '0.01' )
1919 elsif ($engine->isa('Catalyst::Engine::Zeus')
1920 && $engine->VERSION eq '0.01' )
1926 Catalyst::Exception->throw( message =>
1927 qq/Engine "$engine" is not supported by this version of Catalyst/
1932 $class->engine( $engine->new );
1935 =head2 $c->setup_home
1937 Sets up the home directory.
1942 my ( $class, $home ) = @_;
1944 if ( $ENV{CATALYST_HOME} ) {
1945 $home = $ENV{CATALYST_HOME};
1948 if ( $ENV{ uc($class) . '_HOME' } ) {
1949 $home = $ENV{ uc($class) . '_HOME' };
1953 $home = Catalyst::Utils::home($class);
1957 $class->config->{home} ||= $home;
1958 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
1962 =head2 $c->setup_log
1969 my ( $class, $debug ) = @_;
1971 unless ( $class->log ) {
1972 $class->log( Catalyst::Log->new );
1975 my $app_flag = Catalyst::Utils::class2env($class) . '_DEBUG';
1978 ( defined( $ENV{CATALYST_DEBUG} ) || defined( $ENV{$app_flag} ) )
1979 ? ( $ENV{CATALYST_DEBUG} || $ENV{$app_flag} )
1984 *{"$class\::debug"} = sub { 1 };
1985 $class->log->debug('Debug messages enabled');
1989 =head2 $c->setup_plugins
1995 =head2 $c->registered_plugins
1997 Returns a sorted list of the plugins which have either been stated in the
1998 import list or which have been added via C<< MyApp->plugin(@args); >>.
2000 If passed a given plugin name, it will report a boolean value indicating
2001 whether or not that plugin is loaded. A fully qualified name is required if
2002 the plugin name does not begin with C<Catalyst::Plugin::>.
2004 if ($c->registered_plugins('Some::Plugin')) {
2012 sub registered_plugins {
2014 return sort keys %{ $proto->_plugins } unless @_;
2016 return 1 if exists $proto->_plugins->{$plugin};
2017 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
2020 sub _register_plugin {
2021 my ( $proto, $plugin, $instant ) = @_;
2022 my $class = ref $proto || $proto;
2026 if ( my $error = $@ ) {
2027 my $type = $instant ? "instant " : '';
2028 Catalyst::Exception->throw(
2029 message => qq/Couldn't load ${type}plugin "$plugin", $error/ );
2032 $proto->_plugins->{$plugin} = 1;
2035 unshift @{"$class\::ISA"}, $plugin;
2041 my ( $class, $plugins ) = @_;
2043 $class->_plugins( {} ) unless $class->_plugins;
2045 for my $plugin ( reverse @$plugins ) {
2047 unless ( $plugin =~ s/\A\+// ) {
2048 $plugin = "Catalyst::Plugin::$plugin";
2051 $class->_register_plugin($plugin);
2058 Returns an arrayref of the internal execution stack (actions that are currently
2061 =head2 $c->write( $data )
2063 Writes $data to the output stream. When using this method directly, you
2064 will need to manually set the C<Content-Length> header to the length of
2065 your output data, if known.
2072 # Finalize headers if someone manually writes output
2073 $c->finalize_headers;
2075 return $c->engine->write( $c, @_ );
2080 Returns the Catalyst version number. Mostly useful for "powered by"
2081 messages in template systems.
2085 sub version { return $Catalyst::VERSION }
2087 =head1 INTERNAL ACTIONS
2089 Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
2090 C<_ACTION>, and C<_END>. These are by default not shown in the private
2091 action table, but you can make them visible with a config parameter.
2093 MyApp->config->{show_internal_actions} = 1;
2095 =head1 CASE SENSITIVITY
2097 By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> is
2098 mapped to C</foo/bar>. You can activate case sensitivity with a config
2101 MyApp->config->{case_sensitive} = 1;
2103 This causes C<MyApp::C::Foo::Bar> to map to C</Foo/Bar>.
2105 =head1 ON-DEMAND PARSER
2107 The request body is usually parsed at the beginning of a request,
2108 but if you want to handle input yourself or speed things up a bit,
2109 you can enable on-demand parsing with a config parameter.
2111 MyApp->config->{parse_on_demand} = 1;
2113 =head1 PROXY SUPPORT
2115 Many production servers operate using the common double-server approach,
2116 with a lightweight frontend web server passing requests to a larger
2117 backend server. An application running on the backend server must deal
2118 with two problems: the remote user always appears to be C<127.0.0.1> and
2119 the server's hostname will appear to be C<localhost> regardless of the
2120 virtual host that the user connected through.
2122 Catalyst will automatically detect this situation when you are running
2123 the frontend and backend servers on the same machine. The following
2124 changes are made to the request.
2126 $c->req->address is set to the user's real IP address, as read from
2127 the HTTP X-Forwarded-For header.
2129 The host value for $c->req->base and $c->req->uri is set to the real
2130 host, as read from the HTTP X-Forwarded-Host header.
2132 Obviously, your web server must support these headers for this to work.
2134 In a more complex server farm environment where you may have your
2135 frontend proxy server(s) on different machines, you will need to set a
2136 configuration option to tell Catalyst to read the proxied data from the
2139 MyApp->config->{using_frontend_proxy} = 1;
2141 If you do not wish to use the proxy support at all, you may set:
2143 MyApp->config->{ignore_frontend_proxy} = 1;
2145 =head1 THREAD SAFETY
2147 Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
2148 and the standalone forking HTTP server on Windows. We believe the Catalyst
2149 core to be thread-safe.
2151 If you plan to operate in a threaded environment, remember that all other
2152 modules you are using must also be thread-safe. Some modules, most notably
2153 L<DBD::SQLite>, are not thread-safe.
2159 Join #catalyst on irc.perl.org.
2163 http://lists.rawmode.org/mailman/listinfo/catalyst
2164 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
2168 http://catalyst.perl.org
2172 http://dev.catalyst.perl.org
2176 =head2 L<Task::Catalyst> - All you need to start with Catalyst
2178 =head2 L<Catalyst::Manual> - The Catalyst Manual
2180 =head2 L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
2182 =head2 L<Catalyst::Engine> - Core engine
2184 =head2 L<Catalyst::Log> - Log class.
2186 =head2 L<Catalyst::Request> - Request object
2188 =head2 L<Catalyst::Response> - Response object
2190 =head2 L<Catalyst::Test> - The test suite.
2262 Sebastian Riedel, C<sri@oook.de>
2266 This library is free software, you can redistribute it and/or modify it under
2267 the same terms as Perl itself.