Updated pod
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
CommitLineData
fc7ec1d9 1package Catalyst;
2
3use strict;
fbcc39ad 4use base 'Catalyst::Base';
5use bytes;
fc7ec1d9 6use UNIVERSAL::require;
a2f2cde9 7use Catalyst::Exception;
fc7ec1d9 8use Catalyst::Log;
fbcc39ad 9use Catalyst::Request;
10use Catalyst::Request::Upload;
11use Catalyst::Response;
812a28c9 12use Catalyst::Utils;
5d9a6d47 13use NEXT;
8c113188 14use Text::SimpleTable;
4f6748f1 15use Path::Class;
fbcc39ad 16use Time::HiRes qw/gettimeofday tv_interval/;
17use URI;
18use Scalar::Util qw/weaken/;
261c571e 19use attributes;
fc7ec1d9 20
66e28e3f 21__PACKAGE__->mk_accessors(
28591cd7 22 qw/counter request response state action stack namespace/
66e28e3f 23);
10dd6896 24
684d10ed 25attributes->import( __PACKAGE__, \&namespace, 'lvalue' );
261c571e 26
8767c5a3 27sub depth { scalar @{ shift->stack || [] }; }
28591cd7 28
fbcc39ad 29# Laziness++
30*comp = \&component;
31*req = \&request;
32*res = \&response;
33
34# For backwards compatibility
35*finalize_output = \&finalize_body;
36
37# For statistics
38our $COUNT = 1;
39our $START = time;
40our $RECURSION = 1000;
41our $DETACH = "catalyst_detach\n";
42
43require Module::Pluggable::Fast;
44
45# Helper script generation
8604aac5 46our $CATALYST_SCRIPT_GEN = 11;
fbcc39ad 47
48__PACKAGE__->mk_classdata($_)
3cec521a 49 for qw/components arguments dispatcher engine log dispatcher_class
50 engine_class context_class request_class response_class/;
cb0354c6 51
3cec521a 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');
fbcc39ad 56
480f3a1c 57our $VERSION = '5.49_04';
189e2a51 58
fbcc39ad 59sub import {
60 my ( $class, @arguments ) = @_;
61
62 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
63 # callers @ISA.
64 return unless $class eq 'Catalyst';
65
66 my $caller = caller(0);
67
68 unless ( $caller->isa('Catalyst') ) {
69 no strict 'refs';
70 push @{"$caller\::ISA"}, $class;
71 }
72
73 $caller->arguments( [@arguments] );
74 $caller->setup_home;
75}
fc7ec1d9 76
77=head1 NAME
78
79Catalyst - The Elegant MVC Web Application Framework
80
81=head1 SYNOPSIS
82
83 # use the helper to start a new application
91864987 84 catalyst.pl MyApp
fc7ec1d9 85 cd MyApp
86
87 # add models, views, controllers
ae4e40a7 88 script/myapp_create.pl model Something
89 script/myapp_create.pl view Stuff
90 script/myapp_create.pl controller Yada
fc7ec1d9 91
e7f1cf73 92 # built in testserver -- use -r to restart automatically on changes
ae4e40a7 93 script/myapp_server.pl
fc7ec1d9 94
95 # command line interface
ae4e40a7 96 script/myapp_test.pl /yada
fc7ec1d9 97
98
fc7ec1d9 99 use Catalyst;
100
101 use Catalyst qw/My::Module My::OtherModule/;
102
103 use Catalyst '-Debug';
104
105 use Catalyst qw/-Debug -Engine=CGI/;
106
5a8ed4fe 107 sub default : Private { $_[1]->res->output('Hello') } );
108
e3dc9d78 109 sub index : Path('/index.html') {
5a8ed4fe 110 my ( $self, $c ) = @_;
111 $c->res->output('Hello');
064834ea 112 $c->forward('foo');
5a8ed4fe 113 }
114
064834ea 115 sub product : Regex('^product[_]*(\d*).html$') {
5a8ed4fe 116 my ( $self, $c ) = @_;
117 $c->stash->{template} = 'product.tt';
118 $c->stash->{product} = $c->req->snippets->[0];
119 }
fc7ec1d9 120
3803e98f 121See also L<Catalyst::Manual::Intro>
122
fc7ec1d9 123=head1 DESCRIPTION
124
fc7ec1d9 125The key concept of Catalyst is DRY (Don't Repeat Yourself).
126
127See L<Catalyst::Manual> for more documentation.
128
23f9d934 129Catalyst plugins can be loaded by naming them as arguments to the "use Catalyst" statement.
1985c30b 130Omit the C<Catalyst::Plugin::> prefix from the plugin name,
23f9d934 131so C<Catalyst::Plugin::My::Module> becomes C<My::Module>.
fc7ec1d9 132
133 use Catalyst 'My::Module';
134
26e73131 135Special flags like -Debug and -Engine can also be specified as arguments when
23f9d934 136Catalyst is loaded:
fc7ec1d9 137
138 use Catalyst qw/-Debug My::Module/;
139
23f9d934 140The position of plugins and flags in the chain is important, because they are
141loaded in exactly the order that they appear.
fc7ec1d9 142
23f9d934 143The following flags are supported:
144
145=over 4
146
147=item -Debug
148
149enables debug output, i.e.:
fc7ec1d9 150
151 use Catalyst '-Debug';
152
23f9d934 153this is equivalent to:
fc7ec1d9 154
155 use Catalyst;
156 sub debug { 1 }
157
23f9d934 158=item -Engine
fc7ec1d9 159
160Force Catalyst to use a specific engine.
23f9d934 161Omit the C<Catalyst::Engine::> prefix of the engine name, i.e.:
fc7ec1d9 162
163 use Catalyst '-Engine=CGI';
164
fbcc39ad 165=item -Home
166
167Force Catalyst to use a specific home directory.
168
169=item -Log
170
171Specify log level.
172
23f9d934 173=back
fc7ec1d9 174
23f9d934 175=head1 METHODS
176
177=over 4
178
66e28e3f 179=item $c->action
180
e7f1cf73 181Accessor for the current action. Returns a L<Catalyst::Action> object,
182which stringifies to the action name.
66e28e3f 183
fbcc39ad 184=item $c->comp($name)
185
186=item $c->component($name)
187
188Get a component object by name.
189
190 $c->comp('MyApp::Model::MyModel')->do_stuff;
191
192=cut
193
194sub component {
195 my $c = shift;
196
197 if (@_) {
198
199 my $name = shift;
200
201 my $appclass = ref $c || $c;
202
203 my @names = (
204 $name, "${appclass}::${name}",
205 map { "${appclass}::${_}::${name}" } qw/M V C/
206 );
207
208 foreach my $try (@names) {
209
210 if ( exists $c->components->{$try} ) {
211
212 return $c->components->{$try};
213 }
214 }
215
216 foreach my $component ( keys %{ $c->components } ) {
217
218 return $c->components->{$component} if $component =~ /$name/i;
219 }
220
221 }
222
223 return sort keys %{ $c->components };
224}
225
226=item config
227
228Returns a hashref containing your applications settings.
229
af3ff00e 230=cut
231
232=item $c->controller($name)
233
234Get a L<Catalyst::Controller> instance by name.
235
236 $c->controller('Foo')->do_stuff;
237
238=cut
239
240sub controller {
241 my ( $c, $name ) = @_;
242 my $controller = $c->comp("Controller::$name");
243 return $controller if $controller;
244 return $c->comp("C::$name");
245}
246
23f9d934 247=item debug
fc7ec1d9 248
249Overload to enable debug messages.
250
251=cut
252
253sub debug { 0 }
254
fbcc39ad 255=item $c->detach( $command [, \@arguments ] )
fc7ec1d9 256
fbcc39ad 257Like C<forward> but doesn't return.
fc7ec1d9 258
259=cut
260
fbcc39ad 261sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
262
263=item $c->dispatcher
264
e7f1cf73 265Contains the dispatcher instance. Stringifies to class name.
fbcc39ad 266
267=item $c->forward( $command [, \@arguments ] )
268
269Forward processing to a private action or a method from a class.
270If you define a class without method it will default to process().
271also takes an optional arrayref containing arguments to be passed
e7f1cf73 272to the new function. $c->req->args will be restored upon returning
fbcc39ad 273from the function.
274
275 $c->forward('/foo');
276 $c->forward('index');
277 $c->forward(qw/MyApp::Model::CDBI::Foo do_stuff/);
278 $c->forward('MyApp::View::TT');
279
280=cut
281
282sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
283
af3ff00e 284=item $c->model($name)
285
286Get a L<Catalyst::Model> instance by name.
287
288 $c->model('Foo')->do_stuff;
289
290=cut
291
292sub model {
293 my ( $c, $name ) = @_;
294 my $model = $c->comp("Model::$name");
295 return $model if $model;
296 return $c->comp("M::$name");
297}
298
66e28e3f 299=item $c->namespace
300
e7f1cf73 301Returns the namespace of the current action, i.e., the uri prefix corresponding to the
302controller of the current action.
66e28e3f 303
01033d73 304=item $c->path_to(@path)
305
306Merges C<@path> with $c->config->{home} and returns a L<Path::Class> object.
307
308For example:
309
310 $c->path_to( 'db', 'sqlite.db' );
311
312=cut
313
314sub path_to {
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 ) }
319}
320
fbcc39ad 321=item $c->setup
322
e7f1cf73 323Initializes the dispatcher and engine, loads any plugins, and loads the
324model, view, and controller components.
fbcc39ad 325
326 $c->setup;
327
328=cut
329
330sub setup {
0319a12c 331 my ( $class, @arguments ) = @_;
599b5295 332
fbcc39ad 333 unless ( $class->isa('Catalyst') ) {
953b0e15 334
fbcc39ad 335 Catalyst::Exception->throw(
336 message => qq/'$class' does not inherit from Catalyst/ );
1c99e125 337 }
0319a12c 338
fbcc39ad 339 if ( $class->arguments ) {
340 @arguments = ( @arguments, @{ $class->arguments } );
341 }
342
343 # Process options
344 my $flags = {};
345
346 foreach (@arguments) {
347
348 if (/^-Debug$/) {
349 $flags->{log} =
350 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
351 }
352 elsif (/^-(\w+)=?(.*)$/) {
353 $flags->{ lc $1 } = $2;
354 }
355 else {
356 push @{ $flags->{plugins} }, $_;
357 }
358 }
359
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} );
365
366 for my $flag ( sort keys %{$flags} ) {
367
368 if ( my $code = $class->can( 'setup_' . $flag ) ) {
369 &$code( $class, delete $flags->{$flag} );
370 }
371 else {
372 $class->log->warn(qq/Unknown flag "$flag"/);
373 }
374 }
375
4ff0d824 376 $class->log->warn(
377 <<"EOF") if ( $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::CATALYST_SCRIPT_GEN ) );
378You are running an old script!
379
380 Please update by running:
381 catalyst.pl -nonew -scripts $class
382EOF
fbcc39ad 383
384 if ( $class->debug ) {
385
386 my @plugins = ();
387
388 {
389 no strict 'refs';
390 @plugins = grep { /^Catalyst::Plugin/ } @{"$class\::ISA"};
391 }
392
393 if (@plugins) {
8c113188 394 my $t = Text::SimpleTable->new(76);
395 $t->row($_) for @plugins;
fbcc39ad 396 $class->log->debug( "Loaded plugins:\n" . $t->draw );
397 }
398
399 my $dispatcher = $class->dispatcher;
400 my $engine = $class->engine;
401 my $home = $class->config->{home};
402
403 $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
404 $class->log->debug(qq/Loaded engine "$engine"/);
405
406 $home
407 ? ( -d $home )
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/);
411 }
412
413 # Call plugins setup
414 {
415 no warnings qw/redefine/;
416 local *setup = sub { };
417 $class->setup;
418 }
419
420 # Initialize our data structure
421 $class->components( {} );
422
423 $class->setup_components;
424
425 if ( $class->debug ) {
9d3e016e 426 my $t = Text::SimpleTable->new( [ 65, 'Class' ], [ 8, 'Type' ] );
684d10ed 427 for my $comp ( sort keys %{ $class->components } ) {
428 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
429 $t->row( $comp, $type );
430 }
fbcc39ad 431 $class->log->debug( "Loaded components:\n" . $t->draw )
8c113188 432 if ( keys %{ $class->components } );
fbcc39ad 433 }
434
435 # Add our self to components, since we are also a component
436 $class->components->{$class} = $class;
437
438 $class->setup_actions;
439
440 if ( $class->debug ) {
441 my $name = $class->config->{name} || 'Application';
442 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
443 }
444 $class->log->_flush() if $class->log->can('_flush');
445}
446
189e2a51 447=item $c->uri_for($path,[@args])
fbcc39ad 448
449Merges path with $c->request->base for absolute uri's and with
450$c->request->match for relative uri's, then returns a normalized
189e2a51 451L<URI> object. If any args are passed, they are added at the end
452of the path.
fbcc39ad 453
454=cut
455
456sub uri_for {
00e6a2b7 457 my ( $c, $path, @args ) = @_;
fbcc39ad 458 my $base = $c->request->base->clone;
459 my $basepath = $base->path;
460 $basepath =~ s/\/$//;
fdba7a9d 461 $basepath .= '/';
fbcc39ad 462 my $match = $c->request->match;
00e6a2b7 463
189e2a51 464 # massage match, empty if absolute path
fbcc39ad 465 $match =~ s/^\///;
466 $match .= '/' if $match;
6e0c45c9 467 $path ||= '';
fbcc39ad 468 $match = '' if $path =~ /^\//;
469 $path =~ s/^\///;
00e6a2b7 470
189e2a51 471 # join args with '/', or a blank string
00e6a2b7 472 my $args = ( scalar @args ? '/' . join( '/', @args ) : '' );
473 return URI->new_abs( URI->new_abs( "$path$args", "$basepath$match" ),
474 $base )->canonical;
fbcc39ad 475}
476
477=item $c->error
478
479=item $c->error($error, ...)
480
481=item $c->error($arrayref)
482
483Returns an arrayref containing error messages.
484
485 my @error = @{ $c->error };
486
487Add a new error.
488
489 $c->error('Something bad happened');
490
e7f1cf73 491Clear errors.
00e6a2b7 492
493 $c->error(0);
494
fbcc39ad 495=cut
496
497sub error {
498 my $c = shift;
00e6a2b7 499 if ( $_[0] ) {
500 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
501 push @{ $c->{error} }, @$error;
502 }
503 elsif ( defined $_[0] ) { $c->{error} = undef }
504 return $c->{error} || [];
0319a12c 505}
506
507=item $c->engine
508
e7f1cf73 509Contains the engine instance. Stringifies to the class name.
fc7ec1d9 510
0319a12c 511=item $c->log
512
513Contains the logging object. Unless it is already set Catalyst sets this up with a
e7f1cf73 514L<Catalyst::Log> object. To use your own log class:
0319a12c 515
516 $c->log( MyLogger->new );
517 $c->log->info("now logging with my own logger!");
518
e7f1cf73 519Your log class should implement the methods described in the L<Catalyst::Log>
0319a12c 520man page.
521
522=item $c->plugin( $name, $class, @args )
523
524Instant plugins for Catalyst.
525Classdata accessor/mutator will be created, class loaded and instantiated.
526
527 MyApp->plugin( 'prototype', 'HTML::Prototype' );
528
529 $c->prototype->define_javascript_functions;
530
531=cut
532
533sub plugin {
534 my ( $class, $name, $plugin, @args ) = @_;
535 $plugin->require;
536
537 if ( my $error = $UNIVERSAL::require::ERROR ) {
538 Catalyst::Exception->throw(
fbcc39ad 539 message => qq/Couldn't load instant plugin "$plugin", "$error"/ );
0319a12c 540 }
541
542 eval { $plugin->import };
543 $class->mk_classdata($name);
544 my $obj;
545 eval { $obj = $plugin->new(@args) };
546
fbcc39ad 547 if ($@) {
548 Catalyst::Exception->throw( message =>
549 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
0319a12c 550 }
551
552 $class->$name($obj);
553 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
554 if $class->debug;
555}
556
fbcc39ad 557=item $c->request
558
559=item $c->req
560
561Returns a C<Catalyst::Request> object.
562
563 my $req = $c->req;
564
565=item $c->response
566
567=item $c->res
568
569Returns a C<Catalyst::Response> object.
570
571 my $res = $c->res;
572
573=item $c->state
574
575Contains the return value of the last executed action.
576
577=item $c->stash
578
579Returns a hashref containing all your data.
580
fbcc39ad 581 print $c->stash->{foo};
582
23eb3f51 583Keys may be set in the stash by assigning to the hash reference, or by passing
584either a single hash reference or a list of key/value pairs as arguments.
585
586For example:
587
588 $c->stash->{foo} ||= 'yada';
589 $c->stash( { moose => 'majestic', qux => 0 } );
590 $c->stash( bar => 1, gorch => 2 );
591
fbcc39ad 592=cut
593
594sub stash {
595 my $c = shift;
596 if (@_) {
597 my $stash = @_ > 1 ? {@_} : $_[0];
598 while ( my ( $key, $val ) = each %$stash ) {
599 $c->{stash}->{$key} = $val;
600 }
601 }
602 return $c->{stash};
603}
604
af3ff00e 605=item $c->view($name)
606
607Get a L<Catalyst::View> instance by name.
608
609 $c->view('Foo')->do_stuff;
610
611=cut
612
613sub view {
614 my ( $c, $name ) = @_;
615 my $view = $c->comp("View::$name");
616 return $view if $view;
617 return $c->comp("V::$name");
618}
619
2c63fc07 620=item $c->welcome_message
ab2374d3 621
622Returns the Catalyst welcome HTML page.
623
624=cut
625
626sub welcome_message {
bf1f2c60 627 my $c = shift;
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 );
80cdbbff 631 $c->response->content_type('text/html; charset=utf-8');
ab2374d3 632 return <<"EOF";
80cdbbff 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">
ab2374d3 636 <head>
80cdbbff 637 <meta http-equiv="Content-Language" content="en" />
638 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
ab2374d3 639 <title>$name on Catalyst $VERSION</title>
640 <style type="text/css">
641 body {
ab2374d3 642 color: #000;
643 background-color: #eee;
644 }
645 div#content {
646 width: 640px;
80cdbbff 647 margin-left: auto;
648 margin-right: auto;
ab2374d3 649 margin-top: 10px;
650 margin-bottom: 10px;
651 text-align: left;
652 background-color: #ccc;
653 border: 1px solid #aaa;
654 -moz-border-radius: 10px;
655 }
d84c4dab 656 p, h1, h2 {
ab2374d3 657 margin-left: 20px;
658 margin-right: 20px;
16215972 659 font-family: verdana, tahoma, sans-serif;
ab2374d3 660 }
d84c4dab 661 a {
662 font-family: verdana, tahoma, sans-serif;
663 }
d114e033 664 :link, :visited {
665 text-decoration: none;
666 color: #b00;
667 border-bottom: 1px dotted #bbb;
668 }
669 :link:hover, :visited:hover {
d114e033 670 color: #555;
671 }
ab2374d3 672 div#topbar {
673 margin: 0px;
674 }
3e82a295 675 pre {
3e82a295 676 margin: 10px;
677 padding: 8px;
678 }
ab2374d3 679 div#answers {
680 padding: 8px;
681 margin: 10px;
d114e033 682 background-color: #fff;
ab2374d3 683 border: 1px solid #aaa;
684 -moz-border-radius: 10px;
685 }
686 h1 {
33108eaf 687 font-size: 0.9em;
688 font-weight: normal;
ab2374d3 689 text-align: center;
690 }
691 h2 {
692 font-size: 1.0em;
693 }
694 p {
695 font-size: 0.9em;
696 }
ae7c5252 697 p img {
698 float: right;
699 margin-left: 10px;
700 }
9619f23c 701 span#appname {
702 font-weight: bold;
33108eaf 703 font-size: 1.6em;
ab2374d3 704 }
705 </style>
706 </head>
707 <body>
708 <div id="content">
709 <div id="topbar">
9619f23c 710 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
d84c4dab 711 $VERSION</h1>
ab2374d3 712 </div>
713 <div id="answers">
ae7c5252 714 <p>
80cdbbff 715 <img src="$logo" alt="Catalyst Logo" />
ae7c5252 716 </p>
4b8cb778 717 <p>Welcome to the wonderful world of Catalyst.
f92fd545 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>
ab2374d3 721 <h2>What to do now?</h2>
4b8cb778 722 <p>That really depends on what <b>you</b> want to do.
ab2374d3 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
5db7f9a1 725 you might want to check out the documentation.</p>
bf1f2c60 726 <pre><code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
727perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
ab2374d3 728 <h2>What to do next?</h2>
f5681c92 729 <p>Next it's time to write an actual application. Use the
80cdbbff 730 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&amp;mode=all">controllers</a>,
731 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&amp;mode=all">models</a> and
732 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&amp;mode=all">views</a>,
bf1f2c60 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
80cdbbff 736 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&amp;mode=all">plugins for Catalyst on CPAN</a>,
bf1f2c60 737 you are likely to find what you need there.
f5681c92 738 </p>
739
82245cc4 740 <h2>Need help?</h2>
f5681c92 741 <p>Catalyst has a very active community. Here are the main places to
742 get in touch with us.</p>
16215972 743 <ul>
744 <li>
2b9a7d76 745 <a href="http://dev.catalyst.perl.org">Wiki</a>
16215972 746 </li>
747 <li>
748 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
749 </li>
750 <li>
ea7cd80d 751 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
16215972 752 </li>
753 </ul>
ab2374d3 754 <h2>In conclusion</h2>
4e7aa2ea 755 <p>The Catalyst team hopes you will enjoy using Catalyst as much
f5681c92 756 as we enjoyed making it. Please contact us if you have ideas
757 for improvement or other feedback.</p>
ab2374d3 758 </div>
759 </div>
760 </body>
761</html>
762EOF
763}
764
fbcc39ad 765=back
766
767=head1 INTERNAL METHODS
768
769=over 4
770
771=item $c->benchmark($coderef)
772
773Takes a coderef with arguments and returns elapsed time as float.
774
775 my ( $elapsed, $status ) = $c->benchmark( sub { return 1 } );
776 $c->log->info( sprintf "Processing took %f seconds", $elapsed );
777
778=cut
779
780sub benchmark {
781 my $c = shift;
782 my $code = shift;
783 my $time = [gettimeofday];
784 my @return = &$code(@_);
785 my $elapsed = tv_interval $time;
786 return wantarray ? ( $elapsed, @return ) : $elapsed;
787}
788
789=item $c->components
790
e7f1cf73 791Returns a hash of components.
fbcc39ad 792
e7f1cf73 793=item $c->context_class
1f9cb7c1 794
e7f1cf73 795Returns or sets the context class.
1f9cb7c1 796
fbcc39ad 797=item $c->counter
798
e7f1cf73 799Returns a hashref containing coderefs and execution counts (needed for deep recursion detection).
fbcc39ad 800
801=item $c->depth
802
e7f1cf73 803Returns the number of actions on the current internal execution stack.
fbcc39ad 804
805=item $c->dispatch
806
e7f1cf73 807Dispatches a request to actions.
fbcc39ad 808
809=cut
810
811sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
812
e7f1cf73 813=item $c->dispatcher_class
1f9cb7c1 814
e7f1cf73 815Returns or sets the dispatcher class.
1f9cb7c1 816
7f92deef 817=item dump_these
818
819Returns a list of 2-element array references (name, structure) pairs that will
820be dumped on the error page in debug mode.
821
822=cut
823
824sub dump_these {
825 my $c = shift;
826 [ Request => $c->req ], [ Response => $c->res ], [ Stash => $c->stash ],;
827}
828
e7f1cf73 829=item $c->engine_class
1f9cb7c1 830
e7f1cf73 831Returns or sets the engine class.
1f9cb7c1 832
fbcc39ad 833=item $c->execute($class, $coderef)
834
835Execute a coderef in given class and catch exceptions.
836Errors are available via $c->error.
837
838=cut
839
840sub execute {
841 my ( $c, $class, $code ) = @_;
842 $class = $c->components->{$class} || $class;
843 $c->state(0);
a0eca838 844
845 my $callsub =
846 ( caller(0) )[0]->isa('Catalyst::Action')
847 ? ( caller(2) )[3]
848 : ( caller(1) )[3];
fbcc39ad 849
850 my $action = '';
851 if ( $c->debug ) {
852 $action = "$code";
853 $action = "/$action" unless $action =~ /\-\>/;
854 $c->counter->{"$code"}++;
855
856 if ( $c->counter->{"$code"} > $RECURSION ) {
857 my $error = qq/Deep recursion detected in "$action"/;
858 $c->log->error($error);
859 $c->error($error);
860 $c->state(0);
861 return $c->state;
862 }
863
864 $action = "-> $action" if $callsub =~ /forward$/;
865 }
8767c5a3 866 push( @{ $c->stack }, $code );
fbcc39ad 867 eval {
00e6a2b7 868 if ( $c->debug )
869 {
fbcc39ad 870 my ( $elapsed, @state ) =
871 $c->benchmark( $code, $class, $c, @{ $c->req->args } );
0e7f5826 872 unless ( ( $code->name =~ /^_.*/ )
873 && ( !$c->config->{show_internal_actions} ) )
874 {
875 push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ];
876 }
fbcc39ad 877 $c->state(@state);
878 }
7cfcfd27 879 else {
00e6a2b7 880 $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 );
7cfcfd27 881 }
fbcc39ad 882 };
8767c5a3 883 pop( @{ $c->stack } );
fbcc39ad 884
885 if ( my $error = $@ ) {
886
28591cd7 887 if ( $error eq $DETACH ) { die $DETACH if $c->depth > 1 }
fbcc39ad 888 else {
889 unless ( ref $error ) {
890 chomp $error;
891 $error = qq/Caught exception "$error"/;
892 }
fbcc39ad 893 $c->error($error);
894 $c->state(0);
895 }
896 }
897 return $c->state;
898}
899
900=item $c->finalize
901
e7f1cf73 902Finalizes the request.
fbcc39ad 903
904=cut
905
906sub finalize {
907 my $c = shift;
908
369c09bc 909 for my $error ( @{ $c->error } ) {
910 $c->log->error($error);
911 }
912
fbcc39ad 913 $c->finalize_uploads;
914
915 # Error
916 if ( $#{ $c->error } >= 0 ) {
917 $c->finalize_error;
918 }
919
920 $c->finalize_headers;
921
922 # HEAD request
923 if ( $c->request->method eq 'HEAD' ) {
924 $c->response->body('');
925 }
926
927 $c->finalize_body;
928
929 return $c->response->status;
930}
931
932=item $c->finalize_body
933
e7f1cf73 934Finalizes body.
fbcc39ad 935
936=cut
937
938sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
939
940=item $c->finalize_cookies
941
e7f1cf73 942Finalizes cookies.
fbcc39ad 943
944=cut
945
946sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
947
948=item $c->finalize_error
949
e7f1cf73 950Finalizes error.
fbcc39ad 951
952=cut
953
954sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
955
956=item $c->finalize_headers
957
e7f1cf73 958Finalizes headers.
fbcc39ad 959
960=cut
961
962sub finalize_headers {
963 my $c = shift;
964
965 # Check if we already finalized headers
966 return if $c->response->{_finalized_headers};
967
968 # Handle redirects
969 if ( my $location = $c->response->redirect ) {
970 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
971 $c->response->header( Location => $location );
972 }
973
974 # Content-Length
975 if ( $c->response->body && !$c->response->content_length ) {
976 $c->response->content_length( bytes::length( $c->response->body ) );
977 }
978
979 # Errors
980 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
981 $c->response->headers->remove_header("Content-Length");
982 $c->response->body('');
983 }
984
985 $c->finalize_cookies;
986
987 $c->engine->finalize_headers( $c, @_ );
988
989 # Done
990 $c->response->{_finalized_headers} = 1;
991}
992
993=item $c->finalize_output
994
995An alias for finalize_body.
996
997=item $c->finalize_read
998
e7f1cf73 999Finalizes the input after reading is complete.
fbcc39ad 1000
1001=cut
1002
1003sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1004
1005=item $c->finalize_uploads
1006
e7f1cf73 1007Finalizes uploads. Cleans up any temporary files.
fbcc39ad 1008
1009=cut
1010
1011sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1012
a9dc674c 1013=item $c->get_action( $action, $namespace )
fbcc39ad 1014
e7f1cf73 1015Gets an action in a given namespace.
fbcc39ad 1016
1017=cut
1018
684d10ed 1019sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
fbcc39ad 1020
a9dc674c 1021=item $c->get_actions( $action, $namespace )
1022
e7f1cf73 1023Gets all actions of a given name in a namespace and all parent namespaces.
a9dc674c 1024
1025=cut
1026
1027sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1028
fbcc39ad 1029=item handle_request( $class, @arguments )
1030
e7f1cf73 1031Called to handle each HTTP request.
fbcc39ad 1032
1033=cut
1034
1035sub handle_request {
1036 my ( $class, @arguments ) = @_;
1037
1038 # Always expect worst case!
1039 my $status = -1;
1040 eval {
1041 my @stats = ();
1042
1043 my $handler = sub {
1044 my $c = $class->prepare(@arguments);
1045 $c->{stats} = \@stats;
1046 $c->dispatch;
1047 return $c->finalize;
1048 };
1049
1050 if ( $class->debug ) {
1051 my $elapsed;
1052 ( $elapsed, $status ) = $class->benchmark($handler);
1053 $elapsed = sprintf '%f', $elapsed;
1054 my $av = sprintf '%.3f',
1055 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
8c113188 1056 my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] );
fbcc39ad 1057
8c113188 1058 for my $stat (@stats) { $t->row( $stat->[0], $stat->[1] ) }
fbcc39ad 1059 $class->log->info(
1060 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
1061 }
1062 else { $status = &$handler }
1063
1064 };
1065
1066 if ( my $error = $@ ) {
1067 chomp $error;
1068 $class->log->error(qq/Caught exception in engine "$error"/);
1069 }
1070
1071 $COUNT++;
1072 $class->log->_flush() if $class->log->can('_flush');
1073 return $status;
1074}
1075
1076=item $c->prepare(@arguments)
1077
e7f1cf73 1078Creates a Catalyst context from an engine-specific request (Apache, CGI, etc.).
fbcc39ad 1079
1080=cut
1081
1082sub prepare {
1083 my ( $class, @arguments ) = @_;
1084
3cec521a 1085 $class->context_class( ref $class || $class ) unless $class->context_class;
1086 my $c = $class->context_class->new(
1087 {
1088 counter => {},
28591cd7 1089 stack => [],
3cec521a 1090 request => $class->request_class->new(
1091 {
1092 arguments => [],
1093 body_parameters => {},
1094 cookies => {},
1095 headers => HTTP::Headers->new,
1096 parameters => {},
1097 query_parameters => {},
1098 secure => 0,
1099 snippets => [],
1100 uploads => {}
1101 }
1102 ),
1103 response => $class->response_class->new(
1104 {
1105 body => '',
1106 cookies => {},
1107 headers => HTTP::Headers->new(),
1108 status => 200
1109 }
1110 ),
1111 stash => {},
1112 state => 0
1113 }
1114 );
fbcc39ad 1115
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} );
1121
1122 if ( $c->debug ) {
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 );
1129 }
1130
1131 $c->prepare_request(@arguments);
1132 $c->prepare_connection;
1133 $c->prepare_query_parameters;
1134 $c->prepare_headers;
1135 $c->prepare_cookies;
1136 $c->prepare_path;
1137
1138 # On-demand parsing
1139 $c->prepare_body unless $c->config->{parse_on_demand};
1140
1141 $c->prepare_action;
1142 my $method = $c->req->method || '';
1143 my $path = $c->req->path || '';
1144 my $address = $c->req->address || '';
1145
1146 $c->log->debug(qq/"$method" request for "$path" from $address/)
1147 if $c->debug;
1148
1149 return $c;
1150}
1151
1152=item $c->prepare_action
1153
e7f1cf73 1154Prepares action.
fbcc39ad 1155
1156=cut
1157
1158sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1159
1160=item $c->prepare_body
1161
e7f1cf73 1162Prepares message body.
fbcc39ad 1163
1164=cut
1165
1166sub prepare_body {
1167 my $c = shift;
1168
1169 # Do we run for the first time?
1170 return if defined $c->request->{_body};
1171
1172 # Initialize on-demand data
1173 $c->engine->prepare_body( $c, @_ );
1174 $c->prepare_parameters;
1175 $c->prepare_uploads;
1176
1177 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
8c113188 1178 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
fbcc39ad 1179 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1180 my $param = $c->req->body_parameters->{$key};
1181 my $value = defined($param) ? $param : '';
8c113188 1182 $t->row( $key,
fbcc39ad 1183 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1184 }
1185 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1186 }
1187}
1188
4bd82c41 1189=item $c->prepare_body_chunk( $chunk )
1190
e7f1cf73 1191Prepares a chunk of data before sending it to L<HTTP::Body>.
4bd82c41 1192
1193=cut
1194
4f5ebacd 1195sub prepare_body_chunk {
1196 my $c = shift;
4bd82c41 1197 $c->engine->prepare_body_chunk( $c, @_ );
1198}
1199
fbcc39ad 1200=item $c->prepare_body_parameters
1201
e7f1cf73 1202Prepares body parameters.
fbcc39ad 1203
1204=cut
1205
1206sub prepare_body_parameters {
1207 my $c = shift;
1208 $c->engine->prepare_body_parameters( $c, @_ );
1209}
1210
1211=item $c->prepare_connection
1212
e7f1cf73 1213Prepares connection.
fbcc39ad 1214
1215=cut
1216
1217sub prepare_connection {
1218 my $c = shift;
1219 $c->engine->prepare_connection( $c, @_ );
1220}
1221
1222=item $c->prepare_cookies
1223
e7f1cf73 1224Prepares cookies.
fbcc39ad 1225
1226=cut
1227
1228sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1229
1230=item $c->prepare_headers
1231
e7f1cf73 1232Prepares headers.
fbcc39ad 1233
1234=cut
1235
1236sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1237
1238=item $c->prepare_parameters
1239
e7f1cf73 1240Prepares parameters.
fbcc39ad 1241
1242=cut
1243
1244sub prepare_parameters {
1245 my $c = shift;
1246 $c->prepare_body_parameters;
1247 $c->engine->prepare_parameters( $c, @_ );
1248}
1249
1250=item $c->prepare_path
1251
e7f1cf73 1252Prepares path and base.
fbcc39ad 1253
1254=cut
1255
1256sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1257
1258=item $c->prepare_query_parameters
1259
e7f1cf73 1260Prepares query parameters.
fbcc39ad 1261
1262=cut
1263
1264sub prepare_query_parameters {
1265 my $c = shift;
1266
1267 $c->engine->prepare_query_parameters( $c, @_ );
1268
1269 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
8c113188 1270 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
fbcc39ad 1271 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1272 my $param = $c->req->query_parameters->{$key};
1273 my $value = defined($param) ? $param : '';
8c113188 1274 $t->row( $key,
fbcc39ad 1275 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1276 }
1277 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1278 }
1279}
1280
1281=item $c->prepare_read
1282
e7f1cf73 1283Prepares the input for reading.
fbcc39ad 1284
1285=cut
1286
1287sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1288
1289=item $c->prepare_request
1290
e7f1cf73 1291Prepares the engine request.
fbcc39ad 1292
1293=cut
1294
1295sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1296
1297=item $c->prepare_uploads
1298
e7f1cf73 1299Prepares uploads.
fbcc39ad 1300
1301=cut
1302
1303sub prepare_uploads {
1304 my $c = shift;
1305
1306 $c->engine->prepare_uploads( $c, @_ );
1307
1308 if ( $c->debug && keys %{ $c->request->uploads } ) {
8c113188 1309 my $t = Text::SimpleTable->new(
1310 [ 12, 'Key' ],
1311 [ 28, 'Filename' ],
1312 [ 18, 'Type' ],
1313 [ 9, 'Size' ]
1314 );
fbcc39ad 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) ) {
8c113188 1318 $t->row( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1319 }
1320 }
1321 $c->log->debug( "File Uploads are:\n" . $t->draw );
1322 }
1323}
1324
1325=item $c->prepare_write
1326
e7f1cf73 1327Prepares the output for writing.
fbcc39ad 1328
1329=cut
1330
1331sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1332
e7f1cf73 1333=item $c->request_class
1f9cb7c1 1334
e7f1cf73 1335Returns or sets the request class.
1f9cb7c1 1336
e7f1cf73 1337=item $c->response_class
1f9cb7c1 1338
e7f1cf73 1339Returns or sets the response class.
1f9cb7c1 1340
fbcc39ad 1341=item $c->read( [$maxlength] )
1342
e7f1cf73 1343Reads a chunk of data from the request body. This method is designed to be
fbcc39ad 1344used in a while loop, reading $maxlength bytes on every call. $maxlength
1345defaults to the size of the request if not specified.
1346
1347You have to set MyApp->config->{parse_on_demand} to use this directly.
1348
1349=cut
1350
1351sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1352
1353=item $c->run
1354
1355Starts the engine.
1356
1357=cut
1358
1359sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1360
1361=item $c->set_action( $action, $code, $namespace, $attrs )
1362
e7f1cf73 1363Sets an action in a given namespace.
fbcc39ad 1364
1365=cut
1366
1367sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1368
1369=item $c->setup_actions($component)
1370
e7f1cf73 1371Sets up actions for a component.
fbcc39ad 1372
1373=cut
1374
1375sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1376
1377=item $c->setup_components
1378
e7f1cf73 1379Sets up components.
fbcc39ad 1380
1381=cut
1382
1383sub setup_components {
1384 my $class = shift;
1385
1386 my $callback = sub {
1387 my ( $component, $context ) = @_;
1388
6deb49e9 1389 unless ( $component->isa('Catalyst::Component') ) {
fbcc39ad 1390 return $component;
1391 }
1392
76cb6276 1393 my $suffix = Catalyst::Utils::class2classsuffix($component);
fbcc39ad 1394 my $config = $class->config->{$suffix} || {};
1395
1396 my $instance;
1397
1398 eval { $instance = $component->new( $context, $config ); };
1399
1400 if ( my $error = $@ ) {
1401
1402 chomp $error;
1403
1404 Catalyst::Exception->throw( message =>
1405 qq/Couldn't instantiate component "$component", "$error"/ );
1406 }
1407
1408 Catalyst::Exception->throw( message =>
1409qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1410 )
1411 unless ref $instance;
1412 return $instance;
1413 };
1414
1415 eval {
1416 Module::Pluggable::Fast->import(
1417 name => '_catalyst_components',
1418 search => [
1419 "$class\::Controller", "$class\::C",
1420 "$class\::Model", "$class\::M",
1421 "$class\::View", "$class\::V"
1422 ],
1423 callback => $callback
1424 );
1425 };
1426
1427 if ( my $error = $@ ) {
1428
1429 chomp $error;
1430
1431 Catalyst::Exception->throw(
1432 message => qq/Couldn't load components "$error"/ );
1433 }
1434
1435 for my $component ( $class->_catalyst_components($class) ) {
1436 $class->components->{ ref $component || $component } = $component;
1437 }
1438}
1439
1440=item $c->setup_dispatcher
1441
1442=cut
1443
1444sub setup_dispatcher {
1445 my ( $class, $dispatcher ) = @_;
1446
1447 if ($dispatcher) {
1448 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1449 }
1450
1451 if ( $ENV{CATALYST_DISPATCHER} ) {
1452 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1453 }
1454
1455 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1456 $dispatcher =
1457 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1458 }
1459
1460 unless ($dispatcher) {
cb0354c6 1461 $dispatcher = $class->dispatcher_class;
fbcc39ad 1462 }
1463
1464 $dispatcher->require;
1465
1466 if ($@) {
1467 Catalyst::Exception->throw(
1468 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1469 }
1470
1471 # dispatcher instance
1472 $class->dispatcher( $dispatcher->new );
1473}
1474
1475=item $c->setup_engine
1476
1477=cut
1478
1479sub setup_engine {
1480 my ( $class, $engine ) = @_;
1481
1482 if ($engine) {
1483 $engine = 'Catalyst::Engine::' . $engine;
1484 }
1485
1486 if ( $ENV{CATALYST_ENGINE} ) {
1487 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1488 }
1489
1490 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1491 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1492 }
1493
1494 if ( !$engine && $ENV{MOD_PERL} ) {
1495
1496 # create the apache method
1497 {
1498 no strict 'refs';
1499 *{"$class\::apache"} = sub { shift->engine->apache };
1500 }
1501
1502 my ( $software, $version ) =
1503 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1504
1505 $version =~ s/_//g;
1506 $version =~ s/(\.[^.]+)\./$1/g;
1507
1508 if ( $software eq 'mod_perl' ) {
1509
1510 if ( $version >= 1.99922 ) {
1511 $engine = 'Catalyst::Engine::Apache2::MP20';
1512 }
1513
1514 elsif ( $version >= 1.9901 ) {
1515 $engine = 'Catalyst::Engine::Apache2::MP19';
1516 }
1517
1518 elsif ( $version >= 1.24 ) {
1519 $engine = 'Catalyst::Engine::Apache::MP13';
1520 }
1521
1522 else {
1523 Catalyst::Exception->throw( message =>
1524 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1525 }
1526
1527 # install the correct mod_perl handler
1528 if ( $version >= 1.9901 ) {
1529 *handler = sub : method {
1530 shift->handle_request(@_);
1531 };
1532 }
1533 else {
1534 *handler = sub ($$) { shift->handle_request(@_) };
1535 }
1536
1537 }
1538
1539 elsif ( $software eq 'Zeus-Perl' ) {
1540 $engine = 'Catalyst::Engine::Zeus';
1541 }
1542
1543 else {
1544 Catalyst::Exception->throw(
1545 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1546 }
1547 }
1548
1549 unless ($engine) {
cb0354c6 1550 $engine = $class->engine_class;
fbcc39ad 1551 }
1552
1553 $engine->require;
1554
1555 if ($@) {
1556 Catalyst::Exception->throw( message =>
1557qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1558 );
1559 }
0e7f5826 1560
d54484bf 1561 # check for old engines that are no longer compatible
1562 my $old_engine;
0e7f5826 1563 if ( $engine->isa('Catalyst::Engine::Apache')
1564 && !Catalyst::Engine::Apache->VERSION )
d54484bf 1565 {
1566 $old_engine = 1;
1567 }
0e7f5826 1568
d54484bf 1569 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 1570 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 1571 {
1572 $old_engine = 1;
1573 }
0e7f5826 1574
1575 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1576 && $engine->VERSION eq '0.01' )
d54484bf 1577 {
1578 $old_engine = 1;
1579 }
0e7f5826 1580
1581 elsif ($engine->isa('Catalyst::Engine::Zeus')
1582 && $engine->VERSION eq '0.01' )
d54484bf 1583 {
1584 $old_engine = 1;
1585 }
fbcc39ad 1586
d54484bf 1587 if ($old_engine) {
1588 Catalyst::Exception->throw( message =>
0e7f5826 1589 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 1590 );
1591 }
0e7f5826 1592
fbcc39ad 1593 # engine instance
1594 $class->engine( $engine->new );
1595}
1596
1597=item $c->setup_home
1598
1599=cut
1600
1601sub setup_home {
1602 my ( $class, $home ) = @_;
1603
1604 if ( $ENV{CATALYST_HOME} ) {
1605 $home = $ENV{CATALYST_HOME};
1606 }
1607
1608 if ( $ENV{ uc($class) . '_HOME' } ) {
1609 $home = $ENV{ uc($class) . '_HOME' };
1610 }
1611
1612 unless ($home) {
1613 $home = Catalyst::Utils::home($class);
1614 }
1615
1616 if ($home) {
1617 $class->config->{home} ||= $home;
1618 $class->config->{root} ||= dir($home)->subdir('root');
1619 }
1620}
1621
1622=item $c->setup_log
1623
1624=cut
1625
1626sub setup_log {
1627 my ( $class, $debug ) = @_;
1628
1629 unless ( $class->log ) {
1630 $class->log( Catalyst::Log->new );
1631 }
af3ff00e 1632
71f074a9 1633 my $app_flag = Catalyst::Utils::class2env($class) . '_DEBUG';
71f074a9 1634
af3ff00e 1635 if (
1636 ( defined( $ENV{CATALYST_DEBUG} ) || defined( $ENV{$app_flag} ) )
1637 ? ( $ENV{CATALYST_DEBUG} || $ENV{$app_flag} )
1638 : $debug
1639 )
1640 {
fbcc39ad 1641 no strict 'refs';
1642 *{"$class\::debug"} = sub { 1 };
1643 $class->log->debug('Debug messages enabled');
1644 }
1645}
1646
1647=item $c->setup_plugins
1648
1649=cut
1650
1651sub setup_plugins {
1652 my ( $class, $plugins ) = @_;
1653
1654 $plugins ||= [];
1655 for my $plugin ( reverse @$plugins ) {
1656
1657 $plugin = "Catalyst::Plugin::$plugin";
1658
1659 $plugin->require;
1660
1661 if ($@) {
1662 Catalyst::Exception->throw(
1663 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1664 }
1665
1666 {
1667 no strict 'refs';
1668 unshift @{"$class\::ISA"}, $plugin;
1669 }
1670 }
1671}
1672
8767c5a3 1673=item $c->stack
1674
1675Contains the stack.
1676
fbcc39ad 1677=item $c->write( $data )
1678
1679Writes $data to the output stream. When using this method directly, you will
1680need to manually set the Content-Length header to the length of your output
1681data, if known.
1682
1683=cut
1684
4f5ebacd 1685sub write {
1686 my $c = shift;
1687
1688 # Finalize headers if someone manually writes output
1689 $c->finalize_headers;
1690
1691 return $c->engine->write( $c, @_ );
1692}
fbcc39ad 1693
bf88a181 1694=item version
1695
e7f1cf73 1696Returns the Catalyst version number. Mostly useful for "powered by" messages
bf88a181 1697in template systems.
1698
1699=cut
1700
1701sub version { return $Catalyst::VERSION }
1702
23f9d934 1703=back
1704
b0bb11ec 1705=head1 INTERNAL ACTIONS
1706
1707Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>
1708C<_ACTION> and C<_END>, these are by default not shown in the private
1709action table.
1710
1711But you can deactivate this with a config parameter.
1712
1713 MyApp->config->{show_internal_actions} = 1;
1714
d2ee9760 1715=head1 CASE SENSITIVITY
1716
1717By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1718C</foo/bar>.
1719
1720But you can activate case sensitivity with a config parameter.
1721
1722 MyApp->config->{case_sensitive} = 1;
1723
fbcc39ad 1724So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1725
1726=head1 ON-DEMAND PARSER
1727
1728The request body is usually parsed at the beginning of a request,
1729but if you want to handle input yourself or speed things up a bit
1730you can enable on-demand parsing with a config parameter.
1731
1732 MyApp->config->{parse_on_demand} = 1;
1733
1734=head1 PROXY SUPPORT
1735
1736Many production servers operate using the common double-server approach, with
1737a lightweight frontend web server passing requests to a larger backend
1738server. An application running on the backend server must deal with two
1739problems: the remote user always appears to be '127.0.0.1' and the server's
1740hostname will appear to be 'localhost' regardless of the virtual host the
1741user connected through.
1742
1743Catalyst will automatically detect this situation when you are running both
1744the frontend and backend servers on the same machine. The following changes
1745are made to the request.
1746
1747 $c->req->address is set to the user's real IP address, as read from the
1748 HTTP_X_FORWARDED_FOR header.
1749
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.
1752
1753Obviously, your web server must support these 2 headers for this to work.
1754
1755In a more complex server farm environment where you may have your frontend
1756proxy server(s) on different machines, you will need to set a configuration
1757option to tell Catalyst to read the proxied data from the headers.
1758
1759 MyApp->config->{using_frontend_proxy} = 1;
1760
1761If you do not wish to use the proxy support at all, you may set:
d1a31ac6 1762
fbcc39ad 1763 MyApp->config->{ignore_frontend_proxy} = 1;
1764
1765=head1 THREAD SAFETY
1766
1767Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1768and the standalone forking HTTP server on Windows. We believe the Catalyst
1769core to be thread-safe.
1770
1771If you plan to operate in a threaded environment, remember that all other
1772modules you are using must also be thread-safe. Some modules, most notably
1773DBD::SQLite, are not thread-safe.
d1a31ac6 1774
3cb1db8c 1775=head1 SUPPORT
1776
1777IRC:
1778
1779 Join #catalyst on irc.perl.org.
1780
1781Mailing-Lists:
1782
1783 http://lists.rawmode.org/mailman/listinfo/catalyst
1784 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1985c30b 1785
432d507d 1786Web:
1787
1788 http://catalyst.perl.org
1789
fc7ec1d9 1790=head1 SEE ALSO
1791
61b1e958 1792=over 4
1793
1794=item L<Catalyst::Manual> - The Catalyst Manual
1795
e7f1cf73 1796=item L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
1797
61b1e958 1798=item L<Catalyst::Engine> - Core Engine
1799
1800=item L<Catalyst::Log> - The Log Class.
1801
1802=item L<Catalyst::Request> - The Request Object
1803
1804=item L<Catalyst::Response> - The Response Object
1805
1806=item L<Catalyst::Test> - The test suite.
1807
1808=back
fc7ec1d9 1809
15f0b5b7 1810=head1 CREDITS
fc7ec1d9 1811
15f0b5b7 1812Andy Grundman
1813
fbcc39ad 1814Andy Wardley
1815
33108eaf 1816Andreas Marienborg
1817
f4a57de4 1818Andrew Bramble
1819
15f0b5b7 1820Andrew Ford
1821
1822Andrew Ruthven
1823
fbcc39ad 1824Arthur Bergman
1825
15f0b5b7 1826Autrijus Tang
1827
0cf56dbc 1828Brian Cassidy
1829
15f0b5b7 1830Christian Hansen
1831
1832Christopher Hicks
1833
1834Dan Sully
1835
1836Danijel Milicevic
1837
1838David Naughton
1839
1840Gary Ashton Jones
1841
1842Geoff Richards
1843
1844Jesse Sheidlower
1845
fbcc39ad 1846Jesse Vincent
1847
15f0b5b7 1848Jody Belka
1849
1850Johan Lindstrom
1851
1852Juan Camacho
1853
1854Leon Brocard
1855
1856Marcus Ramberg
1857
1858Matt S Trout
1859
71c3bcc3 1860Robert Sedlacek
1861
a727119f 1862Sam Vilain
1863
1cf1c56a 1864Sascha Kiefer
1865
15f0b5b7 1866Tatsuhiko Miyagawa
fc7ec1d9 1867
51f0308d 1868Ulf Edvinsson
1869
bdcb95ef 1870Yuval Kogman
1871
51f0308d 1872=head1 AUTHOR
1873
1874Sebastian Riedel, C<sri@oook.de>
1875
fc7ec1d9 1876=head1 LICENSE
1877
9ce5ab63 1878This library is free software, you can redistribute it and/or modify it under
41ca9ba7 1879the same terms as Perl itself.
fc7ec1d9 1880
1881=cut
1882
18831;