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