Catalyst::View::Mason fixed
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
CommitLineData
fc7ec1d9 1package Catalyst;
2
e9e51b8f 3# we don't need really need this, but if we load it before MRO::Compat gets
4# loaded (via Moose and Class::MOP), we can avoid some nasty warnings
5use Class::C3;
6
a7caa492 7use Moose;
74c89dea 8use Class::MOP::Object ();
a7caa492 9extends 'Catalyst::Component';
fbcc39ad 10use bytes;
edb20ed3 11use Scope::Upper ();
a2f2cde9 12use Catalyst::Exception;
fc7ec1d9 13use Catalyst::Log;
fbcc39ad 14use Catalyst::Request;
15use Catalyst::Request::Upload;
16use Catalyst::Response;
812a28c9 17use Catalyst::Utils;
31375184 18use Catalyst::Controller;
364d7324 19use Devel::InnerPackage ();
8f62c91a 20use File::stat;
c50f595c 21use Module::Pluggable::Object ();
c50f595c 22use Text::SimpleTable ();
23use Path::Class::Dir ();
24use Path::Class::File ();
fbcc39ad 25use Time::HiRes qw/gettimeofday tv_interval/;
c50f595c 26use URI ();
933ba403 27use URI::http;
28use URI::https;
6a4a7002 29use Scalar::Util qw/weaken blessed/;
5513038d 30use Tree::Simple qw/use_weak_refs/;
31use Tree::Simple::Visitor::FindByUID;
261c571e 32use attributes;
5789a3d8 33use utf8;
c45c5d37 34use Carp qw/croak carp/;
fc7ec1d9 35
f63c03e4 36BEGIN { require 5.008001; }
37
8a440eba 38has stack => (is => 'ro', default => sub { [] });
6680c772 39has stash => (is => 'rw', default => sub { {} });
40has state => (is => 'rw', default => 0);
b6d4ee6e 41has stats => (is => 'rw');
42has action => (is => 'rw');
6680c772 43has counter => (is => 'rw', default => sub { {} });
44has request => (is => 'rw', default => sub { $_[0]->request_class->new({}) }, required => 1, lazy => 1);
45has response => (is => 'rw', default => sub { $_[0]->response_class->new({}) }, required => 1, lazy => 1);
e63bdf38 46has namespace => (is => 'rw');
47
8767c5a3 48sub depth { scalar @{ shift->stack || [] }; }
0fc2d522 49sub comp { shift->component(@_) }
6680c772 50
51sub req {
52 # carp "the use of req() is deprecated in favour of request()";
53 my $self = shift; return $self->request(@_);
54}
55sub res {
56 # carp "the use of res() is deprecated in favour of response()";
57 my $self = shift; return $self->response(@_);
58}
fbcc39ad 59
60# For backwards compatibility
0fc2d522 61sub finalize_output { shift->finalize_body(@_) };
fbcc39ad 62
63# For statistics
64our $COUNT = 1;
65our $START = time;
66our $RECURSION = 1000;
67our $DETACH = "catalyst_detach\n";
55424863 68our $GO = "catalyst_go\n";
fbcc39ad 69
b6d4ee6e 70#I imagine that very few of these really need to be class variables. if any.
71#maybe we should just make them attributes with a default?
fbcc39ad 72__PACKAGE__->mk_classdata($_)
3cec521a 73 for qw/components arguments dispatcher engine log dispatcher_class
ac5c933b 74 engine_class context_class request_class response_class stats_class
dc5f035e 75 setup_finished/;
cb0354c6 76
3cec521a 77__PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
78__PACKAGE__->engine_class('Catalyst::Engine::CGI');
79__PACKAGE__->request_class('Catalyst::Request');
80__PACKAGE__->response_class('Catalyst::Response');
dc5f035e 81__PACKAGE__->stats_class('Catalyst::Stats');
fbcc39ad 82
6415bb4d 83# Remember to update this in Catalyst::Runtime as well!
84
76b3b586 85our $VERSION = '5.8000_04';
189e2a51 86
fbcc39ad 87sub import {
88 my ( $class, @arguments ) = @_;
89
90 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
91 # callers @ISA.
92 return unless $class eq 'Catalyst';
93
84ff88cf 94 my $caller = caller();
95 return if $caller eq 'main';
96 my $meta = Moose::Meta::Class->initialize($caller);
97 #Moose->import({ into => $caller }); #do we want to do this?
fbcc39ad 98
99 unless ( $caller->isa('Catalyst') ) {
84ff88cf 100 my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
101 $meta->superclasses(@superclasses);
102 }
103 unless( $meta->has_method('meta') ){
104 $meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
fbcc39ad 105 }
106
107 $caller->arguments( [@arguments] );
108 $caller->setup_home;
109}
fc7ec1d9 110
111=head1 NAME
112
113Catalyst - The Elegant MVC Web Application Framework
114
115=head1 SYNOPSIS
116
e7ad3b81 117See the L<Catalyst::Manual> distribution for comprehensive
118documentation and tutorials.
119
86418559 120 # Install Catalyst::Devel for helpers and other development tools
b4b01a8a 121 # use the helper to create a new application
91864987 122 catalyst.pl MyApp
fc7ec1d9 123
124 # add models, views, controllers
2f381252 125 script/myapp_create.pl model MyDatabase DBIC::Schema create=static dbi:SQLite:/path/to/db
cc95842f 126 script/myapp_create.pl view MyTemplate TT
0ef52a96 127 script/myapp_create.pl controller Search
fc7ec1d9 128
e7f1cf73 129 # built in testserver -- use -r to restart automatically on changes
cc95842f 130 # --help to see all available options
ae4e40a7 131 script/myapp_server.pl
fc7ec1d9 132
0ef52a96 133 # command line testing interface
ae4e40a7 134 script/myapp_test.pl /yada
fc7ec1d9 135
b4b01a8a 136 ### in lib/MyApp.pm
0ef52a96 137 use Catalyst qw/-Debug/; # include plugins here as well
ac5c933b 138
85d9fce6 139 ### In lib/MyApp/Controller/Root.pm (autocreated)
0ef52a96 140 sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc.
ae1e6b59 141 my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2
142 $c->stash->{template} = 'foo.tt'; # set the template
0ef52a96 143 # lookup something from db -- stash vars are passed to TT
ac5c933b 144 $c->stash->{data} =
b4b01a8a 145 $c->model('Database::Foo')->search( { country => $args[0] } );
0ef52a96 146 if ( $c->req->params->{bar} ) { # access GET or POST parameters
147 $c->forward( 'bar' ); # process another action
ac5c933b 148 # do something else after forward returns
0ef52a96 149 }
150 }
ac5c933b 151
ae1e6b59 152 # The foo.tt TT template can use the stash data from the database
0ef52a96 153 [% WHILE (item = data.next) %]
154 [% item.foo %]
155 [% END %]
ac5c933b 156
0ef52a96 157 # called for /bar/of/soap, /bar/of/soap/10, etc.
158 sub bar : Path('/bar/of/soap') { ... }
fc7ec1d9 159
ae1e6b59 160 # called for all actions, from the top-most controller downwards
ac5c933b 161 sub auto : Private {
0ef52a96 162 my ( $self, $c ) = @_;
b4b01a8a 163 if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication
0ef52a96 164 $c->res->redirect( '/login' ); # require login
165 return 0; # abort request and go immediately to end()
166 }
ae1e6b59 167 return 1; # success; carry on to next action
0ef52a96 168 }
ac5c933b 169
ae1e6b59 170 # called after all actions are finished
ac5c933b 171 sub end : Private {
5a8ed4fe 172 my ( $self, $c ) = @_;
0ef52a96 173 if ( scalar @{ $c->error } ) { ... } # handle errors
174 return if $c->res->body; # already have a response
175 $c->forward( 'MyApp::View::TT' ); # render template
5a8ed4fe 176 }
177
0ef52a96 178 ### in MyApp/Controller/Foo.pm
179 # called for /foo/bar
180 sub bar : Local { ... }
ac5c933b 181
5400c668 182 # called for /blargle
183 sub blargle : Global { ... }
ac5c933b 184
5400c668 185 # an index action matches /foo, but not /foo/1, etc.
186 sub index : Private { ... }
ac5c933b 187
0ef52a96 188 ### in MyApp/Controller/Foo/Bar.pm
189 # called for /foo/bar/baz
190 sub baz : Local { ... }
ac5c933b 191
b4b01a8a 192 # first Root auto is called, then Foo auto, then this
0ef52a96 193 sub auto : Private { ... }
ac5c933b 194
0ef52a96 195 # powerful regular expression paths are also possible
196 sub details : Regex('^product/(\w+)/details$') {
5a8ed4fe 197 my ( $self, $c ) = @_;
0ef52a96 198 # extract the (\w+) from the URI
2982e768 199 my $product = $c->req->captures->[0];
5a8ed4fe 200 }
fc7ec1d9 201
0ef52a96 202See L<Catalyst::Manual::Intro> for additional information.
3803e98f 203
fc7ec1d9 204=head1 DESCRIPTION
205
86418559 206Catalyst is a modern framework for making web applications without the
207pain usually associated with this process. This document is a reference
208to the main Catalyst application. If you are a new user, we suggest you
209start with L<Catalyst::Manual::Tutorial> or L<Catalyst::Manual::Intro>.
fc7ec1d9 210
211See L<Catalyst::Manual> for more documentation.
212
ae1e6b59 213Catalyst plugins can be loaded by naming them as arguments to the "use
214Catalyst" statement. Omit the C<Catalyst::Plugin::> prefix from the
215plugin name, i.e., C<Catalyst::Plugin::My::Module> becomes
216C<My::Module>.
fc7ec1d9 217
0ef52a96 218 use Catalyst qw/My::Module/;
fc7ec1d9 219
836e1134 220If your plugin starts with a name other than C<Catalyst::Plugin::>, you can
221fully qualify the name by using a unary plus:
222
223 use Catalyst qw/
224 My::Module
225 +Fully::Qualified::Plugin::Name
226 /;
227
ae1e6b59 228Special flags like C<-Debug> and C<-Engine> can also be specified as
229arguments when Catalyst is loaded:
fc7ec1d9 230
231 use Catalyst qw/-Debug My::Module/;
232
ae1e6b59 233The position of plugins and flags in the chain is important, because
86418559 234they are loaded in the order in which they appear.
fc7ec1d9 235
23f9d934 236The following flags are supported:
237
b5ecfcf0 238=head2 -Debug
23f9d934 239
f8ad6ea5 240Enables debug output. You can also force this setting from the system
86418559 241environment with CATALYST_DEBUG or <MYAPP>_DEBUG. The environment
242settings override the application, with <MYAPP>_DEBUG having the highest
243priority.
fc7ec1d9 244
b5ecfcf0 245=head2 -Engine
fc7ec1d9 246
ae1e6b59 247Forces Catalyst to use a specific engine. Omit the
248C<Catalyst::Engine::> prefix of the engine name, i.e.:
fc7ec1d9 249
0ef52a96 250 use Catalyst qw/-Engine=CGI/;
fc7ec1d9 251
b5ecfcf0 252=head2 -Home
fbcc39ad 253
ae1e6b59 254Forces Catalyst to use a specific home directory, e.g.:
255
86418559 256 use Catalyst qw[-Home=/usr/mst];
fbcc39ad 257
cc95842f 258This can also be done in the shell environment by setting either the
259C<CATALYST_HOME> environment variable or C<MYAPP_HOME>; where C<MYAPP>
260is replaced with the uppercased name of your application, any "::" in
261the name will be replaced with underscores, e.g. MyApp::Web should use
262MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used.
263
b5ecfcf0 264=head2 -Log
fbcc39ad 265
0fa676a7 266 use Catalyst '-Log=warn,fatal,error';
267
268Specifies a comma-delimited list of log levels.
fbcc39ad 269
dc5f035e 270=head2 -Stats
271
272Enables statistics collection and reporting. You can also force this setting
273from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
274environment settings override the application, with <MYAPP>_STATS having the
275highest priority.
276
ac5c933b 277e.g.
dc5f035e 278
279 use Catalyst qw/-Stats=1/
280
23f9d934 281=head1 METHODS
282
f7b672ef 283=head2 INFORMATION ABOUT THE CURRENT REQUEST
0ef52a96 284
b5ecfcf0 285=head2 $c->action
66e28e3f 286
ae1e6b59 287Returns a L<Catalyst::Action> object for the current action, which
288stringifies to the action name. See L<Catalyst::Action>.
0ef52a96 289
b5ecfcf0 290=head2 $c->namespace
0ef52a96 291
86418559 292Returns the namespace of the current action, i.e., the URI prefix
ae1e6b59 293corresponding to the controller of the current action. For example:
294
295 # in Controller::Foo::Bar
296 $c->namespace; # returns 'foo/bar';
0ef52a96 297
b5ecfcf0 298=head2 $c->request
0ef52a96 299
b5ecfcf0 300=head2 $c->req
0ef52a96 301
86418559 302Returns the current L<Catalyst::Request> object, giving access to
303information about the current client request (including parameters,
304cookies, HTTP headers, etc.). See L<Catalyst::Request>.
0ef52a96 305
b4b01a8a 306=head2 REQUEST FLOW HANDLING
0ef52a96 307
b5ecfcf0 308=head2 $c->forward( $action [, \@arguments ] )
0ef52a96 309
b5ecfcf0 310=head2 $c->forward( $class, $method, [, \@arguments ] )
0ef52a96 311
86418559 312Forwards processing to another action, by its private name. If you give a
b4b01a8a 313class name but no method, C<process()> is called. You may also optionally
314pass arguments in an arrayref. The action will receive the arguments in
cc95842f 315C<@_> and C<< $c->req->args >>. Upon returning from the function,
316C<< $c->req->args >> will be restored to the previous values.
0ef52a96 317
3b984c64 318Any data C<return>ed from the action forwarded to, will be returned by the
d759db1e 319call to forward.
3b984c64 320
321 my $foodata = $c->forward('/foo');
0ef52a96 322 $c->forward('index');
e112461a 323 $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/);
0ef52a96 324 $c->forward('MyApp::View::TT');
325
86418559 326Note that forward implies an C<<eval { }>> around the call (actually
327C<execute> does), thus de-fatalizing all 'dies' within the called
328action. If you want C<die> to propagate you need to do something like:
f3e6a8c0 329
330 $c->forward('foo');
331 die $c->error if $c->error;
332
86418559 333Or make sure to always return true values from your actions and write
334your code like this:
f3e6a8c0 335
336 $c->forward('foo') || return;
337
0ef52a96 338=cut
339
6680c772 340sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $c, @_ ) }
0ef52a96 341
b5ecfcf0 342=head2 $c->detach( $action [, \@arguments ] )
0ef52a96 343
b5ecfcf0 344=head2 $c->detach( $class, $method, [, \@arguments ] )
0ef52a96 345
264bac8c 346=head2 $c->detach()
347
ac5c933b 348The same as C<forward>, but doesn't return to the previous action when
349processing is finished.
0ef52a96 350
264bac8c 351When called with no arguments it escapes the processing chain entirely.
352
0ef52a96 353=cut
354
355sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
356
ae0e35ee 357=head2 $c->visit( $action [, \@arguments ] )
358
359=head2 $c->visit( $class, $method, [, \@arguments ] )
360
361Almost the same as C<forward>, but does a full dispatch, instead of just
362calling the new C<$action> / C<$class-E<gt>$method>. This means that C<begin>,
363C<auto> and the method you go to are called, just like a new request.
364
365C<$c-E<gt>stash> is kept unchanged.
366
367In effect, C<visit> allows you to "wrap" another action, just as it
368would have been called by dispatching from a URL, while the analogous
369C<go> allows you to transfer control to another action as if it had
370been reached directly from a URL.
371
372=cut
373
374sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) }
375
2f381252 376=head2 $c->go( $action [, \@arguments ] )
377
378=head2 $c->go( $class, $method, [, \@arguments ] )
379
ae0e35ee 380Almost the same as C<detach>, but does a full dispatch like C<visit>,
381instead of just calling the new C<$action> /
382C<$class-E<gt>$method>. This means that C<begin>, C<auto> and the
383method you visit are called, just like a new request.
2f381252 384
385C<$c-E<gt>stash> is kept unchanged.
386
387=cut
388
389sub go { my $c = shift; $c->dispatcher->go( $c, @_ ) }
390
b4b01a8a 391=head2 $c->response
392
393=head2 $c->res
394
cc95842f 395Returns the current L<Catalyst::Response> object, see there for details.
b4b01a8a 396
397=head2 $c->stash
398
399Returns a hashref to the stash, which may be used to store data and pass
400it between components during a request. You can also set hash keys by
401passing arguments. The stash is automatically sent to the view. The
402stash is cleared at the end of a request; it cannot be used for
86418559 403persistent storage (for this you must use a session; see
404L<Catalyst::Plugin::Session> for a complete system integrated with
405Catalyst).
b4b01a8a 406
407 $c->stash->{foo} = $bar;
408 $c->stash( { moose => 'majestic', qux => 0 } );
409 $c->stash( bar => 1, gorch => 2 ); # equivalent to passing a hashref
ac5c933b 410
b4b01a8a 411 # stash is automatically passed to the view for use in a template
cc95842f 412 $c->forward( 'MyApp::View::TT' );
b4b01a8a 413
414=cut
415
4090e3bb 416around stash => sub {
417 my $orig = shift;
b4b01a8a 418 my $c = shift;
4090e3bb 419 my $stash = $orig->($c);
b4b01a8a 420 if (@_) {
4090e3bb 421 my $new_stash = @_ > 1 ? {@_} : $_[0];
422 croak('stash takes a hash or hashref') unless ref $new_stash;
423 foreach my $key ( keys %$new_stash ) {
424 $stash->{$key} = $new_stash->{$key};
b4b01a8a 425 }
426 }
0fc2d522 427
4090e3bb 428 return $stash;
429};
0fc2d522 430
b4b01a8a 431
b5ecfcf0 432=head2 $c->error
0ef52a96 433
b5ecfcf0 434=head2 $c->error($error, ...)
0ef52a96 435
b5ecfcf0 436=head2 $c->error($arrayref)
0ef52a96 437
83a8fcac 438Returns an arrayref containing error messages. If Catalyst encounters an
439error while processing a request, it stores the error in $c->error. This
e7ad3b81 440method should only be used to store fatal error messages.
0ef52a96 441
442 my @error = @{ $c->error };
443
444Add a new error.
445
446 $c->error('Something bad happened');
447
0ef52a96 448=cut
449
450sub error {
451 my $c = shift;
452 if ( $_[0] ) {
453 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
9ce44430 454 croak @$error unless ref $c;
0ef52a96 455 push @{ $c->{error} }, @$error;
456 }
457 elsif ( defined $_[0] ) { $c->{error} = undef }
458 return $c->{error} || [];
459}
460
b4b01a8a 461
462=head2 $c->state
463
464Contains the return value of the last executed action.
465
ca81eb67 466=head2 $c->clear_errors
467
468Clear errors. You probably don't want to clear the errors unless you are
469implementing a custom error screen.
470
471This is equivalent to running
472
473 $c->error(0);
474
475=cut
476
477sub clear_errors {
478 my $c = shift;
479 $c->error(0);
480}
481
2f381252 482# search components given a name and some prefixes
483sub _comp_search_prefixes {
484 my ( $c, $name, @prefixes ) = @_;
485 my $appclass = ref $c || $c;
486 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
0ef52a96 487
2f381252 488 # map the original component name to the sub part that we will search against
489 my %eligible = map { my $n = $_; $n =~ s{^$appclass\::[^:]+::}{}; $_ => $n; }
490 grep { /$filter/ } keys %{ $c->components };
0756fe3b 491
2f381252 492 # undef for a name will return all
493 return keys %eligible if !defined $name;
0756fe3b 494
2f381252 495 my $query = ref $name ? $name : qr/^$name$/i;
496 my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
0756fe3b 497
2f381252 498 return map { $c->components->{ $_ } } @result if @result;
0756fe3b 499
2f381252 500 # if we were given a regexp to search against, we're done.
501 return if ref $name;
0756fe3b 502
2f381252 503 # regexp fallback
504 $query = qr/$name/i;
505 @result = map { $c->components->{ $_ } } grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
0756fe3b 506
2f381252 507 # no results? try against full names
508 if( !@result ) {
509 @result = map { $c->components->{ $_ } } grep { m{$query} } keys %eligible;
510 }
0756fe3b 511
2f381252 512 # don't warn if we didn't find any results, it just might not exist
513 if( @result ) {
514 $c->log->warn( qq(Found results for "${name}" using regexp fallback.) );
515 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution is unreliable and unsafe.' );
516 $c->log->warn( 'If you really want to search, pass in a regexp as the argument.' );
517 }
0756fe3b 518
2f381252 519 return @result;
0756fe3b 520}
521
ac5c933b 522# Find possible names for a prefix
3b88a455 523sub _comp_names {
524 my ( $c, @prefixes ) = @_;
3b88a455 525 my $appclass = ref $c || $c;
526
2f381252 527 my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
3b88a455 528
2f381252 529 my @names = map { s{$filter}{}; $_; } $c->_comp_search_prefixes( undef, @prefixes );
3b88a455 530 return @names;
531}
532
197bd788 533# Filter a component before returning by calling ACCEPT_CONTEXT if available
534sub _filter_component {
535 my ( $c, $comp, @args ) = @_;
2f381252 536
8abaac85 537 if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
197bd788 538 return $comp->ACCEPT_CONTEXT( $c, @args );
539 }
2f381252 540
541 return $comp;
197bd788 542}
543
f7b672ef 544=head2 COMPONENT ACCESSORS
0ef52a96 545
b5ecfcf0 546=head2 $c->controller($name)
af3ff00e 547
0ef52a96 548Gets a L<Catalyst::Controller> instance by name.
af3ff00e 549
550 $c->controller('Foo')->do_stuff;
551
86418559 552If the name is omitted, will return the controller for the dispatched
553action.
649fd1fa 554
2f381252 555If you want to search for controllers, pass in a regexp as the argument.
556
557 # find all controllers that start with Foo
558 my @foo_controllers = $c->controller(qr{^Foo});
559
560
af3ff00e 561=cut
562
563sub controller {
197bd788 564 my ( $c, $name, @args ) = @_;
2f381252 565
566 if( $name ) {
567 my @result = $c->_comp_search_prefixes( $name, qw/Controller C/ );
568 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
569 return $c->_filter_component( $result[ 0 ], @args );
570 }
571
197bd788 572 return $c->component( $c->action->class );
af3ff00e 573}
574
b5ecfcf0 575=head2 $c->model($name)
fc7ec1d9 576
0ef52a96 577Gets a L<Catalyst::Model> instance by name.
578
579 $c->model('Foo')->do_stuff;
fc7ec1d9 580
72f87c4b 581Any extra arguments are directly passed to ACCEPT_CONTEXT.
582
ac5c933b 583If the name is omitted, it will look for
2f381252 584 - a model object in $c->stash->{current_model_instance}, then
a3b71f0f 585 - a model name in $c->stash->{current_model}, then
586 - a config setting 'default_model', or
587 - check if there is only one model, and return it if that's the case.
649fd1fa 588
2f381252 589If you want to search for models, pass in a regexp as the argument.
590
591 # find all models that start with Foo
592 my @foo_models = $c->model(qr{^Foo});
593
fc7ec1d9 594=cut
595
0ef52a96 596sub model {
197bd788 597 my ( $c, $name, @args ) = @_;
2f381252 598
599 if( $name ) {
600 my @result = $c->_comp_search_prefixes( $name, qw/Model M/ );
601 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
602 return $c->_filter_component( $result[ 0 ], @args );
603 }
604
a3b71f0f 605 if (ref $c) {
ac5c933b 606 return $c->stash->{current_model_instance}
a3b71f0f 607 if $c->stash->{current_model_instance};
608 return $c->model( $c->stash->{current_model} )
609 if $c->stash->{current_model};
a3b71f0f 610 }
72f87c4b 611 return $c->model( $c->config->{default_model} )
612 if $c->config->{default_model};
3b88a455 613
2f381252 614 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/Model M/);
3b88a455 615
2f381252 616 if( $rest ) {
617 $c->log->warn( 'Calling $c->model() will return a random model unless you specify one of:' );
618 $c->log->warn( '* $c->config->{default_model} # the name of the default model to use' );
619 $c->log->warn( '* $c->stash->{current_model} # the name of the model to use for this request' );
620 $c->log->warn( '* $c->stash->{current_model_instance} # the instance of the model to use for this request' );
621 $c->log->warn( 'NB: in version 5.80, the "random" behavior will not work at all.' );
622 }
3b88a455 623
2f381252 624 return $c->_filter_component( $comp );
3b88a455 625}
626
b4b01a8a 627
b5ecfcf0 628=head2 $c->view($name)
0ef52a96 629
630Gets a L<Catalyst::View> instance by name.
fc7ec1d9 631
0ef52a96 632 $c->view('Foo')->do_stuff;
fc7ec1d9 633
72f87c4b 634Any extra arguments are directly passed to ACCEPT_CONTEXT.
635
ac5c933b 636If the name is omitted, it will look for
2f381252 637 - a view object in $c->stash->{current_view_instance}, then
a3b71f0f 638 - a view name in $c->stash->{current_view}, then
639 - a config setting 'default_view', or
640 - check if there is only one view, and return it if that's the case.
649fd1fa 641
2f381252 642If you want to search for views, pass in a regexp as the argument.
643
644 # find all views that start with Foo
645 my @foo_views = $c->view(qr{^Foo});
646
fc7ec1d9 647=cut
648
0ef52a96 649sub view {
197bd788 650 my ( $c, $name, @args ) = @_;
2f381252 651
652 if( $name ) {
653 my @result = $c->_comp_search_prefixes( $name, qw/View V/ );
654 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
655 return $c->_filter_component( $result[ 0 ], @args );
656 }
657
a3b71f0f 658 if (ref $c) {
ac5c933b 659 return $c->stash->{current_view_instance}
a3b71f0f 660 if $c->stash->{current_view_instance};
661 return $c->view( $c->stash->{current_view} )
662 if $c->stash->{current_view};
a3b71f0f 663 }
72f87c4b 664 return $c->view( $c->config->{default_view} )
665 if $c->config->{default_view};
2f381252 666
667 my( $comp, $rest ) = $c->_comp_search_prefixes( undef, qw/View V/);
668
669 if( $rest ) {
670 $c->log->warn( 'Calling $c->view() will return a random view unless you specify one of:' );
671 $c->log->warn( '* $c->config->{default_view} # the name of the default view to use' );
672 $c->log->warn( '* $c->stash->{current_view} # the name of the view to use for this request' );
673 $c->log->warn( '* $c->stash->{current_view_instance} # the instance of the view to use for this request' );
674 $c->log->warn( 'NB: in version 5.80, the "random" behavior will not work at all.' );
675 }
676
677 return $c->_filter_component( $comp );
678}
679
680=head2 $c->controllers
681
682Returns the available names which can be passed to $c->controller
683
684=cut
685
686sub controllers {
687 my ( $c ) = @_;
688 return $c->_comp_names(qw/Controller C/);
0ef52a96 689}
fbcc39ad 690
b4b01a8a 691=head2 $c->models
692
693Returns the available names which can be passed to $c->model
694
695=cut
696
697sub models {
698 my ( $c ) = @_;
699 return $c->_comp_names(qw/Model M/);
700}
701
702
3b88a455 703=head2 $c->views
704
705Returns the available names which can be passed to $c->view
706
707=cut
708
709sub views {
710 my ( $c ) = @_;
711 return $c->_comp_names(qw/View V/);
712}
713
b4b01a8a 714=head2 $c->comp($name)
715
716=head2 $c->component($name)
717
cc95842f 718Gets a component object by name. This method is not recommended,
b4b01a8a 719unless you want to get a specific component by full
cc95842f 720class. C<< $c->controller >>, C<< $c->model >>, and C<< $c->view >>
b4b01a8a 721should be used instead.
722
2f381252 723If C<$name> is a regexp, a list of components matched against the full
724component name will be returned.
725
b4b01a8a 726=cut
727
728sub component {
2f381252 729 my ( $c, $name, @args ) = @_;
b4b01a8a 730
2f381252 731 if( $name ) {
732 my $comps = $c->components;
b4b01a8a 733
2f381252 734 if( !ref $name ) {
735 # is it the exact name?
736 return $c->_filter_component( $comps->{ $name }, @args )
737 if exists $comps->{ $name };
b4b01a8a 738
2f381252 739 # perhaps we just omitted "MyApp"?
740 my $composed = ( ref $c || $c ) . "::${name}";
741 return $c->_filter_component( $comps->{ $composed }, @args )
742 if exists $comps->{ $composed };
b4b01a8a 743
2f381252 744 # search all of the models, views and controllers
745 my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
746 return $c->_filter_component( $comp, @args ) if $comp;
747 }
748
749 # This is here so $c->comp( '::M::' ) works
750 my $query = ref $name ? $name : qr{$name}i;
b4b01a8a 751
2f381252 752 my @result = grep { m{$query} } keys %{ $c->components };
753 return map { $c->_filter_component( $_, @args ) } @result if ref $name;
b4b01a8a 754
2f381252 755 if( $result[ 0 ] ) {
756 $c->log->warn( qq(Found results for "${name}" using regexp fallback.) );
757 $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
758 $c->log->warn( 'is unreliable and unsafe. You have been warned' );
759 return $c->_filter_component( $result[ 0 ], @args );
760 }
761
762 # I would expect to return an empty list here, but that breaks back-compat
b4b01a8a 763 }
764
2f381252 765 # fallback
b4b01a8a 766 return sort keys %{ $c->components };
767}
768
b4b01a8a 769=head2 CLASS DATA AND HELPER CLASSES
fbcc39ad 770
b5ecfcf0 771=head2 $c->config
fbcc39ad 772
0ef52a96 773Returns or takes a hashref containing the application's configuration.
774
61b1d329 775 __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } );
81557adf 776
cc95842f 777You can also use a C<YAML>, C<XML> or C<Config::General> config file
778like myapp.yml in your applications home directory. See
779L<Catalyst::Plugin::ConfigLoader>.
a6ad13b6 780
781 ---
782 db: dsn:SQLite:foo.db
783
b4b01a8a 784
3643e890 785=cut
786
4090e3bb 787around config => sub {
788 my $orig = shift;
3643e890 789 my $c = shift;
790
791 $c->log->warn("Setting config after setup has been run is not a good idea.")
792 if ( @_ and $c->setup_finished );
793
4090e3bb 794 $c->$orig(@_);
795};
3643e890 796
b5ecfcf0 797=head2 $c->log
0ef52a96 798
86418559 799Returns the logging object instance. Unless it is already set, Catalyst
800sets this up with a L<Catalyst::Log> object. To use your own log class,
801set the logger with the C<< __PACKAGE__->log >> method prior to calling
9e7673af 802C<< __PACKAGE__->setup >>.
803
804 __PACKAGE__->log( MyLogger->new );
805 __PACKAGE__->setup;
806
807And later:
0ef52a96 808
ae1e6b59 809 $c->log->info( 'Now logging with my own logger!' );
0ef52a96 810
86418559 811Your log class should implement the methods described in
812L<Catalyst::Log>.
af3ff00e 813
b4b01a8a 814
815=head2 $c->debug
816
817Overload to enable debug messages (same as -Debug option).
818
e80e8542 819Note that this is a static method, not an accessor and should be overloaded
820by declaring "sub debug { 1 }" in your MyApp.pm, not by calling $c->debug(1).
821
af3ff00e 822=cut
823
b4b01a8a 824sub debug { 0 }
825
826=head2 $c->dispatcher
827
828Returns the dispatcher instance. Stringifies to class name. See
829L<Catalyst::Dispatcher>.
830
831=head2 $c->engine
832
833Returns the engine instance. Stringifies to the class name. See
834L<Catalyst::Engine>.
835
836
f7b672ef 837=head2 UTILITY METHODS
66e28e3f 838
b5ecfcf0 839=head2 $c->path_to(@path)
01033d73 840
cc95842f 841Merges C<@path> with C<< $c->config->{home} >> and returns a
afbb9aa3 842L<Path::Class::Dir> object.
01033d73 843
844For example:
845
846 $c->path_to( 'db', 'sqlite.db' );
847
848=cut
849
850sub path_to {
851 my ( $c, @path ) = @_;
a738ab68 852 my $path = Path::Class::Dir->new( $c->config->{home}, @path );
01033d73 853 if ( -d $path ) { return $path }
a738ab68 854 else { return Path::Class::File->new( $c->config->{home}, @path ) }
01033d73 855}
856
b5ecfcf0 857=head2 $c->plugin( $name, $class, @args )
0ef52a96 858
ae1e6b59 859Helper method for plugins. It creates a classdata accessor/mutator and
860loads and instantiates the given class.
0ef52a96 861
862 MyApp->plugin( 'prototype', 'HTML::Prototype' );
863
864 $c->prototype->define_javascript_functions;
865
866=cut
867
868sub plugin {
869 my ( $class, $name, $plugin, @args ) = @_;
97b58e17 870 $class->_register_plugin( $plugin, 1 );
0ef52a96 871
872 eval { $plugin->import };
873 $class->mk_classdata($name);
874 my $obj;
875 eval { $obj = $plugin->new(@args) };
876
877 if ($@) {
878 Catalyst::Exception->throw( message =>
879 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
880 }
881
882 $class->$name($obj);
883 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
884 if $class->debug;
885}
886
b5ecfcf0 887=head2 MyApp->setup
fbcc39ad 888
e7f1cf73 889Initializes the dispatcher and engine, loads any plugins, and loads the
ae1e6b59 890model, view, and controller components. You may also specify an array
891of plugins to load here, if you choose to not load them in the C<use
892Catalyst> line.
fbcc39ad 893
0ef52a96 894 MyApp->setup;
895 MyApp->setup( qw/-Debug/ );
fbcc39ad 896
897=cut
898
899sub setup {
0319a12c 900 my ( $class, @arguments ) = @_;
5168a5fc 901 $class->log->warn("Running setup twice is not a good idea.")
902 if ( $class->setup_finished );
903
fbcc39ad 904 unless ( $class->isa('Catalyst') ) {
953b0e15 905
fbcc39ad 906 Catalyst::Exception->throw(
907 message => qq/'$class' does not inherit from Catalyst/ );
1c99e125 908 }
0319a12c 909
fbcc39ad 910 if ( $class->arguments ) {
911 @arguments = ( @arguments, @{ $class->arguments } );
912 }
913
914 # Process options
915 my $flags = {};
916
917 foreach (@arguments) {
918
919 if (/^-Debug$/) {
920 $flags->{log} =
921 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
922 }
923 elsif (/^-(\w+)=?(.*)$/) {
924 $flags->{ lc $1 } = $2;
925 }
926 else {
927 push @{ $flags->{plugins} }, $_;
928 }
929 }
930
99f187d6 931 $class->setup_home( delete $flags->{home} );
932
fbcc39ad 933 $class->setup_log( delete $flags->{log} );
934 $class->setup_plugins( delete $flags->{plugins} );
935 $class->setup_dispatcher( delete $flags->{dispatcher} );
936 $class->setup_engine( delete $flags->{engine} );
dc5f035e 937 $class->setup_stats( delete $flags->{stats} );
fbcc39ad 938
939 for my $flag ( sort keys %{$flags} ) {
940
941 if ( my $code = $class->can( 'setup_' . $flag ) ) {
942 &$code( $class, delete $flags->{$flag} );
943 }
944 else {
945 $class->log->warn(qq/Unknown flag "$flag"/);
946 }
947 }
948
0eb4af72 949 eval { require Catalyst::Devel; };
950 if( !$@ && $ENV{CATALYST_SCRIPT_GEN} && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::Devel::CATALYST_SCRIPT_GEN ) ) {
951 $class->log->warn(<<"EOF");
4ff0d824 952You are running an old script!
953
34a83d89 954 Please update by running (this will overwrite existing files):
955 catalyst.pl -force -scripts $class
956
957 or (this will not overwrite existing files):
958 catalyst.pl -scripts $class
1cf0345b 959
4ff0d824 960EOF
0eb4af72 961 }
ac5c933b 962
fbcc39ad 963 if ( $class->debug ) {
6601f2ad 964 my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins;
fbcc39ad 965
966 if (@plugins) {
34d28dfd 967 my $t = Text::SimpleTable->new(74);
8c113188 968 $t->row($_) for @plugins;
1cf0345b 969 $class->log->debug( "Loaded plugins:\n" . $t->draw . "\n" );
fbcc39ad 970 }
971
972 my $dispatcher = $class->dispatcher;
973 my $engine = $class->engine;
974 my $home = $class->config->{home};
975
01ce7075 976 $class->log->debug(sprintf(q/Loaded dispatcher "%s"/, blessed($dispatcher)));
977 $class->log->debug(sprintf(q/Loaded engine "%s"/, blessed($engine)));
fbcc39ad 978
979 $home
980 ? ( -d $home )
981 ? $class->log->debug(qq/Found home "$home"/)
982 : $class->log->debug(qq/Home "$home" doesn't exist/)
983 : $class->log->debug(q/Couldn't find home/);
984 }
985
54f4bfef 986 # Call plugins setup, this is stupid and evil.
fbcc39ad 987 {
988 no warnings qw/redefine/;
989 local *setup = sub { };
990 $class->setup;
991 }
992
993 # Initialize our data structure
994 $class->components( {} );
995
996 $class->setup_components;
997
998 if ( $class->debug ) {
34d28dfd 999 my $t = Text::SimpleTable->new( [ 63, 'Class' ], [ 8, 'Type' ] );
684d10ed 1000 for my $comp ( sort keys %{ $class->components } ) {
1001 my $type = ref $class->components->{$comp} ? 'instance' : 'class';
1002 $t->row( $comp, $type );
1003 }
1cf0345b 1004 $class->log->debug( "Loaded components:\n" . $t->draw . "\n" )
8c113188 1005 if ( keys %{ $class->components } );
fbcc39ad 1006 }
1007
1008 # Add our self to components, since we are also a component
96d8d513 1009 if( $class->isa('Catalyst::Controller') ){
1010 $class->components->{$class} = $class;
1011 }
fbcc39ad 1012
1013 $class->setup_actions;
1014
1015 if ( $class->debug ) {
1016 my $name = $class->config->{name} || 'Application';
1017 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
1018 }
1019 $class->log->_flush() if $class->log->can('_flush');
3643e890 1020
3d041c32 1021 # Make sure that the application class becomes immutable at this point,
1022 # which ensures that it gets an inlined constructor. This means that it
1023 # works even if the user has added a plugin which contains a new method.
1024 # Note however that we have to do the work on scope end, so that method
1025 # modifiers work correctly in MyApp (as you have to call setup _before_
1026 # applying modifiers).
edb20ed3 1027 Scope::Upper::reap(sub {
3d041c32 1028 my $meta = $class->Moose::Object::meta();
1029 $meta->make_immutable unless $meta->is_immutable;
edb20ed3 1030 }, 1);
3d041c32 1031
3643e890 1032 $class->setup_finished(1);
fbcc39ad 1033}
1034
8a27f860 1035=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? )
1036
73664287 1037=head2 $c->uri_for( $path, @args?, \%query_values? )
fbcc39ad 1038
8a27f860 1039=over
fbcc39ad 1040
8a27f860 1041=item $action
8dc69021 1042
8a27f860 1043A Catalyst::Action object representing the Catalyst action you want to
1044create a URI for. To get one for an action in the current controller,
1045use C<< $c->action('someactionname') >>. To get one from different
1046controller, fetch the controller using C<< $c->controller() >>, then
1047call C<action_for> on it.
ea0e58d9 1048
9df7c5d9 1049You can maintain the arguments captured by an action (e.g.: Regex, Chained)
1050using C<< $c->req->captures >>.
1051
1052 # For the current action
1053 $c->uri_for($c->action, $c->req->captures);
1054
1055 # For the Foo action in the Bar controller
1056 $c->uri_for($c->controller->('Bar')->action_for('Foo'), $c->req->captures);
1057
d5e3d528 1058=back
1059
4cf1dd00 1060=cut
1061
fbcc39ad 1062sub uri_for {
00e6a2b7 1063 my ( $c, $path, @args ) = @_;
00e6a2b7 1064
ea0e58d9 1065 if ( Scalar::Util::blessed($path) ) { # action object
1066 my $captures = ( scalar @args && ref $args[0] eq 'ARRAY'
1067 ? shift(@args)
1068 : [] );
1069 $path = $c->dispatcher->uri_for_action($path, $captures);
1070 return undef unless defined($path);
81e75875 1071 $path = '/' if $path eq '';
ea0e58d9 1072 }
1073
51674a63 1074 undef($path) if (defined $path && $path eq '');
00e6a2b7 1075
97b58e17 1076 my $params =
1077 ( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
8327e2e2 1078
cbb93105 1079 carp "uri_for called with undef argument" if grep { ! defined $_ } @args;
51674a63 1080 s/([^$URI::uric])/$URI::Escape::escapes{$1}/go for @args;
1081
1082 unshift(@args, $path);
1083
1084 unless (defined $path && $path =~ s!^/!!) { # in-place strip
1085 my $namespace = $c->namespace;
1086 if (defined $path) { # cheesy hack to handle path '../foo'
1087 $namespace =~ s{(?:^|/)[^/]+$}{} while $args[0] =~ s{^\.\./}{};
6601f2ad 1088 }
51674a63 1089 unshift(@args, $namespace || '');
1090 }
ac5c933b 1091
189e2a51 1092 # join args with '/', or a blank string
51674a63 1093 my $args = join('/', grep { defined($_) } @args);
1094 $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
7a2295bc 1095 $args =~ s!^/+!!;
51674a63 1096 my $base = $c->req->base;
1097 my $class = ref($base);
1098 $base =~ s{(?<!/)$}{/};
1099
1100 my $query = '';
1101
1102 if (my @keys = keys %$params) {
1103 # somewhat lifted from URI::_query's query_form
1104 $query = '?'.join('&', map {
2f381252 1105 my $val = $params->{$_};
51674a63 1106 s/([;\/?:@&=+,\$\[\]%])/$URI::Escape::escapes{$1}/go;
1107 s/ /+/g;
1108 my $key = $_;
51674a63 1109 $val = '' unless defined $val;
1110 (map {
1111 $_ = "$_";
0ce485e9 1112 utf8::encode( $_ ) if utf8::is_utf8($_);
51674a63 1113 # using the URI::Escape pattern here so utf8 chars survive
1114 s/([^A-Za-z0-9\-_.!~*'() ])/$URI::Escape::escapes{$1}/go;
1115 s/ /+/g;
1116 "${key}=$_"; } ( ref $val eq 'ARRAY' ? @$val : $val ));
1117 } @keys);
1118 }
1119
1120 my $res = bless(\"${base}${args}${query}", $class);
d3e7a648 1121 $res;
fbcc39ad 1122}
1123
b5ecfcf0 1124=head2 $c->welcome_message
ab2374d3 1125
1126Returns the Catalyst welcome HTML page.
1127
1128=cut
1129
1130sub welcome_message {
bf1f2c60 1131 my $c = shift;
1132 my $name = $c->config->{name};
1133 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
1134 my $prefix = Catalyst::Utils::appprefix( ref $c );
80cdbbff 1135 $c->response->content_type('text/html; charset=utf-8');
ab2374d3 1136 return <<"EOF";
80cdbbff 1137<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
1138 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1139<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
ab2374d3 1140 <head>
85d9fce6 1141 <meta http-equiv="Content-Language" content="en" />
1142 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
ab2374d3 1143 <title>$name on Catalyst $VERSION</title>
1144 <style type="text/css">
1145 body {
ab2374d3 1146 color: #000;
1147 background-color: #eee;
1148 }
1149 div#content {
1150 width: 640px;
80cdbbff 1151 margin-left: auto;
1152 margin-right: auto;
ab2374d3 1153 margin-top: 10px;
1154 margin-bottom: 10px;
1155 text-align: left;
1156 background-color: #ccc;
1157 border: 1px solid #aaa;
ab2374d3 1158 }
d84c4dab 1159 p, h1, h2 {
ab2374d3 1160 margin-left: 20px;
1161 margin-right: 20px;
16215972 1162 font-family: verdana, tahoma, sans-serif;
ab2374d3 1163 }
d84c4dab 1164 a {
1165 font-family: verdana, tahoma, sans-serif;
1166 }
d114e033 1167 :link, :visited {
1168 text-decoration: none;
1169 color: #b00;
1170 border-bottom: 1px dotted #bbb;
1171 }
1172 :link:hover, :visited:hover {
d114e033 1173 color: #555;
1174 }
ab2374d3 1175 div#topbar {
1176 margin: 0px;
1177 }
3e82a295 1178 pre {
3e82a295 1179 margin: 10px;
1180 padding: 8px;
1181 }
ab2374d3 1182 div#answers {
1183 padding: 8px;
1184 margin: 10px;
d114e033 1185 background-color: #fff;
ab2374d3 1186 border: 1px solid #aaa;
ab2374d3 1187 }
1188 h1 {
33108eaf 1189 font-size: 0.9em;
1190 font-weight: normal;
ab2374d3 1191 text-align: center;
1192 }
1193 h2 {
1194 font-size: 1.0em;
1195 }
1196 p {
1197 font-size: 0.9em;
1198 }
ae7c5252 1199 p img {
1200 float: right;
1201 margin-left: 10px;
1202 }
9619f23c 1203 span#appname {
1204 font-weight: bold;
33108eaf 1205 font-size: 1.6em;
ab2374d3 1206 }
1207 </style>
1208 </head>
1209 <body>
1210 <div id="content">
1211 <div id="topbar">
9619f23c 1212 <h1><span id="appname">$name</span> on <a href="http://catalyst.perl.org">Catalyst</a>
d84c4dab 1213 $VERSION</h1>
ab2374d3 1214 </div>
1215 <div id="answers">
ae7c5252 1216 <p>
80cdbbff 1217 <img src="$logo" alt="Catalyst Logo" />
ae7c5252 1218 </p>
596aaffe 1219 <p>Welcome to the world of Catalyst.
f92fd545 1220 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
1221 framework will make web development something you had
60dd6e1d 1222 never expected it to be: Fun, rewarding, and quick.</p>
ab2374d3 1223 <h2>What to do now?</h2>
4b8cb778 1224 <p>That really depends on what <b>you</b> want to do.
ab2374d3 1225 We do, however, provide you with a few starting points.</p>
1226 <p>If you want to jump right into web development with Catalyst
2f381252 1227 you might want to start with a tutorial.</p>
b607f8a0 1228<pre>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Tutorial.pod">Catalyst::Manual::Tutorial</a></code>
596aaffe 1229</pre>
1230<p>Afterwards you can go on to check out a more complete look at our features.</p>
1231<pre>
b607f8a0 1232<code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst-Manual/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
1233<!-- Something else should go here, but the Catalyst::Manual link seems unhelpful -->
1234</code></pre>
ab2374d3 1235 <h2>What to do next?</h2>
f5681c92 1236 <p>Next it's time to write an actual application. Use the
80cdbbff 1237 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&amp;mode=all">controllers</a>,
60dd6e1d 1238 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&amp;mode=all">models</a>, and
1239 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&amp;mode=all">views</a>;
bf1f2c60 1240 they can save you a lot of work.</p>
1241 <pre><code>script/${prefix}_create.pl -help</code></pre>
1242 <p>Also, be sure to check out the vast and growing
60dd6e1d 1243 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 1244 you are likely to find what you need there.
f5681c92 1245 </p>
1246
82245cc4 1247 <h2>Need help?</h2>
f5681c92 1248 <p>Catalyst has a very active community. Here are the main places to
1249 get in touch with us.</p>
16215972 1250 <ul>
1251 <li>
2b9a7d76 1252 <a href="http://dev.catalyst.perl.org">Wiki</a>
16215972 1253 </li>
1254 <li>
6d4c3368 1255 <a href="http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst">Mailing-List</a>
16215972 1256 </li>
1257 <li>
4eaf7c88 1258 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
16215972 1259 </li>
1260 </ul>
ab2374d3 1261 <h2>In conclusion</h2>
ac5c933b 1262 <p>The Catalyst team hopes you will enjoy using Catalyst as much
f5681c92 1263 as we enjoyed making it. Please contact us if you have ideas
1264 for improvement or other feedback.</p>
ab2374d3 1265 </div>
1266 </div>
1267 </body>
1268</html>
1269EOF
1270}
1271
fbcc39ad 1272=head1 INTERNAL METHODS
1273
ae1e6b59 1274These methods are not meant to be used by end users.
1275
b5ecfcf0 1276=head2 $c->components
fbcc39ad 1277
e7f1cf73 1278Returns a hash of components.
fbcc39ad 1279
b5ecfcf0 1280=head2 $c->context_class
1f9cb7c1 1281
e7f1cf73 1282Returns or sets the context class.
1f9cb7c1 1283
b5ecfcf0 1284=head2 $c->counter
fbcc39ad 1285
ae1e6b59 1286Returns a hashref containing coderefs and execution counts (needed for
1287deep recursion detection).
fbcc39ad 1288
b5ecfcf0 1289=head2 $c->depth
fbcc39ad 1290
e7f1cf73 1291Returns the number of actions on the current internal execution stack.
fbcc39ad 1292
b5ecfcf0 1293=head2 $c->dispatch
fbcc39ad 1294
e7f1cf73 1295Dispatches a request to actions.
fbcc39ad 1296
1297=cut
1298
1299sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
1300
b5ecfcf0 1301=head2 $c->dispatcher_class
1f9cb7c1 1302
e7f1cf73 1303Returns or sets the dispatcher class.
1f9cb7c1 1304
b5ecfcf0 1305=head2 $c->dump_these
7f92deef 1306
ae1e6b59 1307Returns a list of 2-element array references (name, structure) pairs
1308that will be dumped on the error page in debug mode.
7f92deef 1309
1310=cut
1311
1312sub dump_these {
1313 my $c = shift;
ac5c933b 1314 [ Request => $c->req ],
1315 [ Response => $c->res ],
052a2d89 1316 [ Stash => $c->stash ],
1317 [ Config => $c->config ];
7f92deef 1318}
1319
b5ecfcf0 1320=head2 $c->engine_class
1f9cb7c1 1321
e7f1cf73 1322Returns or sets the engine class.
1f9cb7c1 1323
b5ecfcf0 1324=head2 $c->execute( $class, $coderef )
fbcc39ad 1325
0ef52a96 1326Execute a coderef in given class and catch exceptions. Errors are available
1327via $c->error.
fbcc39ad 1328
1329=cut
1330
1331sub execute {
1332 my ( $c, $class, $code ) = @_;
858828dd 1333 $class = $c->component($class) || $class;
fbcc39ad 1334 $c->state(0);
a0eca838 1335
197bd788 1336 if ( $c->depth >= $RECURSION ) {
f3414019 1337 my $action = $code->reverse();
91d08727 1338 $action = "/$action" unless $action =~ /->/;
f3414019 1339 my $error = qq/Deep recursion detected calling "${action}"/;
1627551a 1340 $c->log->error($error);
1341 $c->error($error);
1342 $c->state(0);
1343 return $c->state;
1344 }
1345
dc5f035e 1346 my $stats_info = $c->_stats_start_execute( $code ) if $c->use_stats;
22247e54 1347
8767c5a3 1348 push( @{ $c->stack }, $code );
ac5c933b 1349
f3414019 1350 eval { $c->state( $code->execute( $class, $c, @{ $c->req->args } ) || 0 ) };
22247e54 1351
dc5f035e 1352 $c->_stats_finish_execute( $stats_info ) if $c->use_stats and $stats_info;
ac5c933b 1353
a6724a82 1354 my $last = pop( @{ $c->stack } );
fbcc39ad 1355
1356 if ( my $error = $@ ) {
2f381252 1357 if ( !ref($error) and $error eq $DETACH ) {
1358 die $DETACH if($c->depth > 1);
1359 }
55424863 1360 elsif ( !ref($error) and $error eq $GO ) {
1361 die $GO if($c->depth > 0);
1362 }
fbcc39ad 1363 else {
1364 unless ( ref $error ) {
91d08727 1365 no warnings 'uninitialized';
fbcc39ad 1366 chomp $error;
f59def82 1367 my $class = $last->class;
1368 my $name = $last->name;
1369 $error = qq/Caught exception in $class->$name "$error"/;
fbcc39ad 1370 }
fbcc39ad 1371 $c->error($error);
1372 $c->state(0);
1373 }
1374 }
1375 return $c->state;
1376}
1377
7a7d7af5 1378sub _stats_start_execute {
1379 my ( $c, $code ) = @_;
1380
a6724a82 1381 return if ( ( $code->name =~ /^_.*/ )
1382 && ( !$c->config->{show_internal_actions} ) );
7a7d7af5 1383
f3414019 1384 my $action_name = $code->reverse();
1385 $c->counter->{$action_name}++;
7a7d7af5 1386
f3414019 1387 my $action = $action_name;
a6724a82 1388 $action = "/$action" unless $action =~ /->/;
1389
7a7d7af5 1390 # determine if the call was the result of a forward
1391 # this is done by walking up the call stack and looking for a calling
1392 # sub of Catalyst::forward before the eval
1393 my $callsub = q{};
1394 for my $index ( 2 .. 11 ) {
1395 last
1396 if ( ( caller($index) )[0] eq 'Catalyst'
1397 && ( caller($index) )[3] eq '(eval)' );
1398
1399 if ( ( caller($index) )[3] =~ /forward$/ ) {
1400 $callsub = ( caller($index) )[3];
1401 $action = "-> $action";
1402 last;
1403 }
1404 }
1405
f3414019 1406 my $uid = $action_name . $c->counter->{$action_name};
74efc144 1407
a6724a82 1408 # is this a root-level call or a forwarded call?
1409 if ( $callsub =~ /forward$/ ) {
1410
1411 # forward, locate the caller
1412 if ( my $parent = $c->stack->[-1] ) {
69d8f33c 1413 $c->stats->profile(
ac5c933b 1414 begin => $action,
69d8f33c 1415 parent => "$parent" . $c->counter->{"$parent"},
1416 uid => $uid,
1417 );
7a7d7af5 1418 }
1419 else {
1420
a6724a82 1421 # forward with no caller may come from a plugin
69d8f33c 1422 $c->stats->profile(
1423 begin => $action,
1424 uid => $uid,
1425 );
7a7d7af5 1426 }
1427 }
a6724a82 1428 else {
ac5c933b 1429
a6724a82 1430 # root-level call
69d8f33c 1431 $c->stats->profile(
1432 begin => $action,
1433 uid => $uid,
1434 );
a6724a82 1435 }
dc5f035e 1436 return $action;
7a7d7af5 1437
7a7d7af5 1438}
1439
1440sub _stats_finish_execute {
1441 my ( $c, $info ) = @_;
69d8f33c 1442 $c->stats->profile( end => $info );
7a7d7af5 1443}
1444
3d0d6d21 1445=head2 $c->_localize_fields( sub { }, \%keys );
1446
1447=cut
1448
e63bdf38 1449#Why does this exist? This is no longer safe and WILL NOT WORK.
1450# it doesnt seem to be used anywhere. can we remove it?
3d0d6d21 1451sub _localize_fields {
1452 my ( $c, $localized, $code ) = ( @_ );
1453
1454 my $request = delete $localized->{request} || {};
1455 my $response = delete $localized->{response} || {};
ac5c933b 1456
3d0d6d21 1457 local @{ $c }{ keys %$localized } = values %$localized;
1458 local @{ $c->request }{ keys %$request } = values %$request;
1459 local @{ $c->response }{ keys %$response } = values %$response;
1460
1461 $code->();
1462}
1463
b5ecfcf0 1464=head2 $c->finalize
fbcc39ad 1465
e7f1cf73 1466Finalizes the request.
fbcc39ad 1467
1468=cut
1469
1470sub finalize {
1471 my $c = shift;
1472
369c09bc 1473 for my $error ( @{ $c->error } ) {
1474 $c->log->error($error);
1475 }
1476
5050d7a7 1477 # Allow engine to handle finalize flow (for POE)
e63bdf38 1478 my $engine = $c->engine;
1479 if ( my $code = $engine->can('finalize') ) {
1480 $engine->$code($c);
fbcc39ad 1481 }
5050d7a7 1482 else {
fbcc39ad 1483
5050d7a7 1484 $c->finalize_uploads;
fbcc39ad 1485
5050d7a7 1486 # Error
1487 if ( $#{ $c->error } >= 0 ) {
1488 $c->finalize_error;
1489 }
1490
1491 $c->finalize_headers;
fbcc39ad 1492
5050d7a7 1493 # HEAD request
1494 if ( $c->request->method eq 'HEAD' ) {
1495 $c->response->body('');
1496 }
1497
1498 $c->finalize_body;
1499 }
ac5c933b 1500
1501 if ($c->use_stats) {
596677b6 1502 my $elapsed = sprintf '%f', $c->stats->elapsed;
12bf12c0 1503 my $av = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed;
908e3d9e 1504 $c->log->info(
ac5c933b 1505 "Request took ${elapsed}s ($av/s)\n" . $c->stats->report . "\n" );
908e3d9e 1506 }
fbcc39ad 1507
1508 return $c->response->status;
1509}
1510
b5ecfcf0 1511=head2 $c->finalize_body
fbcc39ad 1512
e7f1cf73 1513Finalizes body.
fbcc39ad 1514
1515=cut
1516
1517sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
1518
b5ecfcf0 1519=head2 $c->finalize_cookies
fbcc39ad 1520
e7f1cf73 1521Finalizes cookies.
fbcc39ad 1522
1523=cut
1524
147821ea 1525sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
fbcc39ad 1526
b5ecfcf0 1527=head2 $c->finalize_error
fbcc39ad 1528
e7f1cf73 1529Finalizes error.
fbcc39ad 1530
1531=cut
1532
1533sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
1534
b5ecfcf0 1535=head2 $c->finalize_headers
fbcc39ad 1536
e7f1cf73 1537Finalizes headers.
fbcc39ad 1538
1539=cut
1540
1541sub finalize_headers {
1542 my $c = shift;
1543
e63bdf38 1544 my $response = $c->response; #accessor calls can add up?
1545
fbcc39ad 1546 # Check if we already finalized headers
6680c772 1547 return if $response->finalized_headers;
fbcc39ad 1548
1549 # Handle redirects
e63bdf38 1550 if ( my $location = $response->redirect ) {
fbcc39ad 1551 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
e63bdf38 1552 $response->header( Location => $location );
a7caa492 1553
02570318 1554 if ( !$response->has_body ) {
39655cdc 1555 # Add a default body if none is already present
e63bdf38 1556 $response->body(
e422816e 1557 qq{<html><body><p>This item has moved <a href="$location">here</a>.</p></body></html>}
39655cdc 1558 );
1559 }
fbcc39ad 1560 }
1561
1562 # Content-Length
e63bdf38 1563 if ( $response->body && !$response->content_length ) {
775878ac 1564
8f62c91a 1565 # get the length from a filehandle
e63bdf38 1566 if ( blessed( $response->body ) && $response->body->can('read') )
197bd788 1567 {
e63bdf38 1568 my $stat = stat $response->body;
3b6a1db1 1569 if ( $stat && $stat->size > 0 ) {
e63bdf38 1570 $response->content_length( $stat->size );
8f62c91a 1571 }
1572 else {
775878ac 1573 $c->log->warn('Serving filehandle without a content-length');
8f62c91a 1574 }
1575 }
1576 else {
b5d7a61f 1577 # everything should be bytes at this point, but just in case
e63bdf38 1578 $response->content_length( bytes::length( $response->body ) );
8f62c91a 1579 }
fbcc39ad 1580 }
1581
1582 # Errors
e63bdf38 1583 if ( $response->status =~ /^(1\d\d|[23]04)$/ ) {
1584 $response->headers->remove_header("Content-Length");
1585 $response->body('');
fbcc39ad 1586 }
1587
1588 $c->finalize_cookies;
1589
1590 $c->engine->finalize_headers( $c, @_ );
1591
1592 # Done
6680c772 1593 $response->finalized_headers(1);
fbcc39ad 1594}
1595
b5ecfcf0 1596=head2 $c->finalize_output
fbcc39ad 1597
1598An alias for finalize_body.
1599
b5ecfcf0 1600=head2 $c->finalize_read
fbcc39ad 1601
e7f1cf73 1602Finalizes the input after reading is complete.
fbcc39ad 1603
1604=cut
1605
1606sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
1607
b5ecfcf0 1608=head2 $c->finalize_uploads
fbcc39ad 1609
ae1e6b59 1610Finalizes uploads. Cleans up any temporary files.
fbcc39ad 1611
1612=cut
1613
1614sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
1615
b5ecfcf0 1616=head2 $c->get_action( $action, $namespace )
fbcc39ad 1617
e7f1cf73 1618Gets an action in a given namespace.
fbcc39ad 1619
1620=cut
1621
684d10ed 1622sub get_action { my $c = shift; $c->dispatcher->get_action(@_) }
fbcc39ad 1623
b5ecfcf0 1624=head2 $c->get_actions( $action, $namespace )
a9dc674c 1625
ae1e6b59 1626Gets all actions of a given name in a namespace and all parent
1627namespaces.
a9dc674c 1628
1629=cut
1630
1631sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1632
f7b672ef 1633=head2 $c->handle_request( $class, @arguments )
fbcc39ad 1634
e7f1cf73 1635Called to handle each HTTP request.
fbcc39ad 1636
1637=cut
1638
1639sub handle_request {
1640 my ( $class, @arguments ) = @_;
1641
1642 # Always expect worst case!
1643 my $status = -1;
1644 eval {
dea1884f 1645 if ($class->debug) {
908e3d9e 1646 my $secs = time - $START || 1;
1647 my $av = sprintf '%.3f', $COUNT / $secs;
1648 my $time = localtime time;
1649 $class->log->info("*** Request $COUNT ($av/s) [$$] [$time] ***");
dea1884f 1650 }
908e3d9e 1651
1652 my $c = $class->prepare(@arguments);
1653 $c->dispatch;
ac5c933b 1654 $status = $c->finalize;
fbcc39ad 1655 };
1656
1657 if ( my $error = $@ ) {
1658 chomp $error;
1659 $class->log->error(qq/Caught exception in engine "$error"/);
1660 }
1661
1662 $COUNT++;
6680c772 1663
1664 if(my $coderef = $class->log->can('_flush')){
1665 $class->log->$coderef();
1666 }
fbcc39ad 1667 return $status;
1668}
1669
b5ecfcf0 1670=head2 $c->prepare( @arguments )
fbcc39ad 1671
ae1e6b59 1672Creates a Catalyst context from an engine-specific request (Apache, CGI,
1673etc.).
fbcc39ad 1674
1675=cut
1676
1677sub prepare {
1678 my ( $class, @arguments ) = @_;
1679
6680c772 1680 # XXX
1681 # After the app/ctxt split, this should become an attribute based on something passed
1682 # into the application.
3cec521a 1683 $class->context_class( ref $class || $class ) unless $class->context_class;
6680c772 1684
1685 my $c = $class->context_class->new({});
1686
1687 # For on-demand data
1688 $c->request->_context($c);
1689 $c->response->_context($c);
fbcc39ad 1690
b6d4ee6e 1691 #surely this is not the most efficient way to do things...
dc5f035e 1692 $c->stats($class->stats_class->new)->enable($c->use_stats);
908e3d9e 1693 if ( $c->debug ) {
ac5c933b 1694 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
908e3d9e 1695 }
1696
e63bdf38 1697 #XXX reuse coderef from can
5050d7a7 1698 # Allow engine to direct the prepare flow (for POE)
1699 if ( $c->engine->can('prepare') ) {
1700 $c->engine->prepare( $c, @arguments );
1701 }
1702 else {
1703 $c->prepare_request(@arguments);
1704 $c->prepare_connection;
1705 $c->prepare_query_parameters;
1706 $c->prepare_headers;
1707 $c->prepare_cookies;
1708 $c->prepare_path;
1709
878b821c 1710 # Prepare the body for reading, either by prepare_body
1711 # or the user, if they are using $c->read
1712 $c->prepare_read;
ac5c933b 1713
878b821c 1714 # Parse the body unless the user wants it on-demand
1715 unless ( $c->config->{parse_on_demand} ) {
1716 $c->prepare_body;
1717 }
5050d7a7 1718 }
fbcc39ad 1719
fbcc39ad 1720 my $method = $c->req->method || '';
2f381252 1721 my $path = $c->req->path;
1722 $path = '/' unless length $path;
fbcc39ad 1723 my $address = $c->req->address || '';
1724
e3a13771 1725 $c->log->debug(qq/"$method" request for "$path" from "$address"/)
fbcc39ad 1726 if $c->debug;
1727
e3a13771 1728 $c->prepare_action;
1729
fbcc39ad 1730 return $c;
1731}
1732
b5ecfcf0 1733=head2 $c->prepare_action
fbcc39ad 1734
b4b01a8a 1735Prepares action. See L<Catalyst::Dispatcher>.
fbcc39ad 1736
1737=cut
1738
1739sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1740
b5ecfcf0 1741=head2 $c->prepare_body
fbcc39ad 1742
e7f1cf73 1743Prepares message body.
fbcc39ad 1744
1745=cut
1746
1747sub prepare_body {
1748 my $c = shift;
1749
0f56bbcf 1750 return if $c->request->_has_body;
fbcc39ad 1751
1752 # Initialize on-demand data
1753 $c->engine->prepare_body( $c, @_ );
1754 $c->prepare_parameters;
1755 $c->prepare_uploads;
1756
1757 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
34d28dfd 1758 my $t = Text::SimpleTable->new( [ 35, 'Parameter' ], [ 36, 'Value' ] );
fbcc39ad 1759 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1760 my $param = $c->req->body_parameters->{$key};
1761 my $value = defined($param) ? $param : '';
8c113188 1762 $t->row( $key,
fbcc39ad 1763 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1764 }
1765 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1766 }
1767}
1768
b5ecfcf0 1769=head2 $c->prepare_body_chunk( $chunk )
4bd82c41 1770
e7f1cf73 1771Prepares a chunk of data before sending it to L<HTTP::Body>.
4bd82c41 1772
b4b01a8a 1773See L<Catalyst::Engine>.
1774
4bd82c41 1775=cut
1776
4f5ebacd 1777sub prepare_body_chunk {
1778 my $c = shift;
4bd82c41 1779 $c->engine->prepare_body_chunk( $c, @_ );
1780}
1781
b5ecfcf0 1782=head2 $c->prepare_body_parameters
fbcc39ad 1783
e7f1cf73 1784Prepares body parameters.
fbcc39ad 1785
1786=cut
1787
1788sub prepare_body_parameters {
1789 my $c = shift;
1790 $c->engine->prepare_body_parameters( $c, @_ );
1791}
1792
b5ecfcf0 1793=head2 $c->prepare_connection
fbcc39ad 1794
e7f1cf73 1795Prepares connection.
fbcc39ad 1796
1797=cut
1798
1799sub prepare_connection {
1800 my $c = shift;
1801 $c->engine->prepare_connection( $c, @_ );
1802}
1803
b5ecfcf0 1804=head2 $c->prepare_cookies
fbcc39ad 1805
e7f1cf73 1806Prepares cookies.
fbcc39ad 1807
1808=cut
1809
1810sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1811
b5ecfcf0 1812=head2 $c->prepare_headers
fbcc39ad 1813
e7f1cf73 1814Prepares headers.
fbcc39ad 1815
1816=cut
1817
1818sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1819
b5ecfcf0 1820=head2 $c->prepare_parameters
fbcc39ad 1821
e7f1cf73 1822Prepares parameters.
fbcc39ad 1823
1824=cut
1825
1826sub prepare_parameters {
1827 my $c = shift;
1828 $c->prepare_body_parameters;
1829 $c->engine->prepare_parameters( $c, @_ );
1830}
1831
b5ecfcf0 1832=head2 $c->prepare_path
fbcc39ad 1833
e7f1cf73 1834Prepares path and base.
fbcc39ad 1835
1836=cut
1837
1838sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1839
b5ecfcf0 1840=head2 $c->prepare_query_parameters
fbcc39ad 1841
e7f1cf73 1842Prepares query parameters.
fbcc39ad 1843
1844=cut
1845
1846sub prepare_query_parameters {
1847 my $c = shift;
1848
1849 $c->engine->prepare_query_parameters( $c, @_ );
1850
1851 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
34d28dfd 1852 my $t = Text::SimpleTable->new( [ 35, 'Parameter' ], [ 36, 'Value' ] );
fbcc39ad 1853 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1854 my $param = $c->req->query_parameters->{$key};
1855 my $value = defined($param) ? $param : '';
8c113188 1856 $t->row( $key,
fbcc39ad 1857 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1858 }
1859 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1860 }
1861}
1862
b5ecfcf0 1863=head2 $c->prepare_read
fbcc39ad 1864
e7f1cf73 1865Prepares the input for reading.
fbcc39ad 1866
1867=cut
1868
1869sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1870
b5ecfcf0 1871=head2 $c->prepare_request
fbcc39ad 1872
e7f1cf73 1873Prepares the engine request.
fbcc39ad 1874
1875=cut
1876
1877sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1878
b5ecfcf0 1879=head2 $c->prepare_uploads
fbcc39ad 1880
e7f1cf73 1881Prepares uploads.
fbcc39ad 1882
1883=cut
1884
1885sub prepare_uploads {
1886 my $c = shift;
1887
1888 $c->engine->prepare_uploads( $c, @_ );
1889
1890 if ( $c->debug && keys %{ $c->request->uploads } ) {
8c113188 1891 my $t = Text::SimpleTable->new(
34d28dfd 1892 [ 12, 'Parameter' ],
1893 [ 26, 'Filename' ],
8c113188 1894 [ 18, 'Type' ],
1895 [ 9, 'Size' ]
1896 );
fbcc39ad 1897 for my $key ( sort keys %{ $c->request->uploads } ) {
1898 my $upload = $c->request->uploads->{$key};
1899 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
8c113188 1900 $t->row( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1901 }
1902 }
1903 $c->log->debug( "File Uploads are:\n" . $t->draw );
1904 }
1905}
1906
b5ecfcf0 1907=head2 $c->prepare_write
fbcc39ad 1908
e7f1cf73 1909Prepares the output for writing.
fbcc39ad 1910
1911=cut
1912
1913sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1914
b5ecfcf0 1915=head2 $c->request_class
1f9cb7c1 1916
e7f1cf73 1917Returns or sets the request class.
1f9cb7c1 1918
b5ecfcf0 1919=head2 $c->response_class
1f9cb7c1 1920
e7f1cf73 1921Returns or sets the response class.
1f9cb7c1 1922
b5ecfcf0 1923=head2 $c->read( [$maxlength] )
fbcc39ad 1924
ae1e6b59 1925Reads a chunk of data from the request body. This method is designed to
1926be used in a while loop, reading C<$maxlength> bytes on every call.
1927C<$maxlength> defaults to the size of the request if not specified.
fbcc39ad 1928
cc95842f 1929You have to set C<< MyApp->config->{parse_on_demand} >> to use this
ae1e6b59 1930directly.
fbcc39ad 1931
878b821c 1932Warning: If you use read(), Catalyst will not process the body,
1933so you will not be able to access POST parameters or file uploads via
1934$c->request. You must handle all body parsing yourself.
1935
fbcc39ad 1936=cut
1937
1938sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1939
b5ecfcf0 1940=head2 $c->run
fbcc39ad 1941
1942Starts the engine.
1943
1944=cut
1945
1946sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1947
b5ecfcf0 1948=head2 $c->set_action( $action, $code, $namespace, $attrs )
fbcc39ad 1949
e7f1cf73 1950Sets an action in a given namespace.
fbcc39ad 1951
1952=cut
1953
1954sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1955
b5ecfcf0 1956=head2 $c->setup_actions($component)
fbcc39ad 1957
e7f1cf73 1958Sets up actions for a component.
fbcc39ad 1959
1960=cut
1961
1962sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1963
b5ecfcf0 1964=head2 $c->setup_components
fbcc39ad 1965
86418559 1966Sets up components. Specify a C<setup_components> config option to pass
1967additional options directly to L<Module::Pluggable>. To add additional
1968search paths, specify a key named C<search_extra> as an array
1969reference. Items in the array beginning with C<::> will have the
18de900e 1970application class name prepended to them.
fbcc39ad 1971
2f381252 1972All components found will also have any
1973L<Devel::InnerPackage|inner packages> loaded and set up as components.
1974Note, that modules which are B<not> an I<inner package> of the main
1975file namespace loaded will not be instantiated as components.
1976
fbcc39ad 1977=cut
1978
1979sub setup_components {
1980 my $class = shift;
1981
18de900e 1982 my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
1983 my $config = $class->config->{ setup_components };
1984 my $extra = delete $config->{ search_extra } || [];
ac5c933b 1985
18de900e 1986 push @paths, @$extra;
ac5c933b 1987
364d7324 1988 my $locator = Module::Pluggable::Object->new(
18de900e 1989 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
1990 %$config
364d7324 1991 );
b94b200c 1992
1993 my @comps = sort { length $a <=> length $b } $locator->plugins;
1994 my %comps = map { $_ => 1 } @comps;
ac5c933b 1995
b94b200c 1996 for my $component ( @comps ) {
dd91afb5 1997
1998 # We pass ignore_loaded here so that overlay files for (e.g.)
1999 # Model::DBI::Schema sub-classes are loaded - if it's in @comps
2000 # we know M::P::O found a file on disk so this is safe
2001
f5a4863c 2002 Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
2003 #Class::MOP::load_class($component);
364d7324 2004
2005 my $module = $class->setup_component( $component );
2006 my %modules = (
2007 $component => $module,
2008 map {
2009 $_ => $class->setup_component( $_ )
ac5c933b 2010 } grep {
b94b200c 2011 not exists $comps{$_}
364d7324 2012 } Devel::InnerPackage::list_packages( $component )
2013 );
ac5c933b 2014
364d7324 2015 for my $key ( keys %modules ) {
2016 $class->components->{ $key } = $modules{ $key };
fbcc39ad 2017 }
364d7324 2018 }
2019}
fbcc39ad 2020
364d7324 2021=head2 $c->setup_component
fbcc39ad 2022
364d7324 2023=cut
fbcc39ad 2024
364d7324 2025sub setup_component {
2026 my( $class, $component ) = @_;
fbcc39ad 2027
364d7324 2028 unless ( $component->can( 'COMPONENT' ) ) {
2029 return $component;
2030 }
fbcc39ad 2031
364d7324 2032 my $suffix = Catalyst::Utils::class2classsuffix( $component );
2033 my $config = $class->config->{ $suffix } || {};
fbcc39ad 2034
364d7324 2035 my $instance = eval { $component->COMPONENT( $class, $config ); };
fbcc39ad 2036
2037 if ( my $error = $@ ) {
fbcc39ad 2038 chomp $error;
fbcc39ad 2039 Catalyst::Exception->throw(
364d7324 2040 message => qq/Couldn't instantiate component "$component", "$error"/
2041 );
fbcc39ad 2042 }
2043
364d7324 2044 Catalyst::Exception->throw(
2045 message =>
2046 qq/Couldn't instantiate component "$component", "COMPONENT() didn't return an object-like value"/
84ff88cf 2047 ) unless blessed($instance);
364d7324 2048
2049 return $instance;
fbcc39ad 2050}
2051
b5ecfcf0 2052=head2 $c->setup_dispatcher
fbcc39ad 2053
ae1e6b59 2054Sets up dispatcher.
2055
fbcc39ad 2056=cut
2057
2058sub setup_dispatcher {
2059 my ( $class, $dispatcher ) = @_;
2060
2061 if ($dispatcher) {
2062 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
2063 }
2064
cb69249e 2065 if ( my $env = Catalyst::Utils::env_value( $class, 'DISPATCHER' ) ) {
2066 $dispatcher = 'Catalyst::Dispatcher::' . $env;
fbcc39ad 2067 }
2068
2069 unless ($dispatcher) {
cb0354c6 2070 $dispatcher = $class->dispatcher_class;
fbcc39ad 2071 }
2072
e63bdf38 2073 Class::MOP::load_class($dispatcher);
fbcc39ad 2074
2075 # dispatcher instance
2076 $class->dispatcher( $dispatcher->new );
2077}
2078
b5ecfcf0 2079=head2 $c->setup_engine
fbcc39ad 2080
ae1e6b59 2081Sets up engine.
2082
fbcc39ad 2083=cut
2084
2085sub setup_engine {
2086 my ( $class, $engine ) = @_;
2087
2088 if ($engine) {
2089 $engine = 'Catalyst::Engine::' . $engine;
2090 }
2091
cb69249e 2092 if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
2093 $engine = 'Catalyst::Engine::' . $env;
fbcc39ad 2094 }
2095
9b0a3e0f 2096 if ( $ENV{MOD_PERL} ) {
74c89dea 2097 my $meta = $class->Class::MOP::Object::meta();
2098
fbcc39ad 2099 # create the apache method
74c89dea 2100 $meta->add_method('apache' => sub { shift->engine->apache });
fbcc39ad 2101
2102 my ( $software, $version ) =
2103 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
2104
2105 $version =~ s/_//g;
2106 $version =~ s/(\.[^.]+)\./$1/g;
2107
2108 if ( $software eq 'mod_perl' ) {
2109
9b0a3e0f 2110 if ( !$engine ) {
22247e54 2111
9b0a3e0f 2112 if ( $version >= 1.99922 ) {
2113 $engine = 'Catalyst::Engine::Apache2::MP20';
2114 }
22247e54 2115
9b0a3e0f 2116 elsif ( $version >= 1.9901 ) {
2117 $engine = 'Catalyst::Engine::Apache2::MP19';
2118 }
22247e54 2119
9b0a3e0f 2120 elsif ( $version >= 1.24 ) {
2121 $engine = 'Catalyst::Engine::Apache::MP13';
2122 }
22247e54 2123
9b0a3e0f 2124 else {
2125 Catalyst::Exception->throw( message =>
2126 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
2127 }
fbcc39ad 2128
fbcc39ad 2129 }
2130
2131 # install the correct mod_perl handler
2132 if ( $version >= 1.9901 ) {
2133 *handler = sub : method {
2134 shift->handle_request(@_);
2135 };
2136 }
2137 else {
2138 *handler = sub ($$) { shift->handle_request(@_) };
2139 }
2140
2141 }
2142
2143 elsif ( $software eq 'Zeus-Perl' ) {
2144 $engine = 'Catalyst::Engine::Zeus';
2145 }
2146
2147 else {
2148 Catalyst::Exception->throw(
2149 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
2150 }
2151 }
2152
2153 unless ($engine) {
cb0354c6 2154 $engine = $class->engine_class;
fbcc39ad 2155 }
2156
e63bdf38 2157 Class::MOP::load_class($engine);
0e7f5826 2158
d54484bf 2159 # check for old engines that are no longer compatible
2160 my $old_engine;
0e7f5826 2161 if ( $engine->isa('Catalyst::Engine::Apache')
2162 && !Catalyst::Engine::Apache->VERSION )
d54484bf 2163 {
2164 $old_engine = 1;
2165 }
0e7f5826 2166
d54484bf 2167 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 2168 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 2169 {
2170 $old_engine = 1;
2171 }
0e7f5826 2172
2173 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
2174 && $engine->VERSION eq '0.01' )
d54484bf 2175 {
2176 $old_engine = 1;
2177 }
0e7f5826 2178
2179 elsif ($engine->isa('Catalyst::Engine::Zeus')
2180 && $engine->VERSION eq '0.01' )
d54484bf 2181 {
2182 $old_engine = 1;
2183 }
fbcc39ad 2184
d54484bf 2185 if ($old_engine) {
2186 Catalyst::Exception->throw( message =>
0e7f5826 2187 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 2188 );
2189 }
0e7f5826 2190
fbcc39ad 2191 # engine instance
2192 $class->engine( $engine->new );
2193}
2194
b5ecfcf0 2195=head2 $c->setup_home
fbcc39ad 2196
ae1e6b59 2197Sets up the home directory.
2198
fbcc39ad 2199=cut
2200
2201sub setup_home {
2202 my ( $class, $home ) = @_;
2203
cb69249e 2204 if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
2205 $home = $env;
fbcc39ad 2206 }
2207
b6d4ee6e 2208 $home ||= Catalyst::Utils::home($class);
fbcc39ad 2209
2210 if ($home) {
e63bdf38 2211 #I remember recently being scolded for assigning config values like this
fbcc39ad 2212 $class->config->{home} ||= $home;
a738ab68 2213 $class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
fbcc39ad 2214 }
2215}
2216
b5ecfcf0 2217=head2 $c->setup_log
fbcc39ad 2218
0fa676a7 2219Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
2220passing it to C<log()>. Pass in a comma-delimited list of levels to set the
2221log to.
2222
2223This method also installs a C<debug> method that returns a true value into the
2224catalyst subclass if the "debug" level is passed in the comma-delimited list,
2225or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
2226
2227Note that if the log has already been setup, by either a previous call to
2228C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
2229that this method won't actually set up the log.
ae1e6b59 2230
fbcc39ad 2231=cut
2232
2233sub setup_log {
0fa676a7 2234 my ( $class, $levels ) = @_;
fbcc39ad 2235
0fa676a7 2236 my %levels;
fbcc39ad 2237 unless ( $class->log ) {
0fa676a7 2238 $levels ||= '';
2239 $levels =~ s/^\s+//;
2240 $levels =~ s/\s+$//;
2241 %levels = map { $_ => 1 } split /\s*,\s*/, $levels || '';
2242 $class->log( Catalyst::Log->new(keys %levels) );
fbcc39ad 2243 }
af3ff00e 2244
cb69249e 2245 my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
0fa676a7 2246 if ( defined($env_debug) or $levels{debug} ) {
74c89dea 2247 $class->Class::MOP::Object::meta()->add_method('debug' => sub { 1 });
fbcc39ad 2248 $class->log->debug('Debug messages enabled');
2249 }
2250}
2251
b5ecfcf0 2252=head2 $c->setup_plugins
fbcc39ad 2253
ae1e6b59 2254Sets up plugins.
2255
fbcc39ad 2256=cut
2257
dc5f035e 2258=head2 $c->setup_stats
2259
2260Sets up timing statistics class.
2261
2262=cut
2263
2264sub setup_stats {
2265 my ( $class, $stats ) = @_;
2266
2267 Catalyst::Utils::ensure_class_loaded($class->stats_class);
2268
2269 my $env = Catalyst::Utils::env_value( $class, 'STATS' );
2270 if ( defined($env) ? $env : ($stats || $class->debug ) ) {
74c89dea 2271 $class->Class::MOP::Object::meta()->add_method('use_stats' => sub { 1 });
b01f0c69 2272 $class->log->debug('Statistics enabled');
dc5f035e 2273 }
2274}
2275
2276
ac5c933b 2277=head2 $c->registered_plugins
836e1134 2278
2279Returns a sorted list of the plugins which have either been stated in the
2280import list or which have been added via C<< MyApp->plugin(@args); >>.
2281
2282If passed a given plugin name, it will report a boolean value indicating
2283whether or not that plugin is loaded. A fully qualified name is required if
2284the plugin name does not begin with C<Catalyst::Plugin::>.
2285
2286 if ($c->registered_plugins('Some::Plugin')) {
2287 ...
2288 }
2289
2290=cut
fbcc39ad 2291
836e1134 2292{
97b58e17 2293
2294 sub registered_plugins {
836e1134 2295 my $proto = shift;
197bd788 2296 return sort keys %{ $proto->_plugins } unless @_;
836e1134 2297 my $plugin = shift;
d0d4d785 2298 return 1 if exists $proto->_plugins->{$plugin};
2299 return exists $proto->_plugins->{"Catalyst::Plugin::$plugin"};
836e1134 2300 }
fbcc39ad 2301
836e1134 2302 sub _register_plugin {
2303 my ( $proto, $plugin, $instant ) = @_;
2304 my $class = ref $proto || $proto;
fbcc39ad 2305
dd91afb5 2306 # no ignore_loaded here, the plugin may already have been
2307 # defined in memory and we don't want to error on "no file" if so
2308
b6d4ee6e 2309 Class::MOP::load_class( $plugin );
fbcc39ad 2310
197bd788 2311 $proto->_plugins->{$plugin} = 1;
836e1134 2312 unless ($instant) {
fbcc39ad 2313 no strict 'refs';
74c89dea 2314 if ( my $meta = $class->Class::MOP::Object::meta() ) {
2315 my @superclasses = ($plugin, $meta->superclasses );
2316 $meta->superclasses(@superclasses);
5fb67d52 2317 } else {
2318 unshift @{"$class\::ISA"}, $plugin;
2319 }
fbcc39ad 2320 }
836e1134 2321 return $class;
2322 }
2323
2324 sub setup_plugins {
2325 my ( $class, $plugins ) = @_;
2326
d0d4d785 2327 $class->_plugins( {} ) unless $class->_plugins;
836e1134 2328 $plugins ||= [];
2329 for my $plugin ( reverse @$plugins ) {
2330
2331 unless ( $plugin =~ s/\A\+// ) {
2332 $plugin = "Catalyst::Plugin::$plugin";
2333 }
2334
2335 $class->_register_plugin($plugin);
2336 }
fbcc39ad 2337 }
2338}
2339
b5ecfcf0 2340=head2 $c->stack
8767c5a3 2341
86418559 2342Returns an arrayref of the internal execution stack (actions that are
2343currently executing).
8767c5a3 2344
dc5f035e 2345=head2 $c->stats_class
2346
2347Returns or sets the stats (timing statistics) class.
2348
2349=head2 $c->use_stats
2350
2351Returns 1 when stats collection is enabled. Stats collection is enabled
2352when the -Stats options is set, debug is on or when the <MYAPP>_STATS
2353environment variable is set.
2354
2355Note that this is a static method, not an accessor and should be overloaded
2356by declaring "sub use_stats { 1 }" in your MyApp.pm, not by calling $c->use_stats(1).
2357
2358=cut
2359
2360sub use_stats { 0 }
2361
2362
b5ecfcf0 2363=head2 $c->write( $data )
fbcc39ad 2364
ae1e6b59 2365Writes $data to the output stream. When using this method directly, you
2366will need to manually set the C<Content-Length> header to the length of
2367your output data, if known.
fbcc39ad 2368
2369=cut
2370
4f5ebacd 2371sub write {
2372 my $c = shift;
2373
2374 # Finalize headers if someone manually writes output
2375 $c->finalize_headers;
2376
2377 return $c->engine->write( $c, @_ );
2378}
fbcc39ad 2379
b5ecfcf0 2380=head2 version
bf88a181 2381
ae1e6b59 2382Returns the Catalyst version number. Mostly useful for "powered by"
2383messages in template systems.
bf88a181 2384
2385=cut
2386
2387sub version { return $Catalyst::VERSION }
2388
b0bb11ec 2389=head1 INTERNAL ACTIONS
2390
ae1e6b59 2391Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
2392C<_ACTION>, and C<_END>. These are by default not shown in the private
3e705254 2393action table, but you can make them visible with a config parameter.
b0bb11ec 2394
2395 MyApp->config->{show_internal_actions} = 1;
2396
d2ee9760 2397=head1 CASE SENSITIVITY
2398
3e705254 2399By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> is
ae1e6b59 2400mapped to C</foo/bar>. You can activate case sensitivity with a config
3e705254 2401parameter.
d2ee9760 2402
2403 MyApp->config->{case_sensitive} = 1;
2404
3e705254 2405This causes C<MyApp::C::Foo::Bar> to map to C</Foo/Bar>.
fbcc39ad 2406
2407=head1 ON-DEMAND PARSER
2408
2409The request body is usually parsed at the beginning of a request,
878b821c 2410but if you want to handle input yourself, you can enable on-demand
2411parsing with a config parameter.
fbcc39ad 2412
2413 MyApp->config->{parse_on_demand} = 1;
ac5c933b 2414
fbcc39ad 2415=head1 PROXY SUPPORT
2416
ae1e6b59 2417Many production servers operate using the common double-server approach,
2418with a lightweight frontend web server passing requests to a larger
2419backend server. An application running on the backend server must deal
2420with two problems: the remote user always appears to be C<127.0.0.1> and
2421the server's hostname will appear to be C<localhost> regardless of the
2422virtual host that the user connected through.
fbcc39ad 2423
ae1e6b59 2424Catalyst will automatically detect this situation when you are running
2425the frontend and backend servers on the same machine. The following
2426changes are made to the request.
fbcc39ad 2427
ac5c933b 2428 $c->req->address is set to the user's real IP address, as read from
ae1e6b59 2429 the HTTP X-Forwarded-For header.
ac5c933b 2430
ae1e6b59 2431 The host value for $c->req->base and $c->req->uri is set to the real
2432 host, as read from the HTTP X-Forwarded-Host header.
fbcc39ad 2433
3e705254 2434Obviously, your web server must support these headers for this to work.
fbcc39ad 2435
ae1e6b59 2436In a more complex server farm environment where you may have your
2437frontend proxy server(s) on different machines, you will need to set a
2438configuration option to tell Catalyst to read the proxied data from the
2439headers.
fbcc39ad 2440
2441 MyApp->config->{using_frontend_proxy} = 1;
ac5c933b 2442
fbcc39ad 2443If you do not wish to use the proxy support at all, you may set:
d1a31ac6 2444
fbcc39ad 2445 MyApp->config->{ignore_frontend_proxy} = 1;
2446
2447=head1 THREAD SAFETY
2448
86418559 2449Catalyst has been tested under Apache 2's threading C<mpm_worker>,
2450C<mpm_winnt>, and the standalone forking HTTP server on Windows. We
2451believe the Catalyst core to be thread-safe.
fbcc39ad 2452
2453If you plan to operate in a threaded environment, remember that all other
3e705254 2454modules you are using must also be thread-safe. Some modules, most notably
2455L<DBD::SQLite>, are not thread-safe.
d1a31ac6 2456
3cb1db8c 2457=head1 SUPPORT
2458
2459IRC:
2460
4eaf7c88 2461 Join #catalyst on irc.perl.org.
3cb1db8c 2462
3e705254 2463Mailing Lists:
3cb1db8c 2464
6d4c3368 2465 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
2466 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
1985c30b 2467
432d507d 2468Web:
2469
2470 http://catalyst.perl.org
2471
0ef52a96 2472Wiki:
2473
2474 http://dev.catalyst.perl.org
2475
fc7ec1d9 2476=head1 SEE ALSO
2477
829a28ca 2478=head2 L<Task::Catalyst> - All you need to start with Catalyst
2479
b5ecfcf0 2480=head2 L<Catalyst::Manual> - The Catalyst Manual
e7f1cf73 2481
b5ecfcf0 2482=head2 L<Catalyst::Component>, L<Catalyst::Base> - Base classes for components
61b1e958 2483
b5ecfcf0 2484=head2 L<Catalyst::Engine> - Core engine
61b1e958 2485
b5ecfcf0 2486=head2 L<Catalyst::Log> - Log class.
61b1e958 2487
b5ecfcf0 2488=head2 L<Catalyst::Request> - Request object
61b1e958 2489
b5ecfcf0 2490=head2 L<Catalyst::Response> - Response object
61b1e958 2491
b5ecfcf0 2492=head2 L<Catalyst::Test> - The test suite.
fc7ec1d9 2493
2f381252 2494=head1 PROJECT FOUNDER
2495
2496sri: Sebastian Riedel <sri@cpan.org>
fc7ec1d9 2497
2f381252 2498=head1 CONTRIBUTORS
15f0b5b7 2499
2f381252 2500abw: Andy Wardley
fbcc39ad 2501
2f381252 2502acme: Leon Brocard <leon@astray.com>
33108eaf 2503
f4a57de4 2504Andrew Bramble
2505
15f0b5b7 2506Andrew Ford
2507
2508Andrew Ruthven
2509
2f381252 2510andyg: Andy Grundman <andy@hybridized.org>
fbcc39ad 2511
2f381252 2512audreyt: Audrey Tang
15f0b5b7 2513
2f381252 2514bricas: Brian Cassidy <bricas@cpan.org>
0cf56dbc 2515
e31b525c 2516Caelum: Rafael Kitover <rkitover@io.com>
2517
2f381252 2518chansen: Christian Hansen
6aaa1c60 2519
2f381252 2520chicks: Christopher Hicks
15f0b5b7 2521
0fa676a7 2522David E. Wheeler
2523
2f381252 2524dkubb: Dan Kubb <dan.kubb-cpan@onautopilot.com>
15f0b5b7 2525
2f381252 2526Drew Taylor
15f0b5b7 2527
2f381252 2528esskar: Sascha Kiefer
0ef52a96 2529
2f381252 2530fireartist: Carl Franks <cfranks@cpan.org>
15f0b5b7 2531
2f381252 2532gabb: Danijel Milicevic
61bef238 2533
15f0b5b7 2534Gary Ashton Jones
2535
2536Geoff Richards
2537
e4cc83b2 2538ilmari: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
2539
2f381252 2540jcamacho: Juan Camacho
fbcc39ad 2541
15f0b5b7 2542Jody Belka
2543
2544Johan Lindstrom
2545
2f381252 2546jon: Jon Schutz <jjschutz@cpan.org>
15f0b5b7 2547
2f381252 2548marcus: Marcus Ramberg <mramberg@cpan.org>
15f0b5b7 2549
2f381252 2550miyagawa: Tatsuhiko Miyagawa <miyagawa@bulknews.net>
15f0b5b7 2551
2f381252 2552mst: Matt S. Trout <mst@shadowcatsystems.co.uk>
15f0b5b7 2553
2f381252 2554mugwump: Sam Vilain
71c3bcc3 2555
2f381252 2556naughton: David Naughton
a727119f 2557
2f381252 2558ningu: David Kamholz <dkamholz@cpan.org>
1cf1c56a 2559
2f381252 2560nothingmuch: Yuval Kogman <nothingmuch@woobling.org>
9c71d51d 2561
2f381252 2562numa: Dan Sully <daniel@cpan.org>
fc7ec1d9 2563
2f381252 2564obra: Jesse Vincent
2565
2566omega: Andreas Marienborg
51f0308d 2567
2f381252 2568phaylon: Robert Sedlacek <phaylon@dunkelheit.at>
bdcb95ef 2569
6dae3eef 2570rafl: Florian Ragwitz <rafl@debian.org>
2571
2f381252 2572sky: Arthur Bergman
2573
2574the_jester: Jesse Sheidlower
2575
2576Ulf Edvinsson
51f0308d 2577
2f381252 2578willert: Sebastian Willert <willert@cpan.org>
51f0308d 2579
fc7ec1d9 2580=head1 LICENSE
2581
9ce5ab63 2582This library is free software, you can redistribute it and/or modify it under
41ca9ba7 2583the same terms as Perl itself.
fc7ec1d9 2584
2585=cut
2586
4090e3bb 2587no Moose;
2588
46d0346d 2589__PACKAGE__->meta->make_immutable;
2590
fc7ec1d9 25911;