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