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