Added some 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(
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
1f9cb7c1 792=item $c->context_class($class)
793
794Contains the context class.
795
fbcc39ad 796=item $c->counter
797
798Returns a hashref containing coderefs and execution counts.
799(Needed for deep recursion detection)
800
801=item $c->depth
802
803Returns the actual forward depth.
804
805=item $c->dispatch
806
807Dispatch request to actions.
808
809=cut
810
811sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
812
1f9cb7c1 813=item $c->dispatcher_class($class)
814
815Contains the dispatcher class.
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
1f9cb7c1 829=item $c->engine_class($class)
830
831Contains the engine class.
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);
844 my $callsub = ( caller(1) )[3];
845
846 my $action = '';
847 if ( $c->debug ) {
848 $action = "$code";
849 $action = "/$action" unless $action =~ /\-\>/;
850 $c->counter->{"$code"}++;
851
852 if ( $c->counter->{"$code"} > $RECURSION ) {
853 my $error = qq/Deep recursion detected in "$action"/;
854 $c->log->error($error);
855 $c->error($error);
856 $c->state(0);
857 return $c->state;
858 }
859
860 $action = "-> $action" if $callsub =~ /forward$/;
861 }
862 $c->{depth}++;
863 eval {
00e6a2b7 864 if ( $c->debug )
865 {
fbcc39ad 866 my ( $elapsed, @state ) =
867 $c->benchmark( $code, $class, $c, @{ $c->req->args } );
0e7f5826 868 unless ( ( $code->name =~ /^_.*/ )
869 && ( !$c->config->{show_internal_actions} ) )
870 {
871 push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ];
872 }
fbcc39ad 873 $c->state(@state);
874 }
7cfcfd27 875 else {
00e6a2b7 876 $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 );
7cfcfd27 877 }
fbcc39ad 878 };
879 $c->{depth}--;
880
881 if ( my $error = $@ ) {
882
883 if ( $error eq $DETACH ) { die $DETACH if $c->{depth} > 1 }
884 else {
885 unless ( ref $error ) {
886 chomp $error;
887 $error = qq/Caught exception "$error"/;
888 }
fbcc39ad 889 $c->error($error);
890 $c->state(0);
891 }
892 }
893 return $c->state;
894}
895
896=item $c->finalize
897
898Finalize request.
899
900=cut
901
902sub finalize {
903 my $c = shift;
904
369c09bc 905 for my $error ( @{ $c->error } ) {
906 $c->log->error($error);
907 }
908
fbcc39ad 909 $c->finalize_uploads;
910
911 # Error
912 if ( $#{ $c->error } >= 0 ) {
913 $c->finalize_error;
914 }
915
916 $c->finalize_headers;
917
918 # HEAD request
919 if ( $c->request->method eq 'HEAD' ) {
920 $c->response->body('');
921 }
922
923 $c->finalize_body;
924
925 return $c->response->status;
926}
927
928=item $c->finalize_body
929
930Finalize body.
931
932=cut
933
934sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
935
936=item $c->finalize_cookies
937
938Finalize cookies.
939
940=cut
941
942sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
943
944=item $c->finalize_error
945
946Finalize error.
947
948=cut
949
950sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
951
952=item $c->finalize_headers
953
954Finalize headers.
955
956=cut
957
958sub finalize_headers {
959 my $c = shift;
960
961 # Check if we already finalized headers
962 return if $c->response->{_finalized_headers};
963
964 # Handle redirects
965 if ( my $location = $c->response->redirect ) {
966 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
967 $c->response->header( Location => $location );
968 }
969
970 # Content-Length
971 if ( $c->response->body && !$c->response->content_length ) {
972 $c->response->content_length( bytes::length( $c->response->body ) );
973 }
974
975 # Errors
976 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
977 $c->response->headers->remove_header("Content-Length");
978 $c->response->body('');
979 }
980
981 $c->finalize_cookies;
982
983 $c->engine->finalize_headers( $c, @_ );
984
985 # Done
986 $c->response->{_finalized_headers} = 1;
987}
988
989=item $c->finalize_output
990
991An alias for finalize_body.
992
993=item $c->finalize_read
994
995Finalize the input after reading is complete.
996
997=cut
998
999sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1000
1001=item $c->finalize_uploads
1002
1003Finalize uploads. Cleans up any temporary files.
1004
1005=cut
1006
1007sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1008
a9dc674c 1009=item $c->get_action( $action, $namespace )
fbcc39ad 1010
1011Get an action in a given namespace.
1012
1013=cut
1014
684d10ed 1015sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
fbcc39ad 1016
a9dc674c 1017=item $c->get_actions( $action, $namespace )
1018
1019Get all actions of a given name in a namespace and all base namespaces.
1020
1021=cut
1022
1023sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1024
fbcc39ad 1025=item handle_request( $class, @arguments )
1026
1027Handles the request.
1028
1029=cut
1030
1031sub handle_request {
1032 my ( $class, @arguments ) = @_;
1033
1034 # Always expect worst case!
1035 my $status = -1;
1036 eval {
1037 my @stats = ();
1038
1039 my $handler = sub {
1040 my $c = $class->prepare(@arguments);
1041 $c->{stats} = \@stats;
1042 $c->dispatch;
1043 return $c->finalize;
1044 };
1045
1046 if ( $class->debug ) {
1047 my $elapsed;
1048 ( $elapsed, $status ) = $class->benchmark($handler);
1049 $elapsed = sprintf '%f', $elapsed;
1050 my $av = sprintf '%.3f',
1051 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
8c113188 1052 my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] );
fbcc39ad 1053
8c113188 1054 for my $stat (@stats) { $t->row( $stat->[0], $stat->[1] ) }
fbcc39ad 1055 $class->log->info(
1056 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
1057 }
1058 else { $status = &$handler }
1059
1060 };
1061
1062 if ( my $error = $@ ) {
1063 chomp $error;
1064 $class->log->error(qq/Caught exception in engine "$error"/);
1065 }
1066
1067 $COUNT++;
1068 $class->log->_flush() if $class->log->can('_flush');
1069 return $status;
1070}
1071
1072=item $c->prepare(@arguments)
1073
1074Turns the engine-specific request( Apache, CGI ... )
1075into a Catalyst context .
1076
1077=cut
1078
1079sub prepare {
1080 my ( $class, @arguments ) = @_;
1081
3cec521a 1082 $class->context_class( ref $class || $class ) unless $class->context_class;
1083 my $c = $class->context_class->new(
1084 {
1085 counter => {},
1086 depth => 0,
1087 request => $class->request_class->new(
1088 {
1089 arguments => [],
1090 body_parameters => {},
1091 cookies => {},
1092 headers => HTTP::Headers->new,
1093 parameters => {},
1094 query_parameters => {},
1095 secure => 0,
1096 snippets => [],
1097 uploads => {}
1098 }
1099 ),
1100 response => $class->response_class->new(
1101 {
1102 body => '',
1103 cookies => {},
1104 headers => HTTP::Headers->new(),
1105 status => 200
1106 }
1107 ),
1108 stash => {},
1109 state => 0
1110 }
1111 );
fbcc39ad 1112
1113 # For on-demand data
1114 $c->request->{_context} = $c;
1115 $c->response->{_context} = $c;
1116 weaken( $c->request->{_context} );
1117 weaken( $c->response->{_context} );
1118
1119 if ( $c->debug ) {
1120 my $secs = time - $START || 1;
1121 my $av = sprintf '%.3f', $COUNT / $secs;
1122 $c->log->debug('**********************************');
1123 $c->log->debug("* Request $COUNT ($av/s) [$$]");
1124 $c->log->debug('**********************************');
1125 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1126 }
1127
1128 $c->prepare_request(@arguments);
1129 $c->prepare_connection;
1130 $c->prepare_query_parameters;
1131 $c->prepare_headers;
1132 $c->prepare_cookies;
1133 $c->prepare_path;
1134
1135 # On-demand parsing
1136 $c->prepare_body unless $c->config->{parse_on_demand};
1137
1138 $c->prepare_action;
1139 my $method = $c->req->method || '';
1140 my $path = $c->req->path || '';
1141 my $address = $c->req->address || '';
1142
1143 $c->log->debug(qq/"$method" request for "$path" from $address/)
1144 if $c->debug;
1145
1146 return $c;
1147}
1148
1149=item $c->prepare_action
1150
1151Prepare action.
1152
1153=cut
1154
1155sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1156
1157=item $c->prepare_body
1158
1159Prepare message body.
1160
1161=cut
1162
1163sub prepare_body {
1164 my $c = shift;
1165
1166 # Do we run for the first time?
1167 return if defined $c->request->{_body};
1168
1169 # Initialize on-demand data
1170 $c->engine->prepare_body( $c, @_ );
1171 $c->prepare_parameters;
1172 $c->prepare_uploads;
1173
1174 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
8c113188 1175 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
fbcc39ad 1176 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1177 my $param = $c->req->body_parameters->{$key};
1178 my $value = defined($param) ? $param : '';
8c113188 1179 $t->row( $key,
fbcc39ad 1180 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1181 }
1182 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1183 }
1184}
1185
4bd82c41 1186=item $c->prepare_body_chunk( $chunk )
1187
1188Prepare a chunk of data before sending it to HTTP::Body.
1189
1190=cut
1191
4f5ebacd 1192sub prepare_body_chunk {
1193 my $c = shift;
4bd82c41 1194 $c->engine->prepare_body_chunk( $c, @_ );
1195}
1196
fbcc39ad 1197=item $c->prepare_body_parameters
1198
1199Prepare body parameters.
1200
1201=cut
1202
1203sub prepare_body_parameters {
1204 my $c = shift;
1205 $c->engine->prepare_body_parameters( $c, @_ );
1206}
1207
1208=item $c->prepare_connection
1209
1210Prepare connection.
1211
1212=cut
1213
1214sub prepare_connection {
1215 my $c = shift;
1216 $c->engine->prepare_connection( $c, @_ );
1217}
1218
1219=item $c->prepare_cookies
1220
1221Prepare cookies.
1222
1223=cut
1224
1225sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1226
1227=item $c->prepare_headers
1228
1229Prepare headers.
1230
1231=cut
1232
1233sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1234
1235=item $c->prepare_parameters
1236
1237Prepare parameters.
1238
1239=cut
1240
1241sub prepare_parameters {
1242 my $c = shift;
1243 $c->prepare_body_parameters;
1244 $c->engine->prepare_parameters( $c, @_ );
1245}
1246
1247=item $c->prepare_path
1248
1249Prepare path and base.
1250
1251=cut
1252
1253sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1254
1255=item $c->prepare_query_parameters
1256
1257Prepare query parameters.
1258
1259=cut
1260
1261sub prepare_query_parameters {
1262 my $c = shift;
1263
1264 $c->engine->prepare_query_parameters( $c, @_ );
1265
1266 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
8c113188 1267 my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
fbcc39ad 1268 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1269 my $param = $c->req->query_parameters->{$key};
1270 my $value = defined($param) ? $param : '';
8c113188 1271 $t->row( $key,
fbcc39ad 1272 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1273 }
1274 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1275 }
1276}
1277
1278=item $c->prepare_read
1279
1280Prepare the input for reading.
1281
1282=cut
1283
1284sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1285
1286=item $c->prepare_request
1287
1288Prepare the engine request.
1289
1290=cut
1291
1292sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1293
1294=item $c->prepare_uploads
1295
1296Prepare uploads.
1297
1298=cut
1299
1300sub prepare_uploads {
1301 my $c = shift;
1302
1303 $c->engine->prepare_uploads( $c, @_ );
1304
1305 if ( $c->debug && keys %{ $c->request->uploads } ) {
8c113188 1306 my $t = Text::SimpleTable->new(
1307 [ 12, 'Key' ],
1308 [ 28, 'Filename' ],
1309 [ 18, 'Type' ],
1310 [ 9, 'Size' ]
1311 );
fbcc39ad 1312 for my $key ( sort keys %{ $c->request->uploads } ) {
1313 my $upload = $c->request->uploads->{$key};
1314 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
8c113188 1315 $t->row( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1316 }
1317 }
1318 $c->log->debug( "File Uploads are:\n" . $t->draw );
1319 }
1320}
1321
1322=item $c->prepare_write
1323
1324Prepare the output for writing.
1325
1326=cut
1327
1328sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1329
1f9cb7c1 1330=item $c->request_class($class)
1331
1332Contains the request class.
1333
1334=item $c->response_class($class)
1335
1336Contains the response class.
1337
fbcc39ad 1338=item $c->read( [$maxlength] )
1339
1340Read a chunk of data from the request body. This method is designed to be
1341used in a while loop, reading $maxlength bytes on every call. $maxlength
1342defaults to the size of the request if not specified.
1343
1344You have to set MyApp->config->{parse_on_demand} to use this directly.
1345
1346=cut
1347
1348sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1349
1350=item $c->run
1351
1352Starts the engine.
1353
1354=cut
1355
1356sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1357
1358=item $c->set_action( $action, $code, $namespace, $attrs )
1359
1360Set an action in a given namespace.
1361
1362=cut
1363
1364sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1365
1366=item $c->setup_actions($component)
1367
1368Setup actions for a component.
1369
1370=cut
1371
1372sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1373
1374=item $c->setup_components
1375
1376Setup components.
1377
1378=cut
1379
1380sub setup_components {
1381 my $class = shift;
1382
1383 my $callback = sub {
1384 my ( $component, $context ) = @_;
1385
6deb49e9 1386 unless ( $component->isa('Catalyst::Component') ) {
fbcc39ad 1387 return $component;
1388 }
1389
71f074a9 1390 my $suffix = Catalyst::Utils::class2classsuffix($class);
fbcc39ad 1391 my $config = $class->config->{$suffix} || {};
1392
1393 my $instance;
1394
1395 eval { $instance = $component->new( $context, $config ); };
1396
1397 if ( my $error = $@ ) {
1398
1399 chomp $error;
1400
1401 Catalyst::Exception->throw( message =>
1402 qq/Couldn't instantiate component "$component", "$error"/ );
1403 }
1404
1405 Catalyst::Exception->throw( message =>
1406qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1407 )
1408 unless ref $instance;
1409 return $instance;
1410 };
1411
1412 eval {
1413 Module::Pluggable::Fast->import(
1414 name => '_catalyst_components',
1415 search => [
1416 "$class\::Controller", "$class\::C",
1417 "$class\::Model", "$class\::M",
1418 "$class\::View", "$class\::V"
1419 ],
1420 callback => $callback
1421 );
1422 };
1423
1424 if ( my $error = $@ ) {
1425
1426 chomp $error;
1427
1428 Catalyst::Exception->throw(
1429 message => qq/Couldn't load components "$error"/ );
1430 }
1431
1432 for my $component ( $class->_catalyst_components($class) ) {
1433 $class->components->{ ref $component || $component } = $component;
1434 }
1435}
1436
1437=item $c->setup_dispatcher
1438
1439=cut
1440
1441sub setup_dispatcher {
1442 my ( $class, $dispatcher ) = @_;
1443
1444 if ($dispatcher) {
1445 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1446 }
1447
1448 if ( $ENV{CATALYST_DISPATCHER} ) {
1449 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1450 }
1451
1452 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1453 $dispatcher =
1454 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1455 }
1456
1457 unless ($dispatcher) {
cb0354c6 1458 $dispatcher = $class->dispatcher_class;
fbcc39ad 1459 }
1460
1461 $dispatcher->require;
1462
1463 if ($@) {
1464 Catalyst::Exception->throw(
1465 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1466 }
1467
1468 # dispatcher instance
1469 $class->dispatcher( $dispatcher->new );
1470}
1471
1472=item $c->setup_engine
1473
1474=cut
1475
1476sub setup_engine {
1477 my ( $class, $engine ) = @_;
1478
1479 if ($engine) {
1480 $engine = 'Catalyst::Engine::' . $engine;
1481 }
1482
1483 if ( $ENV{CATALYST_ENGINE} ) {
1484 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1485 }
1486
1487 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1488 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1489 }
1490
1491 if ( !$engine && $ENV{MOD_PERL} ) {
1492
1493 # create the apache method
1494 {
1495 no strict 'refs';
1496 *{"$class\::apache"} = sub { shift->engine->apache };
1497 }
1498
1499 my ( $software, $version ) =
1500 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1501
1502 $version =~ s/_//g;
1503 $version =~ s/(\.[^.]+)\./$1/g;
1504
1505 if ( $software eq 'mod_perl' ) {
1506
1507 if ( $version >= 1.99922 ) {
1508 $engine = 'Catalyst::Engine::Apache2::MP20';
1509 }
1510
1511 elsif ( $version >= 1.9901 ) {
1512 $engine = 'Catalyst::Engine::Apache2::MP19';
1513 }
1514
1515 elsif ( $version >= 1.24 ) {
1516 $engine = 'Catalyst::Engine::Apache::MP13';
1517 }
1518
1519 else {
1520 Catalyst::Exception->throw( message =>
1521 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1522 }
1523
1524 # install the correct mod_perl handler
1525 if ( $version >= 1.9901 ) {
1526 *handler = sub : method {
1527 shift->handle_request(@_);
1528 };
1529 }
1530 else {
1531 *handler = sub ($$) { shift->handle_request(@_) };
1532 }
1533
1534 }
1535
1536 elsif ( $software eq 'Zeus-Perl' ) {
1537 $engine = 'Catalyst::Engine::Zeus';
1538 }
1539
1540 else {
1541 Catalyst::Exception->throw(
1542 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1543 }
1544 }
1545
1546 unless ($engine) {
cb0354c6 1547 $engine = $class->engine_class;
fbcc39ad 1548 }
1549
1550 $engine->require;
1551
1552 if ($@) {
1553 Catalyst::Exception->throw( message =>
1554qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1555 );
1556 }
0e7f5826 1557
d54484bf 1558 # check for old engines that are no longer compatible
1559 my $old_engine;
0e7f5826 1560 if ( $engine->isa('Catalyst::Engine::Apache')
1561 && !Catalyst::Engine::Apache->VERSION )
d54484bf 1562 {
1563 $old_engine = 1;
1564 }
0e7f5826 1565
d54484bf 1566 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 1567 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 1568 {
1569 $old_engine = 1;
1570 }
0e7f5826 1571
1572 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1573 && $engine->VERSION eq '0.01' )
d54484bf 1574 {
1575 $old_engine = 1;
1576 }
0e7f5826 1577
1578 elsif ($engine->isa('Catalyst::Engine::Zeus')
1579 && $engine->VERSION eq '0.01' )
d54484bf 1580 {
1581 $old_engine = 1;
1582 }
fbcc39ad 1583
d54484bf 1584 if ($old_engine) {
1585 Catalyst::Exception->throw( message =>
0e7f5826 1586 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 1587 );
1588 }
0e7f5826 1589
fbcc39ad 1590 # engine instance
1591 $class->engine( $engine->new );
1592}
1593
1594=item $c->setup_home
1595
1596=cut
1597
1598sub setup_home {
1599 my ( $class, $home ) = @_;
1600
1601 if ( $ENV{CATALYST_HOME} ) {
1602 $home = $ENV{CATALYST_HOME};
1603 }
1604
1605 if ( $ENV{ uc($class) . '_HOME' } ) {
1606 $home = $ENV{ uc($class) . '_HOME' };
1607 }
1608
1609 unless ($home) {
1610 $home = Catalyst::Utils::home($class);
1611 }
1612
1613 if ($home) {
1614 $class->config->{home} ||= $home;
1615 $class->config->{root} ||= dir($home)->subdir('root');
1616 }
1617}
1618
1619=item $c->setup_log
1620
1621=cut
1622
1623sub setup_log {
1624 my ( $class, $debug ) = @_;
1625
1626 unless ( $class->log ) {
1627 $class->log( Catalyst::Log->new );
1628 }
af3ff00e 1629
71f074a9 1630 my $app_flag = Catalyst::Utils::class2env($class) . '_DEBUG';
71f074a9 1631
af3ff00e 1632 if (
1633 ( defined( $ENV{CATALYST_DEBUG} ) || defined( $ENV{$app_flag} ) )
1634 ? ( $ENV{CATALYST_DEBUG} || $ENV{$app_flag} )
1635 : $debug
1636 )
1637 {
fbcc39ad 1638 no strict 'refs';
1639 *{"$class\::debug"} = sub { 1 };
1640 $class->log->debug('Debug messages enabled');
1641 }
1642}
1643
1644=item $c->setup_plugins
1645
1646=cut
1647
1648sub setup_plugins {
1649 my ( $class, $plugins ) = @_;
1650
1651 $plugins ||= [];
1652 for my $plugin ( reverse @$plugins ) {
1653
1654 $plugin = "Catalyst::Plugin::$plugin";
1655
1656 $plugin->require;
1657
1658 if ($@) {
1659 Catalyst::Exception->throw(
1660 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1661 }
1662
1663 {
1664 no strict 'refs';
1665 unshift @{"$class\::ISA"}, $plugin;
1666 }
1667 }
1668}
1669
1670=item $c->write( $data )
1671
1672Writes $data to the output stream. When using this method directly, you will
1673need to manually set the Content-Length header to the length of your output
1674data, if known.
1675
1676=cut
1677
4f5ebacd 1678sub write {
1679 my $c = shift;
1680
1681 # Finalize headers if someone manually writes output
1682 $c->finalize_headers;
1683
1684 return $c->engine->write( $c, @_ );
1685}
fbcc39ad 1686
bf88a181 1687=item version
1688
1689Returns the Catalyst version number. mostly useful for powered by messages
1690in template systems.
1691
1692=cut
1693
1694sub version { return $Catalyst::VERSION }
1695
23f9d934 1696=back
1697
b0bb11ec 1698=head1 INTERNAL ACTIONS
1699
1700Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>
1701C<_ACTION> and C<_END>, these are by default not shown in the private
1702action table.
1703
1704But you can deactivate this with a config parameter.
1705
1706 MyApp->config->{show_internal_actions} = 1;
1707
d2ee9760 1708=head1 CASE SENSITIVITY
1709
1710By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1711C</foo/bar>.
1712
1713But you can activate case sensitivity with a config parameter.
1714
1715 MyApp->config->{case_sensitive} = 1;
1716
fbcc39ad 1717So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1718
1719=head1 ON-DEMAND PARSER
1720
1721The request body is usually parsed at the beginning of a request,
1722but if you want to handle input yourself or speed things up a bit
1723you can enable on-demand parsing with a config parameter.
1724
1725 MyApp->config->{parse_on_demand} = 1;
1726
1727=head1 PROXY SUPPORT
1728
1729Many production servers operate using the common double-server approach, with
1730a lightweight frontend web server passing requests to a larger backend
1731server. An application running on the backend server must deal with two
1732problems: the remote user always appears to be '127.0.0.1' and the server's
1733hostname will appear to be 'localhost' regardless of the virtual host the
1734user connected through.
1735
1736Catalyst will automatically detect this situation when you are running both
1737the frontend and backend servers on the same machine. The following changes
1738are made to the request.
1739
1740 $c->req->address is set to the user's real IP address, as read from the
1741 HTTP_X_FORWARDED_FOR header.
1742
1743 The host value for $c->req->base and $c->req->uri is set to the real host,
1744 as read from the HTTP_X_FORWARDED_HOST header.
1745
1746Obviously, your web server must support these 2 headers for this to work.
1747
1748In a more complex server farm environment where you may have your frontend
1749proxy server(s) on different machines, you will need to set a configuration
1750option to tell Catalyst to read the proxied data from the headers.
1751
1752 MyApp->config->{using_frontend_proxy} = 1;
1753
1754If you do not wish to use the proxy support at all, you may set:
d1a31ac6 1755
fbcc39ad 1756 MyApp->config->{ignore_frontend_proxy} = 1;
1757
1758=head1 THREAD SAFETY
1759
1760Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1761and the standalone forking HTTP server on Windows. We believe the Catalyst
1762core to be thread-safe.
1763
1764If you plan to operate in a threaded environment, remember that all other
1765modules you are using must also be thread-safe. Some modules, most notably
1766DBD::SQLite, are not thread-safe.
d1a31ac6 1767
3cb1db8c 1768=head1 SUPPORT
1769
1770IRC:
1771
1772 Join #catalyst on irc.perl.org.
1773
1774Mailing-Lists:
1775
1776 http://lists.rawmode.org/mailman/listinfo/catalyst
1777 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1985c30b 1778
432d507d 1779Web:
1780
1781 http://catalyst.perl.org
1782
fc7ec1d9 1783=head1 SEE ALSO
1784
61b1e958 1785=over 4
1786
1787=item L<Catalyst::Manual> - The Catalyst Manual
1788
1789=item L<Catalyst::Engine> - Core Engine
1790
1791=item L<Catalyst::Log> - The Log Class.
1792
1793=item L<Catalyst::Request> - The Request Object
1794
1795=item L<Catalyst::Response> - The Response Object
1796
1797=item L<Catalyst::Test> - The test suite.
1798
1799=back
fc7ec1d9 1800
15f0b5b7 1801=head1 CREDITS
fc7ec1d9 1802
15f0b5b7 1803Andy Grundman
1804
fbcc39ad 1805Andy Wardley
1806
33108eaf 1807Andreas Marienborg
1808
f4a57de4 1809Andrew Bramble
1810
15f0b5b7 1811Andrew Ford
1812
1813Andrew Ruthven
1814
fbcc39ad 1815Arthur Bergman
1816
15f0b5b7 1817Autrijus Tang
1818
0cf56dbc 1819Brian Cassidy
1820
15f0b5b7 1821Christian Hansen
1822
1823Christopher Hicks
1824
1825Dan Sully
1826
1827Danijel Milicevic
1828
1829David Naughton
1830
1831Gary Ashton Jones
1832
1833Geoff Richards
1834
1835Jesse Sheidlower
1836
fbcc39ad 1837Jesse Vincent
1838
15f0b5b7 1839Jody Belka
1840
1841Johan Lindstrom
1842
1843Juan Camacho
1844
1845Leon Brocard
1846
1847Marcus Ramberg
1848
1849Matt S Trout
1850
71c3bcc3 1851Robert Sedlacek
1852
a727119f 1853Sam Vilain
1854
1cf1c56a 1855Sascha Kiefer
1856
15f0b5b7 1857Tatsuhiko Miyagawa
fc7ec1d9 1858
51f0308d 1859Ulf Edvinsson
1860
bdcb95ef 1861Yuval Kogman
1862
51f0308d 1863=head1 AUTHOR
1864
1865Sebastian Riedel, C<sri@oook.de>
1866
fc7ec1d9 1867=head1 LICENSE
1868
9ce5ab63 1869This library is free software, you can redistribute it and/or modify it under
41ca9ba7 1870the same terms as Perl itself.
fc7ec1d9 1871
1872=cut
1873
18741;