4 use base 'Catalyst::Base';
6 use UNIVERSAL::require;
7 use Catalyst::Exception;
10 use Catalyst::Request::Upload;
11 use Catalyst::Response;
14 use Text::SimpleTable;
16 use Time::HiRes qw/gettimeofday tv_interval/;
18 use Scalar::Util qw/weaken/;
21 __PACKAGE__->mk_accessors(
22 qw/counter request response state action stack namespace/
25 attributes->import( __PACKAGE__, \&namespace, 'lvalue' );
27 sub depth { scalar @{ shift->stack || [] }; }
34 # For backwards compatibility
35 *finalize_output = \&finalize_body;
40 our $RECURSION = 1000;
41 our $DETACH = "catalyst_detach\n";
43 require Module::Pluggable::Fast;
45 # Helper script generation
46 our $CATALYST_SCRIPT_GEN = 11;
48 __PACKAGE__->mk_classdata($_)
49 for qw/components arguments dispatcher engine log dispatcher_class
50 engine_class context_class request_class response_class/;
52 __PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
53 __PACKAGE__->engine_class('Catalyst::Engine::CGI');
54 __PACKAGE__->request_class('Catalyst::Request');
55 __PACKAGE__->response_class('Catalyst::Response');
57 our $VERSION = '5.49_04';
60 my ( $class, @arguments ) = @_;
62 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
64 return unless $class eq 'Catalyst';
66 my $caller = caller(0);
68 unless ( $caller->isa('Catalyst') ) {
70 push @{"$caller\::ISA"}, $class;
73 $caller->arguments( [@arguments] );
79 Catalyst - The Elegant MVC Web Application Framework
83 # use the helper to start a new application
87 # add models, views, controllers
88 script/myapp_create.pl model Something
89 script/myapp_create.pl view Stuff
90 script/myapp_create.pl controller Yada
92 # built in testserver -- use -r to restart automatically on changes
93 script/myapp_server.pl
95 # command line interface
96 script/myapp_test.pl /yada
101 use Catalyst qw/My::Module My::OtherModule/;
103 use Catalyst '-Debug';
105 use Catalyst qw/-Debug -Engine=CGI/;
107 sub default : Private { $_[1]->res->output('Hello') } );
109 sub index : Path('/index.html') {
110 my ( $self, $c ) = @_;
111 $c->res->output('Hello');
115 sub product : Regex('^product[_]*(\d*).html$') {
116 my ( $self, $c ) = @_;
117 $c->stash->{template} = 'product.tt';
118 $c->stash->{product} = $c->req->snippets->[0];
121 See also L<Catalyst::Manual::Intro>
125 The key concept of Catalyst is DRY (Don't Repeat Yourself).
127 See L<Catalyst::Manual> for more documentation.
129 Catalyst plugins can be loaded by naming them as arguments to the "use Catalyst" statement.
130 Omit the C<Catalyst::Plugin::> prefix from the plugin name,
131 so C<Catalyst::Plugin::My::Module> becomes C<My::Module>.
133 use Catalyst 'My::Module';
135 Special flags like -Debug and -Engine can also be specified as arguments when
138 use Catalyst qw/-Debug My::Module/;
140 The position of plugins and flags in the chain is important, because they are
141 loaded in exactly the order that they appear.
143 The following flags are supported:
149 enables debug output, i.e.:
151 use Catalyst '-Debug';
153 this is equivalent to:
160 Force Catalyst to use a specific engine.
161 Omit the C<Catalyst::Engine::> prefix of the engine name, i.e.:
163 use Catalyst '-Engine=CGI';
167 Force Catalyst to use a specific home directory.
181 Accessor for the current action. Returns a L<Catalyst::Action> object,
182 which stringifies to the action name.
184 =item $c->comp($name)
186 =item $c->component($name)
188 Get a component object by name.
190 $c->comp('MyApp::Model::MyModel')->do_stuff;
201 my $appclass = ref $c || $c;
204 $name, "${appclass}::${name}",
205 map { "${appclass}::${_}::${name}" } qw/M V C/
208 foreach my $try (@names) {
210 if ( exists $c->components->{$try} ) {
212 return $c->components->{$try};
216 foreach my $component ( keys %{ $c->components } ) {
218 return $c->components->{$component} if $component =~ /$name/i;
223 return sort keys %{ $c->components };
228 Returns a hashref containing your applications settings.
232 =item $c->controller($name)
234 Get a L<Catalyst::Controller> instance by name.
236 $c->controller('Foo')->do_stuff;
241 my ( $c, $name ) = @_;
242 my $controller = $c->comp("Controller::$name");
243 return $controller if $controller;
244 return $c->comp("C::$name");
249 Overload to enable debug messages.
255 =item $c->detach( $command [, \@arguments ] )
257 Like C<forward> but doesn't return.
261 sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
265 Contains the dispatcher instance. Stringifies to class name.
267 =item $c->forward( $command [, \@arguments ] )
269 Forward processing to a private action or a method from a class.
270 If you define a class without method it will default to process().
271 also takes an optional arrayref containing arguments to be passed
272 to the new function. $c->req->args will be restored upon returning
276 $c->forward('index');
277 $c->forward(qw/MyApp::Model::CDBI::Foo do_stuff/);
278 $c->forward('MyApp::View::TT');
282 sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
284 =item $c->model($name)
286 Get a L<Catalyst::Model> instance by name.
288 $c->model('Foo')->do_stuff;
293 my ( $c, $name ) = @_;
294 my $model = $c->comp("Model::$name");
295 return $model if $model;
296 return $c->comp("M::$name");
301 Returns the namespace of the current action, i.e., the uri prefix corresponding to the
302 controller of the current action.
304 =item $c->path_to(@path)
306 Merges C<@path> with $c->config->{home} and returns a L<Path::Class> object.
310 $c->path_to( 'db', 'sqlite.db' );
315 my ( $c, @path ) = @_;
316 my $path = dir( $c->config->{home}, @path );
317 if ( -d $path ) { return $path }
318 else { return file( $c->config->{home}, @path ) }
323 Initializes the dispatcher and engine, loads any plugins, and loads the
324 model, view, and controller components.
331 my ( $class, @arguments ) = @_;
333 unless ( $class->isa('Catalyst') ) {
335 Catalyst::Exception->throw(
336 message => qq/'$class' does not inherit from Catalyst/ );
339 if ( $class->arguments ) {
340 @arguments = ( @arguments, @{ $class->arguments } );
346 foreach (@arguments) {
350 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
352 elsif (/^-(\w+)=?(.*)$/) {
353 $flags->{ lc $1 } = $2;
356 push @{ $flags->{plugins} }, $_;
360 $class->setup_log( delete $flags->{log} );
361 $class->setup_plugins( delete $flags->{plugins} );
362 $class->setup_dispatcher( delete $flags->{dispatcher} );
363 $class->setup_engine( delete $flags->{engine} );
364 $class->setup_home( delete $flags->{home} );
366 for my $flag ( sort keys %{$flags} ) {
368 if ( my $code = $class->can( 'setup_' . $flag ) ) {
369 &$code( $class, delete $flags->{$flag} );
372 $class->log->warn(qq/Unknown flag "$flag"/);
377 <<"EOF") if ( $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::CATALYST_SCRIPT_GEN ) );
378 You are running an old script!
380 Please update by running:
381 catalyst.pl -nonew -scripts $class
384 if ( $class->debug ) {
390 @plugins = grep { /^Catalyst::Plugin/ } @{"$class\::ISA"};
394 my $t = Text::SimpleTable->new(76);
395 $t->row($_) for @plugins;
396 $class->log->debug( "Loaded plugins:\n" . $t->draw );
399 my $dispatcher = $class->dispatcher;
400 my $engine = $class->engine;
401 my $home = $class->config->{home};
403 $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
404 $class->log->debug(qq/Loaded engine "$engine"/);
408 ? $class->log->debug(qq/Found home "$home"/)
409 : $class->log->debug(qq/Home "$home" doesn't exist/)
410 : $class->log->debug(q/Couldn't find home/);
415 no warnings qw/redefine/;
416 local *setup = sub { };
420 # Initialize our data structure
421 $class->components( {} );
423 $class->setup_components;
425 if ( $class->debug ) {
426 my $t = Text::SimpleTable->new( [ 65, 'Class' ], [ 8, 'Type' ] );
427 for my $comp ( sort keys %{ $class->components } ) {
428 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
429 $t->row( $comp, $type );
431 $class->log->debug( "Loaded components:\n" . $t->draw )
432 if ( keys %{ $class->components } );
435 # Add our self to components, since we are also a component
436 $class->components->{$class} = $class;
438 $class->setup_actions;
440 if ( $class->debug ) {
441 my $name = $class->config->{name} || 'Application';
442 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
444 $class->log->_flush() if $class->log->can('_flush');
447 =item $c->uri_for($path,[@args])
449 Merges path with $c->request->base for absolute uri's and with
450 $c->request->match for relative uri's, then returns a normalized
451 L<URI> object. If any args are passed, they are added at the end
457 my ( $c, $path, @args ) = @_;
458 my $base = $c->request->base->clone;
459 my $basepath = $base->path;
460 $basepath =~ s/\/$//;
462 my $match = $c->request->match;
464 # massage match, empty if absolute path
466 $match .= '/' if $match;
468 $match = '' if $path =~ /^\//;
471 # join args with '/', or a blank string
472 my $args = ( scalar @args ? '/' . join( '/', @args ) : '' );
473 return URI->new_abs( URI->new_abs( "$path$args", "$basepath$match" ),
479 =item $c->error($error, ...)
481 =item $c->error($arrayref)
483 Returns an arrayref containing error messages.
485 my @error = @{ $c->error };
489 $c->error('Something bad happened');
500 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
501 push @{ $c->{error} }, @$error;
503 elsif ( defined $_[0] ) { $c->{error} = undef }
504 return $c->{error} || [];
509 Contains the engine instance. Stringifies to the class name.
513 Contains the logging object. Unless it is already set Catalyst sets this up with a
514 L<Catalyst::Log> object. To use your own log class:
516 $c->log( MyLogger->new );
517 $c->log->info("now logging with my own logger!");
519 Your log class should implement the methods described in the L<Catalyst::Log>
522 =item $c->plugin( $name, $class, @args )
524 Instant plugins for Catalyst.
525 Classdata accessor/mutator will be created, class loaded and instantiated.
527 MyApp->plugin( 'prototype', 'HTML::Prototype' );
529 $c->prototype->define_javascript_functions;
534 my ( $class, $name, $plugin, @args ) = @_;
537 if ( my $error = $UNIVERSAL::require::ERROR ) {
538 Catalyst::Exception->throw(
539 message => qq/Couldn't load instant plugin "$plugin", "$error"/ );
542 eval { $plugin->import };
543 $class->mk_classdata($name);
545 eval { $obj = $plugin->new(@args) };
548 Catalyst::Exception->throw( message =>
549 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
553 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
561 Returns a C<Catalyst::Request> object.
569 Returns a C<Catalyst::Response> object.
575 Contains the return value of the last executed action.
579 Returns a hashref containing all your data.
581 print $c->stash->{foo};
583 Keys may be set in the stash by assigning to the hash reference, or by passing
584 either a single hash reference or a list of key/value pairs as arguments.
588 $c->stash->{foo} ||= 'yada';
589 $c->stash( { moose => 'majestic', qux => 0 } );
590 $c->stash( bar => 1, gorch => 2 );
597 my $stash = @_ > 1 ? {@_} : $_[0];
598 while ( my ( $key, $val ) = each %$stash ) {
599 $c->{stash}->{$key} = $val;
605 =item $c->view($name)
607 Get a L<Catalyst::View> instance by name.
609 $c->view('Foo')->do_stuff;
614 my ( $c, $name ) = @_;
615 my $view = $c->comp("View::$name");
616 return $view if $view;
617 return $c->comp("V::$name");
620 =item $c->welcome_message
622 Returns the Catalyst welcome HTML page.
626 sub welcome_message {
628 my $name = $c->config->{name};
629 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
630 my $prefix = Catalyst::Utils::appprefix( ref $c );
631 $c->response->content_type('text/html; charset=utf-8');
633 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
634 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
635 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
637 <meta http-equiv="Content-Language" content="en" />
638 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
639 <title>$name on Catalyst $VERSION</title>
640 <style type="text/css">
643 background-color: #eee;
652 background-color: #ccc;
653 border: 1px solid #aaa;
654 -moz-border-radius: 10px;
659 font-family: verdana, tahoma, sans-serif;
662 font-family: verdana, tahoma, sans-serif;
665 text-decoration: none;
667 border-bottom: 1px dotted #bbb;
669 :link:hover, :visited:hover {
682 background-color: #fff;
683 border: 1px solid #aaa;
684 -moz-border-radius: 10px;
710 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
715 <img src="$logo" alt="Catalyst Logo" />
717 <p>Welcome to the wonderful world of Catalyst.
718 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
719 framework will make web development something you had
720 never expected it to be: Fun, rewarding and quick.</p>
721 <h2>What to do now?</h2>
722 <p>That really depends on what <b>you</b> want to do.
723 We do, however, provide you with a few starting points.</p>
724 <p>If you want to jump right into web development with Catalyst
725 you might want to check out the documentation.</p>
726 <pre><code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
727 perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
728 <h2>What to do next?</h2>
729 <p>Next it's time to write an actual application. Use the
730 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
731 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a> and
732 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>,
733 they can save you a lot of work.</p>
734 <pre><code>script/${prefix}_create.pl -help</code></pre>
735 <p>Also, be sure to check out the vast and growing
736 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&mode=all">plugins for Catalyst on CPAN</a>,
737 you are likely to find what you need there.
741 <p>Catalyst has a very active community. Here are the main places to
742 get in touch with us.</p>
745 <a href="http://dev.catalyst.perl.org">Wiki</a>
748 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
751 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
754 <h2>In conclusion</h2>
755 <p>The Catalyst team hopes you will enjoy using Catalyst as much
756 as we enjoyed making it. Please contact us if you have ideas
757 for improvement or other feedback.</p>
767 =head1 INTERNAL METHODS
771 =item $c->benchmark($coderef)
773 Takes a coderef with arguments and returns elapsed time as float.
775 my ( $elapsed, $status ) = $c->benchmark( sub { return 1 } );
776 $c->log->info( sprintf "Processing took %f seconds", $elapsed );
783 my $time = [gettimeofday];
784 my @return = &$code(@_);
785 my $elapsed = tv_interval $time;
786 return wantarray ? ( $elapsed, @return ) : $elapsed;
791 Returns a hash of components.
793 =item $c->context_class
795 Returns or sets the context class.
799 Returns a hashref containing coderefs and execution counts (needed for deep recursion detection).
803 Returns the number of actions on the current internal execution stack.
807 Dispatches a request to actions.
811 sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
813 =item $c->dispatcher_class
815 Returns or sets the dispatcher class.
819 Returns a list of 2-element array references (name, structure) pairs that will
820 be dumped on the error page in debug mode.
826 [ Request => $c->req ], [ Response => $c->res ], [ Stash => $c->stash ],;
829 =item $c->engine_class
831 Returns or sets the engine class.
833 =item $c->execute($class, $coderef)
835 Execute a coderef in given class and catch exceptions.
836 Errors are available via $c->error.
841 my ( $c, $class, $code ) = @_;
842 $class = $c->components->{$class} || $class;
846 ( caller(0) )[0]->isa('Catalyst::Action')
853 $action = "/$action" unless $action =~ /\-\>/;
854 $c->counter->{"$code"}++;
856 if ( $c->counter->{"$code"} > $RECURSION ) {
857 my $error = qq/Deep recursion detected in "$action"/;
858 $c->log->error($error);
864 $action = "-> $action" if $callsub =~ /forward$/;
866 push( @{ $c->stack }, $code );
870 my ( $elapsed, @state ) =
871 $c->benchmark( $code, $class, $c, @{ $c->req->args } );
872 unless ( ( $code->name =~ /^_.*/ )
873 && ( !$c->config->{show_internal_actions} ) )
875 push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ];
880 $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 );
883 pop( @{ $c->stack } );
885 if ( my $error = $@ ) {
887 if ( $error eq $DETACH ) { die $DETACH if $c->depth > 1 }
889 unless ( ref $error ) {
891 $error = qq/Caught exception "$error"/;
902 Finalizes the request.
909 for my $error ( @{ $c->error } ) {
910 $c->log->error($error);
913 $c->finalize_uploads;
916 if ( $#{ $c->error } >= 0 ) {
920 $c->finalize_headers;
923 if ( $c->request->method eq 'HEAD' ) {
924 $c->response->body('');
929 return $c->response->status;
932 =item $c->finalize_body
938 sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
940 =item $c->finalize_cookies
946 sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
948 =item $c->finalize_error
954 sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
956 =item $c->finalize_headers
962 sub finalize_headers {
965 # Check if we already finalized headers
966 return if $c->response->{_finalized_headers};
969 if ( my $location = $c->response->redirect ) {
970 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
971 $c->response->header( Location => $location );
975 if ( $c->response->body && !$c->response->content_length ) {
976 $c->response->content_length( bytes::length( $c->response->body ) );
980 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
981 $c->response->headers->remove_header("Content-Length");
982 $c->response->body('');
985 $c->finalize_cookies;
987 $c->engine->finalize_headers( $c, @_ );
990 $c->response->{_finalized_headers} = 1;
993 =item $c->finalize_output
995 An alias for finalize_body.
997 =item $c->finalize_read
999 Finalizes the input after reading is complete.
1003 sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1005 =item $c->finalize_uploads
1007 Finalizes uploads. Cleans up any temporary files.
1011 sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1013 =item $c->get_action( $action, $namespace )
1015 Gets an action in a given namespace.
1019 sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
1021 =item $c->get_actions( $action, $namespace )
1023 Gets all actions of a given name in a namespace and all parent namespaces.
1027 sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1029 =item handle_request( $class, @arguments )
1031 Called to handle each HTTP request.
1035 sub handle_request {
1036 my ( $class, @arguments ) = @_;
1038 # Always expect worst case!
1044 my $c = $class->prepare(@arguments);
1045 $c->{stats} = \@stats;
1047 return $c->finalize;
1050 if ( $class->debug ) {
1052 ( $elapsed, $status ) = $class->benchmark($handler);
1053 $elapsed = sprintf '%f', $elapsed;
1054 my $av = sprintf '%.3f',
1055 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
1056 my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] );
1058 for my $stat (@stats) { $t->row( $stat->[0], $stat->[1] ) }
1060 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
1062 else { $status = &$handler }
1066 if ( my $error = $@ ) {
1068 $class->log->error(qq/Caught exception in engine "$error"/);
1072 $class->log->_flush() if $class->log->can('_flush');
1076 =item $c->prepare(@arguments)
1078 Creates a Catalyst context from an engine-specific request (Apache, CGI, etc.).
1083 my ( $class, @arguments ) = @_;
1085 $class->context_class( ref $class || $class ) unless $class->context_class;
1086 my $c = $class->context_class->new(
1090 request => $class->request_class->new(
1093 body_parameters => {},
1095 headers => HTTP::Headers->new,
1097 query_parameters => {},
1103 response => $class->response_class->new(
1107 headers => HTTP::Headers->new(),
1116 # For on-demand data
1117 $c->request->{_context} = $c;
1118 $c->response->{_context} = $c;
1119 weaken( $c->request->{_context} );
1120 weaken( $c->response->{_context} );
1123 my $secs = time - $START || 1;
1124 my $av = sprintf '%.3f', $COUNT / $secs;
1125 $c->log->debug('**********************************');
1126 $c->log->debug("* Request $COUNT ($av/s) [$$]");
1127 $c->log->debug('**********************************');
1128 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1131 $c->prepare_request(@arguments);
1132 $c->prepare_connection;
1133 $c->prepare_query_parameters;
1134 $c->prepare_headers;
1135 $c->prepare_cookies;
1139 $c->prepare_body unless $c->config->{parse_on_demand};
1142 my $method = $c->req->method || '';
1143 my $path = $c->req->path || '';
1144 my $address = $c->req->address || '';
1146 $c->log->debug(qq/"$method" request for "$path" from $address/)
1152 =item $c->prepare_action
1158 sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1160 =item $c->prepare_body
1162 Prepares message body.
1169 # Do we run for the first time?
1170 return if defined $c->request->{_body};
1172 # Initialize on-demand data
1173 $c->engine->prepare_body( $c, @_ );
1174 $c->prepare_parameters;
1175 $c->prepare_uploads;
1177 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
1178 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
1179 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1180 my $param = $c->req->body_parameters->{$key};
1181 my $value = defined($param) ? $param : '';
1183 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1185 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1189 =item $c->prepare_body_chunk( $chunk )
1191 Prepares a chunk of data before sending it to L<HTTP::Body>.
1195 sub prepare_body_chunk {
1197 $c->engine->prepare_body_chunk( $c, @_ );
1200 =item $c->prepare_body_parameters
1202 Prepares body parameters.
1206 sub prepare_body_parameters {
1208 $c->engine->prepare_body_parameters( $c, @_ );
1211 =item $c->prepare_connection
1213 Prepares connection.
1217 sub prepare_connection {
1219 $c->engine->prepare_connection( $c, @_ );
1222 =item $c->prepare_cookies
1228 sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1230 =item $c->prepare_headers
1236 sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1238 =item $c->prepare_parameters
1240 Prepares parameters.
1244 sub prepare_parameters {
1246 $c->prepare_body_parameters;
1247 $c->engine->prepare_parameters( $c, @_ );
1250 =item $c->prepare_path
1252 Prepares path and base.
1256 sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1258 =item $c->prepare_query_parameters
1260 Prepares query parameters.
1264 sub prepare_query_parameters {
1267 $c->engine->prepare_query_parameters( $c, @_ );
1269 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
1270 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
1271 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1272 my $param = $c->req->query_parameters->{$key};
1273 my $value = defined($param) ? $param : '';
1275 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1277 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1281 =item $c->prepare_read
1283 Prepares the input for reading.
1287 sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1289 =item $c->prepare_request
1291 Prepares the engine request.
1295 sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1297 =item $c->prepare_uploads
1303 sub prepare_uploads {
1306 $c->engine->prepare_uploads( $c, @_ );
1308 if ( $c->debug && keys %{ $c->request->uploads } ) {
1309 my $t = Text::SimpleTable->new(
1315 for my $key ( sort keys %{ $c->request->uploads } ) {
1316 my $upload = $c->request->uploads->{$key};
1317 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
1318 $t->row( $key, $u->filename, $u->type, $u->size );
1321 $c->log->debug( "File Uploads are:\n" . $t->draw );
1325 =item $c->prepare_write
1327 Prepares the output for writing.
1331 sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1333 =item $c->request_class
1335 Returns or sets the request class.
1337 =item $c->response_class
1339 Returns or sets the response class.
1341 =item $c->read( [$maxlength] )
1343 Reads a chunk of data from the request body. This method is designed to be
1344 used in a while loop, reading $maxlength bytes on every call. $maxlength
1345 defaults to the size of the request if not specified.
1347 You have to set MyApp->config->{parse_on_demand} to use this directly.
1351 sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1359 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1361 =item $c->set_action( $action, $code, $namespace, $attrs )
1363 Sets an action in a given namespace.
1367 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1369 =item $c->setup_actions($component)
1371 Sets up actions for a component.
1375 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1377 =item $c->setup_components
1383 sub setup_components {
1386 my $callback = sub {
1387 my ( $component, $context ) = @_;
1389 unless ( $component->isa('Catalyst::Component') ) {
1393 my $suffix = Catalyst::Utils::class2classsuffix($component);
1394 my $config = $class->config->{$suffix} || {};
1398 eval { $instance = $component->new( $context, $config ); };
1400 if ( my $error = $@ ) {
1404 Catalyst::Exception->throw( message =>
1405 qq/Couldn't instantiate component "$component", "$error"/ );
1408 Catalyst::Exception->throw( message =>
1409 qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1411 unless ref $instance;
1416 Module::Pluggable::Fast->import(
1417 name => '_catalyst_components',
1419 "$class\::Controller", "$class\::C",
1420 "$class\::Model", "$class\::M",
1421 "$class\::View", "$class\::V"
1423 callback => $callback
1427 if ( my $error = $@ ) {
1431 Catalyst::Exception->throw(
1432 message => qq/Couldn't load components "$error"/ );
1435 for my $component ( $class->_catalyst_components($class) ) {
1436 $class->components->{ ref $component || $component } = $component;
1440 =item $c->setup_dispatcher
1444 sub setup_dispatcher {
1445 my ( $class, $dispatcher ) = @_;
1448 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1451 if ( $ENV{CATALYST_DISPATCHER} ) {
1452 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1455 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1457 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1460 unless ($dispatcher) {
1461 $dispatcher = $class->dispatcher_class;
1464 $dispatcher->require;
1467 Catalyst::Exception->throw(
1468 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1471 # dispatcher instance
1472 $class->dispatcher( $dispatcher->new );
1475 =item $c->setup_engine
1480 my ( $class, $engine ) = @_;
1483 $engine = 'Catalyst::Engine::' . $engine;
1486 if ( $ENV{CATALYST_ENGINE} ) {
1487 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1490 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1491 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1494 if ( !$engine && $ENV{MOD_PERL} ) {
1496 # create the apache method
1499 *{"$class\::apache"} = sub { shift->engine->apache };
1502 my ( $software, $version ) =
1503 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1506 $version =~ s/(\.[^.]+)\./$1/g;
1508 if ( $software eq 'mod_perl' ) {
1510 if ( $version >= 1.99922 ) {
1511 $engine = 'Catalyst::Engine::Apache2::MP20';
1514 elsif ( $version >= 1.9901 ) {
1515 $engine = 'Catalyst::Engine::Apache2::MP19';
1518 elsif ( $version >= 1.24 ) {
1519 $engine = 'Catalyst::Engine::Apache::MP13';
1523 Catalyst::Exception->throw( message =>
1524 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1527 # install the correct mod_perl handler
1528 if ( $version >= 1.9901 ) {
1529 *handler = sub : method {
1530 shift->handle_request(@_);
1534 *handler = sub ($$) { shift->handle_request(@_) };
1539 elsif ( $software eq 'Zeus-Perl' ) {
1540 $engine = 'Catalyst::Engine::Zeus';
1544 Catalyst::Exception->throw(
1545 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1550 $engine = $class->engine_class;
1556 Catalyst::Exception->throw( message =>
1557 qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1561 # check for old engines that are no longer compatible
1563 if ( $engine->isa('Catalyst::Engine::Apache')
1564 && !Catalyst::Engine::Apache->VERSION )
1569 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
1570 && Catalyst::Engine::Server->VERSION le '0.02' )
1575 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1576 && $engine->VERSION eq '0.01' )
1581 elsif ($engine->isa('Catalyst::Engine::Zeus')
1582 && $engine->VERSION eq '0.01' )
1588 Catalyst::Exception->throw( message =>
1589 qq/Engine "$engine" is not supported by this version of Catalyst/
1594 $class->engine( $engine->new );
1597 =item $c->setup_home
1602 my ( $class, $home ) = @_;
1604 if ( $ENV{CATALYST_HOME} ) {
1605 $home = $ENV{CATALYST_HOME};
1608 if ( $ENV{ uc($class) . '_HOME' } ) {
1609 $home = $ENV{ uc($class) . '_HOME' };
1613 $home = Catalyst::Utils::home($class);
1617 $class->config->{home} ||= $home;
1618 $class->config->{root} ||= dir($home)->subdir('root');
1627 my ( $class, $debug ) = @_;
1629 unless ( $class->log ) {
1630 $class->log( Catalyst::Log->new );
1633 my $app_flag = Catalyst::Utils::class2env($class) . '_DEBUG';
1636 ( defined( $ENV{CATALYST_DEBUG} ) || defined( $ENV{$app_flag} ) )
1637 ? ( $ENV{CATALYST_DEBUG} || $ENV{$app_flag} )
1642 *{"$class\::debug"} = sub { 1 };
1643 $class->log->debug('Debug messages enabled');
1647 =item $c->setup_plugins
1652 my ( $class, $plugins ) = @_;
1655 for my $plugin ( reverse @$plugins ) {
1657 $plugin = "Catalyst::Plugin::$plugin";
1662 Catalyst::Exception->throw(
1663 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1668 unshift @{"$class\::ISA"}, $plugin;
1677 =item $c->write( $data )
1679 Writes $data to the output stream. When using this method directly, you will
1680 need to manually set the Content-Length header to the length of your output
1688 # Finalize headers if someone manually writes output
1689 $c->finalize_headers;
1691 return $c->engine->write( $c, @_ );
1696 Returns the Catalyst version number. Mostly useful for "powered by" messages
1697 in template systems.
1701 sub version { return $Catalyst::VERSION }
1705 =head1 INTERNAL ACTIONS
1707 Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>
1708 C<_ACTION> and C<_END>, these are by default not shown in the private
1711 But you can deactivate this with a config parameter.
1713 MyApp->config->{show_internal_actions} = 1;
1715 =head1 CASE SENSITIVITY
1717 By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1720 But you can activate case sensitivity with a config parameter.
1722 MyApp->config->{case_sensitive} = 1;
1724 So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1726 =head1 ON-DEMAND PARSER
1728 The request body is usually parsed at the beginning of a request,
1729 but if you want to handle input yourself or speed things up a bit
1730 you can enable on-demand parsing with a config parameter.
1732 MyApp->config->{parse_on_demand} = 1;
1734 =head1 PROXY SUPPORT
1736 Many production servers operate using the common double-server approach, with
1737 a lightweight frontend web server passing requests to a larger backend
1738 server. An application running on the backend server must deal with two
1739 problems: the remote user always appears to be '127.0.0.1' and the server's
1740 hostname will appear to be 'localhost' regardless of the virtual host the
1741 user connected through.
1743 Catalyst will automatically detect this situation when you are running both
1744 the frontend and backend servers on the same machine. The following changes
1745 are made to the request.
1747 $c->req->address is set to the user's real IP address, as read from the
1748 HTTP_X_FORWARDED_FOR header.
1750 The host value for $c->req->base and $c->req->uri is set to the real host,
1751 as read from the HTTP_X_FORWARDED_HOST header.
1753 Obviously, your web server must support these 2 headers for this to work.
1755 In a more complex server farm environment where you may have your frontend
1756 proxy server(s) on different machines, you will need to set a configuration
1757 option to tell Catalyst to read the proxied data from the headers.
1759 MyApp->config->{using_frontend_proxy} = 1;
1761 If you do not wish to use the proxy support at all, you may set:
1763 MyApp->config->{ignore_frontend_proxy} = 1;
1765 =head1 THREAD SAFETY
1767 Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1768 and the standalone forking HTTP server on Windows. We believe the Catalyst
1769 core to be thread-safe.
1771 If you plan to operate in a threaded environment, remember that all other
1772 modules you are using must also be thread-safe. Some modules, most notably
1773 DBD::SQLite, are not thread-safe.
1779 Join #catalyst on irc.perl.org.
1783 http://lists.rawmode.org/mailman/listinfo/catalyst
1784 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1788 http://catalyst.perl.org
1794 =item L<Catalyst::Manual> - The Catalyst Manual
1796 =item L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
1798 =item L<Catalyst::Engine> - Core Engine
1800 =item L<Catalyst::Log> - The Log Class.
1802 =item L<Catalyst::Request> - The Request Object
1804 =item L<Catalyst::Response> - The Response Object
1806 =item L<Catalyst::Test> - The test suite.
1874 Sebastian Riedel, C<sri@oook.de>
1878 This library is free software, you can redistribute it and/or modify it under
1879 the same terms as Perl itself.