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