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