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