4 use base 'Catalyst::Base';
6 use UNIVERSAL::require;
7 use Catalyst::Exception;
10 use Catalyst::Request::Upload;
11 use Catalyst::Response;
13 use JSAN::Parse::FileDeps;
17 use Time::HiRes qw/gettimeofday tv_interval/;
19 use Scalar::Util qw/weaken/;
21 __PACKAGE__->mk_accessors(
22 qw/counter depth request response state action namespace/
30 # For backwards compatibility
31 *finalize_output = \&finalize_body;
36 our $RECURSION = 1000;
37 our $DETACH = "catalyst_detach\n";
39 require Module::Pluggable::Fast;
41 # Helper script generation
42 our $CATALYST_SCRIPT_GEN = 9;
44 __PACKAGE__->mk_classdata($_)
45 for qw/components arguments dispatcher engine log/;
47 our $VERSION = '5.49_02';
50 my ( $class, @arguments ) = @_;
52 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
54 return unless $class eq 'Catalyst';
56 my $caller = caller(0);
58 unless ( $caller->isa('Catalyst') ) {
60 push @{"$caller\::ISA"}, $class;
63 $caller->arguments( [@arguments] );
69 Catalyst - The Elegant MVC Web Application Framework
73 # use the helper to start a new application
77 # add models, views, controllers
78 script/myapp_create.pl model Something
79 script/myapp_create.pl view Stuff
80 script/myapp_create.pl controller Yada
83 script/myapp_server.pl
85 # command line interface
86 script/myapp_test.pl /yada
91 use Catalyst qw/My::Module My::OtherModule/;
93 use Catalyst '-Debug';
95 use Catalyst qw/-Debug -Engine=CGI/;
97 sub default : Private { $_[1]->res->output('Hello') } );
99 sub index : Path('/index.html') {
100 my ( $self, $c ) = @_;
101 $c->res->output('Hello');
105 sub product : Regex('^product[_]*(\d*).html$') {
106 my ( $self, $c ) = @_;
107 $c->stash->{template} = 'product.tt';
108 $c->stash->{product} = $c->req->snippets->[0];
111 See also L<Catalyst::Manual::Intro>
115 The key concept of Catalyst is DRY (Don't Repeat Yourself).
117 See L<Catalyst::Manual> for more documentation.
119 Catalyst plugins can be loaded by naming them as arguments to the "use Catalyst" statement.
120 Omit the C<Catalyst::Plugin::> prefix from the plugin name,
121 so C<Catalyst::Plugin::My::Module> becomes C<My::Module>.
123 use Catalyst 'My::Module';
125 Special flags like -Debug and -Engine can also be specified as arguments when
128 use Catalyst qw/-Debug My::Module/;
130 The position of plugins and flags in the chain is important, because they are
131 loaded in exactly the order that they appear.
133 The following flags are supported:
139 enables debug output, i.e.:
141 use Catalyst '-Debug';
143 this is equivalent to:
150 Force Catalyst to use a specific dispatcher.
154 Force Catalyst to use a specific engine.
155 Omit the C<Catalyst::Engine::> prefix of the engine name, i.e.:
157 use Catalyst '-Engine=CGI';
161 Force Catalyst to use a specific home directory.
175 Accessor for the current action
177 =item $c->comp($name)
179 =item $c->component($name)
181 Get a component object by name.
183 $c->comp('MyApp::Model::MyModel')->do_stuff;
194 my $appclass = ref $c || $c;
197 $name, "${appclass}::${name}",
198 map { "${appclass}::${_}::${name}" } qw/M V C/
201 foreach my $try (@names) {
203 if ( exists $c->components->{$try} ) {
205 return $c->components->{$try};
209 foreach my $component ( keys %{ $c->components } ) {
211 return $c->components->{$component} if $component =~ /$name/i;
216 return sort keys %{ $c->components };
221 Returns a hashref containing your applications settings.
225 Overload to enable debug messages.
231 =item $c->detach( $command [, \@arguments ] )
233 Like C<forward> but doesn't return.
237 sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
241 Contains the dispatcher instance.
242 Stringifies to class.
244 =item $c->forward( $command [, \@arguments ] )
246 Forward processing to a private action or a method from a class.
247 If you define a class without method it will default to process().
248 also takes an optional arrayref containing arguments to be passed
249 to the new function. $c->req->args will be reset upon returning
253 $c->forward('index');
254 $c->forward(qw/MyApp::Model::CDBI::Foo do_stuff/);
255 $c->forward('MyApp::View::TT');
259 sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
263 Accessor to the namespace of the current action
265 =item $c->path_to(@path)
267 Merges C<@path> with $c->config->{home} and returns a L<Path::Class> object.
271 $c->path_to( 'db', 'sqlite.db' );
276 my ( $c, @path ) = @_;
277 my $path = dir( $c->config->{home}, @path );
278 if ( -d $path ) { return $path }
279 else { return file( $c->config->{home}, @path ) }
291 my ( $class, @arguments ) = @_;
293 unless ( $class->isa('Catalyst') ) {
295 Catalyst::Exception->throw(
296 message => qq/'$class' does not inherit from Catalyst/ );
299 if ( $class->arguments ) {
300 @arguments = ( @arguments, @{ $class->arguments } );
306 foreach (@arguments) {
310 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
312 elsif (/^-(\w+)=?(.*)$/) {
313 $flags->{ lc $1 } = $2;
316 push @{ $flags->{plugins} }, $_;
320 $class->setup_log( delete $flags->{log} );
321 $class->setup_plugins( delete $flags->{plugins} );
322 $class->setup_dispatcher( delete $flags->{dispatcher} );
323 $class->setup_engine( delete $flags->{engine} );
324 $class->setup_home( delete $flags->{home} );
326 for my $flag ( sort keys %{$flags} ) {
328 if ( my $code = $class->can( 'setup_' . $flag ) ) {
329 &$code( $class, delete $flags->{$flag} );
332 $class->log->warn(qq/Unknown flag "$flag"/);
336 $class->log->warn( "You are running an old helper script! "
337 . "Please update your scripts by regenerating the "
338 . "application and copying over the new scripts." )
339 if ( $ENV{CATALYST_SCRIPT_GEN}
340 && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::CATALYST_SCRIPT_GEN ) );
342 if ( $class->debug ) {
348 @plugins = grep { /^Catalyst::Plugin/ } @{"$class\::ISA"};
352 my $t = Text::ASCIITable->new;
353 $t->setOptions( 'hide_HeadRow', 1 );
354 $t->setOptions( 'hide_HeadLine', 1 );
355 $t->setCols('Class');
356 $t->setColWidth( 'Class', 75, 1 );
357 $t->addRow($_) for @plugins;
358 $class->log->debug( "Loaded plugins:\n" . $t->draw );
361 my $dispatcher = $class->dispatcher;
362 my $engine = $class->engine;
363 my $home = $class->config->{home};
365 $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
366 $class->log->debug(qq/Loaded engine "$engine"/);
370 ? $class->log->debug(qq/Found home "$home"/)
371 : $class->log->debug(qq/Home "$home" doesn't exist/)
372 : $class->log->debug(q/Couldn't find home/);
377 no warnings qw/redefine/;
378 local *setup = sub { };
382 # Initialize our data structure
383 $class->components( {} );
385 $class->setup_components;
387 if ( $class->debug ) {
388 my $t = Text::ASCIITable->new;
389 $t->setOptions( 'hide_HeadRow', 1 );
390 $t->setOptions( 'hide_HeadLine', 1 );
391 $t->setCols('Class');
392 $t->setColWidth( 'Class', 75, 1 );
393 $t->addRow($_) for sort keys %{ $class->components };
394 $class->log->debug( "Loaded components:\n" . $t->draw )
395 if ( @{ $t->{tbl_rows} } );
398 # Add our self to components, since we are also a component
399 $class->components->{$class} = $class;
401 $class->setup_actions;
403 if ( $class->debug ) {
404 my $name = $class->config->{name} || 'Application';
405 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
407 $class->log->_flush() if $class->log->can('_flush');
410 =item $c->uri_for($path,[@args])
412 Merges path with $c->request->base for absolute uri's and with
413 $c->request->match for relative uri's, then returns a normalized
414 L<URI> object. If any args are passed, they are added at the end
420 my ( $c, $path, @args ) = @_;
421 my $base = $c->request->base->clone;
422 my $basepath = $base->path;
423 $basepath =~ s/\/$//;
425 my $match = $c->request->match;
427 # massage match, empty if absolute path
429 $match .= '/' if $match;
430 $match = '' if $path =~ /^\//;
433 # join args with '/', or a blank string
434 my $args = ( scalar @args ? '/' . join( '/', @args ) : '' );
435 return URI->new_abs( URI->new_abs( "$path$args", "$basepath$match" ),
441 =item $c->error($error, ...)
443 =item $c->error($arrayref)
445 Returns an arrayref containing error messages.
447 my @error = @{ $c->error };
451 $c->error('Something bad happened');
462 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
463 push @{ $c->{error} }, @$error;
465 elsif ( defined $_[0] ) { $c->{error} = undef }
466 return $c->{error} || [];
471 Contains the engine instance.
472 Stringifies to the class.
476 Contains the logging object. Unless it is already set Catalyst sets this up with a
477 C<Catalyst::Log> object. To use your own log class:
479 $c->log( MyLogger->new );
480 $c->log->info("now logging with my own logger!");
482 Your log class should implement the methods described in the C<Catalyst::Log>
485 =item $c->plugin( $name, $class, @args )
487 Instant plugins for Catalyst.
488 Classdata accessor/mutator will be created, class loaded and instantiated.
490 MyApp->plugin( 'prototype', 'HTML::Prototype' );
492 $c->prototype->define_javascript_functions;
497 my ( $class, $name, $plugin, @args ) = @_;
500 if ( my $error = $UNIVERSAL::require::ERROR ) {
501 Catalyst::Exception->throw(
502 message => qq/Couldn't load instant plugin "$plugin", "$error"/ );
505 eval { $plugin->import };
506 $class->mk_classdata($name);
508 eval { $obj = $plugin->new(@args) };
511 Catalyst::Exception->throw( message =>
512 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
516 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
524 Returns a C<Catalyst::Request> object.
532 Returns a C<Catalyst::Response> object.
538 Contains the return value of the last executed action.
542 Returns a hashref containing all your data.
544 print $c->stash->{foo};
546 Keys may be set in the stash by assigning to the hash reference, or by passing
547 either a single hash reference or a list of key/value pairs as arguments.
551 $c->stash->{foo} ||= 'yada';
552 $c->stash( { moose => 'majestic', qux => 0 } );
553 $c->stash( bar => 1, gorch => 2 );
560 my $stash = @_ > 1 ? {@_} : $_[0];
561 while ( my ( $key, $val ) = each %$stash ) {
562 $c->{stash}->{$key} = $val;
568 =item $c->welcome_message
570 Returns the Catalyst welcome HTML page.
574 sub welcome_message {
576 my $name = $c->config->{name};
577 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
578 my $prefix = Catalyst::Utils::appprefix( ref $c );
582 <title>$name on Catalyst $VERSION</title>
583 <style type="text/css">
588 background-color: #eee;
596 background-color: #ccc;
597 border: 1px solid #aaa;
598 -moz-border-radius: 10px;
603 font-family: verdana, tahoma, sans-serif;
606 font-family: verdana, tahoma, sans-serif;
609 text-decoration: none;
611 border-bottom: 1px dotted #bbb;
613 :link:hover, :visited:hover {
626 background-color: #fff;
627 border: 1px solid #aaa;
628 -moz-border-radius: 10px;
653 <h1><b id="appname">$name</b> on <a href="http://catalyst.perl.org">Catalyst</a>
660 <p>Welcome to the wonderful world of Catalyst.
661 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
662 framework will make web development something you had
663 never expected it to be: Fun, rewarding and quick.</p>
664 <h2>What to do now?</h2>
665 <p>That really depends on what <b>you</b> want to do.
666 We do, however, provide you with a few starting points.</p>
667 <p>If you want to jump right into web development with Catalyst
668 you might want to check out the documentation.</p>
669 <pre><code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
670 perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
671 <h2>What to do next?</h2>
672 <p>Next it's time to write an actual application. Use the
673 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
674 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a> and
675 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>,
676 they can save you a lot of work.</p>
677 <pre><code>script/${prefix}_create.pl -help</code></pre>
678 <p>Also, be sure to check out the vast and growing
679 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&mode=all">plugins for Catalyst on CPAN</a>,
680 you are likely to find what you need there.
684 <p>Catalyst has a very active community. Here are the main places to
685 get in touch with us.</p>
688 <a href="http://dev.catalyst.perl.org">Wiki</a>
691 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
694 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
697 <h2>In conclusion</h2>
698 <p>The Catalyst team hopes you will enjoy using Catalyst as much
699 as we enjoyed making it. Please contact us if you have ideas
700 for improvement or other feedback.</p>
710 =head1 INTERNAL METHODS
714 =item $c->benchmark($coderef)
716 Takes a coderef with arguments and returns elapsed time as float.
718 my ( $elapsed, $status ) = $c->benchmark( sub { return 1 } );
719 $c->log->info( sprintf "Processing took %f seconds", $elapsed );
726 my $time = [gettimeofday];
727 my @return = &$code(@_);
728 my $elapsed = tv_interval $time;
729 return wantarray ? ( $elapsed, @return ) : $elapsed;
734 Contains the components.
738 Returns a hashref containing coderefs and execution counts.
739 (Needed for deep recursion detection)
743 Returns the actual forward depth.
747 Dispatch request to actions.
751 sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
753 =item $c->execute($class, $coderef)
755 Execute a coderef in given class and catch exceptions.
756 Errors are available via $c->error.
761 my ( $c, $class, $code ) = @_;
762 $class = $c->components->{$class} || $class;
764 my $callsub = ( caller(1) )[3];
769 $action = "/$action" unless $action =~ /\-\>/;
770 $c->counter->{"$code"}++;
772 if ( $c->counter->{"$code"} > $RECURSION ) {
773 my $error = qq/Deep recursion detected in "$action"/;
774 $c->log->error($error);
780 $action = "-> $action" if $callsub =~ /forward$/;
786 my ( $elapsed, @state ) =
787 $c->benchmark( $code, $class, $c, @{ $c->req->args } );
788 push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ];
792 $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 );
797 if ( my $error = $@ ) {
799 if ( $error eq $DETACH ) { die $DETACH if $c->{depth} > 1 }
801 unless ( ref $error ) {
803 $error = qq/Caught exception "$error"/;
806 $c->log->error($error);
823 $c->finalize_uploads;
826 if ( $#{ $c->error } >= 0 ) {
830 $c->finalize_headers;
833 if ( $c->request->method eq 'HEAD' ) {
834 $c->response->body('');
839 return $c->response->status;
842 =item $c->finalize_body
848 sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
850 =item $c->finalize_cookies
856 sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
858 =item $c->finalize_error
864 sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
866 =item $c->finalize_headers
872 sub finalize_headers {
875 # Check if we already finalized headers
876 return if $c->response->{_finalized_headers};
879 if ( my $location = $c->response->redirect ) {
880 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
881 $c->response->header( Location => $location );
885 if ( $c->response->body && !$c->response->content_length ) {
886 $c->response->content_length( bytes::length( $c->response->body ) );
890 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
891 $c->response->headers->remove_header("Content-Length");
892 $c->response->body('');
895 $c->finalize_cookies;
897 $c->engine->finalize_headers( $c, @_ );
900 $c->response->{_finalized_headers} = 1;
903 =item $c->finalize_output
905 An alias for finalize_body.
907 =item $c->finalize_read
909 Finalize the input after reading is complete.
913 sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
915 =item $c->finalize_uploads
917 Finalize uploads. Cleans up any temporary files.
921 sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
923 =item $c->get_action( $action, $namespace, $inherit )
925 Get an action in a given namespace.
929 sub get_action { my $c = shift; $c->dispatcher->get_action( $c, @_ ) }
931 =item handle_request( $class, @arguments )
938 my ( $class, @arguments ) = @_;
940 # Always expect worst case!
946 my $c = $class->prepare(@arguments);
947 $c->{stats} = \@stats;
952 if ( $class->debug ) {
954 ( $elapsed, $status ) = $class->benchmark($handler);
955 $elapsed = sprintf '%f', $elapsed;
956 my $av = sprintf '%.3f',
957 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
958 my $t = Text::ASCIITable->new;
959 $t->setCols( 'Action', 'Time' );
960 $t->setColWidth( 'Action', 64, 1 );
961 $t->setColWidth( 'Time', 9, 1 );
963 for my $stat (@stats) { $t->addRow( $stat->[0], $stat->[1] ) }
965 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
967 else { $status = &$handler }
971 if ( my $error = $@ ) {
973 $class->log->error(qq/Caught exception in engine "$error"/);
977 $class->log->_flush() if $class->log->can('_flush');
981 =item $c->prepare(@arguments)
983 Turns the engine-specific request( Apache, CGI ... )
984 into a Catalyst context .
989 my ( $class, @arguments ) = @_;
994 request => Catalyst::Request->new(
997 body_parameters => {},
999 headers => HTTP::Headers->new,
1001 query_parameters => {},
1007 response => Catalyst::Response->new(
1011 headers => HTTP::Headers->new(),
1019 # For on-demand data
1020 $c->request->{_context} = $c;
1021 $c->response->{_context} = $c;
1022 weaken( $c->request->{_context} );
1023 weaken( $c->response->{_context} );
1026 my $secs = time - $START || 1;
1027 my $av = sprintf '%.3f', $COUNT / $secs;
1028 $c->log->debug('**********************************');
1029 $c->log->debug("* Request $COUNT ($av/s) [$$]");
1030 $c->log->debug('**********************************');
1031 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1034 $c->prepare_request(@arguments);
1035 $c->prepare_connection;
1036 $c->prepare_query_parameters;
1037 $c->prepare_headers;
1038 $c->prepare_cookies;
1042 $c->prepare_body unless $c->config->{parse_on_demand};
1045 my $method = $c->req->method || '';
1046 my $path = $c->req->path || '';
1047 my $address = $c->req->address || '';
1049 $c->log->debug(qq/"$method" request for "$path" from $address/)
1055 =item $c->prepare_action
1061 sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1063 =item $c->prepare_body
1065 Prepare message body.
1072 # Do we run for the first time?
1073 return if defined $c->request->{_body};
1075 # Initialize on-demand data
1076 $c->engine->prepare_body( $c, @_ );
1077 $c->prepare_parameters;
1078 $c->prepare_uploads;
1080 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
1081 my $t = Text::ASCIITable->new;
1082 $t->setCols( 'Key', 'Value' );
1083 $t->setColWidth( 'Key', 37, 1 );
1084 $t->setColWidth( 'Value', 36, 1 );
1085 $t->alignCol( 'Value', 'right' );
1086 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1087 my $param = $c->req->body_parameters->{$key};
1088 my $value = defined($param) ? $param : '';
1090 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1092 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1096 =item $c->prepare_body_chunk( $chunk )
1098 Prepare a chunk of data before sending it to HTTP::Body.
1102 sub prepare_body_chunk {
1104 $c->engine->prepare_body_chunk( $c, @_ );
1107 =item $c->prepare_body_parameters
1109 Prepare body parameters.
1113 sub prepare_body_parameters {
1115 $c->engine->prepare_body_parameters( $c, @_ );
1118 =item $c->prepare_connection
1124 sub prepare_connection {
1126 $c->engine->prepare_connection( $c, @_ );
1129 =item $c->prepare_cookies
1135 sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1137 =item $c->prepare_headers
1143 sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1145 =item $c->prepare_parameters
1151 sub prepare_parameters {
1153 $c->prepare_body_parameters;
1154 $c->engine->prepare_parameters( $c, @_ );
1157 =item $c->prepare_path
1159 Prepare path and base.
1163 sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1165 =item $c->prepare_query_parameters
1167 Prepare query parameters.
1171 sub prepare_query_parameters {
1174 $c->engine->prepare_query_parameters( $c, @_ );
1176 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
1177 my $t = Text::ASCIITable->new;
1178 $t->setCols( 'Key', 'Value' );
1179 $t->setColWidth( 'Key', 37, 1 );
1180 $t->setColWidth( 'Value', 36, 1 );
1181 $t->alignCol( 'Value', 'right' );
1182 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1183 my $param = $c->req->query_parameters->{$key};
1184 my $value = defined($param) ? $param : '';
1186 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1188 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1192 =item $c->prepare_read
1194 Prepare the input for reading.
1198 sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1200 =item $c->prepare_request
1202 Prepare the engine request.
1206 sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1208 =item $c->prepare_uploads
1214 sub prepare_uploads {
1217 $c->engine->prepare_uploads( $c, @_ );
1219 if ( $c->debug && keys %{ $c->request->uploads } ) {
1220 my $t = Text::ASCIITable->new;
1221 $t->setCols( 'Key', 'Filename', 'Type', 'Size' );
1222 $t->setColWidth( 'Key', 12, 1 );
1223 $t->setColWidth( 'Filename', 28, 1 );
1224 $t->setColWidth( 'Type', 18, 1 );
1225 $t->setColWidth( 'Size', 9, 1 );
1226 $t->alignCol( 'Size', 'left' );
1227 for my $key ( sort keys %{ $c->request->uploads } ) {
1228 my $upload = $c->request->uploads->{$key};
1229 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
1230 $t->addRow( $key, $u->filename, $u->type, $u->size );
1233 $c->log->debug( "File Uploads are:\n" . $t->draw );
1237 =item $c->prepare_write
1239 Prepare the output for writing.
1243 sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1245 =item $c->read( [$maxlength] )
1247 Read a chunk of data from the request body. This method is designed to be
1248 used in a while loop, reading $maxlength bytes on every call. $maxlength
1249 defaults to the size of the request if not specified.
1251 You have to set MyApp->config->{parse_on_demand} to use this directly.
1255 sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1263 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1265 =item $c->set_action( $action, $code, $namespace, $attrs )
1267 Set an action in a given namespace.
1271 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1273 =item $c->setup_actions($component)
1275 Setup actions for a component.
1279 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1281 =item $c->setup_components
1287 sub setup_components {
1290 my $callback = sub {
1291 my ( $component, $context ) = @_;
1293 unless ( $component->isa('Catalyst::Base') ) {
1297 my $suffix = Catalyst::Utils::class2classsuffix($component);
1298 my $config = $class->config->{$suffix} || {};
1302 eval { $instance = $component->new( $context, $config ); };
1304 if ( my $error = $@ ) {
1308 Catalyst::Exception->throw( message =>
1309 qq/Couldn't instantiate component "$component", "$error"/ );
1312 Catalyst::Exception->throw( message =>
1313 qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1315 unless ref $instance;
1320 Module::Pluggable::Fast->import(
1321 name => '_catalyst_components',
1323 "$class\::Controller", "$class\::C",
1324 "$class\::Model", "$class\::M",
1325 "$class\::View", "$class\::V"
1327 callback => $callback
1331 if ( my $error = $@ ) {
1335 Catalyst::Exception->throw(
1336 message => qq/Couldn't load components "$error"/ );
1339 for my $component ( $class->_catalyst_components($class) ) {
1340 $class->components->{ ref $component || $component } = $component;
1344 =item $c->setup_dispatcher
1348 sub setup_dispatcher {
1349 my ( $class, $dispatcher ) = @_;
1352 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1355 if ( $ENV{CATALYST_DISPATCHER} ) {
1356 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1359 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1361 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1364 unless ($dispatcher) {
1365 $dispatcher = 'Catalyst::Dispatcher';
1368 $dispatcher->require;
1371 Catalyst::Exception->throw(
1372 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1375 # dispatcher instance
1376 $class->dispatcher( $dispatcher->new );
1379 =item $c->setup_engine
1384 my ( $class, $engine ) = @_;
1387 $engine = 'Catalyst::Engine::' . $engine;
1390 if ( $ENV{CATALYST_ENGINE} ) {
1391 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1394 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1395 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1398 if ( !$engine && $ENV{MOD_PERL} ) {
1400 # create the apache method
1403 *{"$class\::apache"} = sub { shift->engine->apache };
1406 my ( $software, $version ) =
1407 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1410 $version =~ s/(\.[^.]+)\./$1/g;
1412 if ( $software eq 'mod_perl' ) {
1414 if ( $version >= 1.99922 ) {
1415 $engine = 'Catalyst::Engine::Apache2::MP20';
1418 elsif ( $version >= 1.9901 ) {
1419 $engine = 'Catalyst::Engine::Apache2::MP19';
1422 elsif ( $version >= 1.24 ) {
1423 $engine = 'Catalyst::Engine::Apache::MP13';
1427 Catalyst::Exception->throw( message =>
1428 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1431 # install the correct mod_perl handler
1432 if ( $version >= 1.9901 ) {
1433 *handler = sub : method {
1434 shift->handle_request(@_);
1438 *handler = sub ($$) { shift->handle_request(@_) };
1443 elsif ( $software eq 'Zeus-Perl' ) {
1444 $engine = 'Catalyst::Engine::Zeus';
1448 Catalyst::Exception->throw(
1449 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1454 $engine = 'Catalyst::Engine::CGI';
1460 Catalyst::Exception->throw( message =>
1461 qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1466 $class->engine( $engine->new );
1469 =item $c->setup_home
1474 my ( $class, $home ) = @_;
1476 if ( $ENV{CATALYST_HOME} ) {
1477 $home = $ENV{CATALYST_HOME};
1480 if ( $ENV{ uc($class) . '_HOME' } ) {
1481 $home = $ENV{ uc($class) . '_HOME' };
1485 $home = Catalyst::Utils::home($class);
1489 $class->config->{home} ||= $home;
1490 $class->config->{root} ||= dir($home)->subdir('root');
1499 my ( $class, $debug ) = @_;
1501 unless ( $class->log ) {
1502 $class->log( Catalyst::Log->new );
1505 if ( $ENV{CATALYST_DEBUG} || $ENV{ uc($class) . '_DEBUG' } || $debug ) {
1507 *{"$class\::debug"} = sub { 1 };
1508 $class->log->debug('Debug messages enabled');
1512 =item $c->setup_plugins
1517 my ( $class, $plugins ) = @_;
1520 for my $plugin ( reverse @$plugins ) {
1522 $plugin = "Catalyst::Plugin::$plugin";
1527 Catalyst::Exception->throw(
1528 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1533 unshift @{"$class\::ISA"}, $plugin;
1538 =item $c->write( $data )
1540 Writes $data to the output stream. When using this method directly, you will
1541 need to manually set the Content-Length header to the length of your output
1549 # Finalize headers if someone manually writes output
1550 $c->finalize_headers;
1552 return $c->engine->write( $c, @_ );
1557 Returns the Catalyst version number. mostly useful for powered by messages
1558 in template systems.
1562 sub version { return $Catalyst::VERSION }
1566 =head1 CASE SENSITIVITY
1568 By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1571 But you can activate case sensitivity with a config parameter.
1573 MyApp->config->{case_sensitive} = 1;
1575 So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1577 =head1 ON-DEMAND PARSER
1579 The request body is usually parsed at the beginning of a request,
1580 but if you want to handle input yourself or speed things up a bit
1581 you can enable on-demand parsing with a config parameter.
1583 MyApp->config->{parse_on_demand} = 1;
1585 =head1 PROXY SUPPORT
1587 Many production servers operate using the common double-server approach, with
1588 a lightweight frontend web server passing requests to a larger backend
1589 server. An application running on the backend server must deal with two
1590 problems: the remote user always appears to be '127.0.0.1' and the server's
1591 hostname will appear to be 'localhost' regardless of the virtual host the
1592 user connected through.
1594 Catalyst will automatically detect this situation when you are running both
1595 the frontend and backend servers on the same machine. The following changes
1596 are made to the request.
1598 $c->req->address is set to the user's real IP address, as read from the
1599 HTTP_X_FORWARDED_FOR header.
1601 The host value for $c->req->base and $c->req->uri is set to the real host,
1602 as read from the HTTP_X_FORWARDED_HOST header.
1604 Obviously, your web server must support these 2 headers for this to work.
1606 In a more complex server farm environment where you may have your frontend
1607 proxy server(s) on different machines, you will need to set a configuration
1608 option to tell Catalyst to read the proxied data from the headers.
1610 MyApp->config->{using_frontend_proxy} = 1;
1612 If you do not wish to use the proxy support at all, you may set:
1614 MyApp->config->{ignore_frontend_proxy} = 1;
1616 =head1 THREAD SAFETY
1618 Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1619 and the standalone forking HTTP server on Windows. We believe the Catalyst
1620 core to be thread-safe.
1622 If you plan to operate in a threaded environment, remember that all other
1623 modules you are using must also be thread-safe. Some modules, most notably
1624 DBD::SQLite, are not thread-safe.
1630 Join #catalyst on irc.perl.org.
1634 http://lists.rawmode.org/mailman/listinfo/catalyst
1635 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1639 http://catalyst.perl.org
1645 =item L<Catalyst::Manual> - The Catalyst Manual
1647 =item L<Catalyst::Engine> - Core Engine
1649 =item L<Catalyst::Log> - The Log Class.
1651 =item L<Catalyst::Request> - The Request Object
1653 =item L<Catalyst::Response> - The Response Object
1655 =item L<Catalyst::Test> - The test suite.
1717 Sebastian Riedel, C<sri@oook.de>
1721 This library is free software, you can redistribute it and/or modify it under
1722 the same terms as Perl itself.