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