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