RT #64126: typos
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Cookbook.pod
CommitLineData
cb93c9d7 1=head1 NAME
2
3Catalyst::Manual::Cookbook - Cooking with Catalyst
4
5=head1 DESCRIPTION
6
7Yummy code like your mum used to bake!
8
9=head1 RECIPES
10
11=head1 Basics
12
c718cfb6 13These recipes cover some basic stuff that is worth knowing for
46a5f2f5 14Catalyst developers.
cb93c9d7 15
16=head2 Delivering a Custom Error Page
17
18By default, Catalyst will display its own error page whenever it
19encounters an error in your application. When running under C<-Debug>
c718cfb6 20mode, the error page is a useful screen including the error message
21and L<Data::Dump> output of the relevant parts of the C<$c> context
22object. When not in C<-Debug>, users see a simple "Please come back
23later" screen.
cb93c9d7 24
c718cfb6 25To use a custom error page, use a special C<end> method to
26short-circuit the error processing. The following is an example; you
27might want to adjust it further depending on the needs of your
28application (for example, any calls to C<fillform> will probably need
29to go into this C<end> method; see L<Catalyst::Plugin::FillInForm>).
cb93c9d7 30
31 sub end : Private {
32 my ( $self, $c ) = @_;
33
34 if ( scalar @{ $c->error } ) {
35 $c->stash->{errors} = $c->error;
bf6900ba 36 for my $error ( @{ $c->error } ) {
37 $c->log->error($error);
38 }
cb93c9d7 39 $c->stash->{template} = 'errors.tt';
40 $c->forward('MyApp::View::TT');
bf6900ba 41 $c->clear_errors;
cb93c9d7 42 }
43
44 return 1 if $c->response->status =~ /^3\d\d$/;
45 return 1 if $c->response->body;
46
47 unless ( $c->response->content_type ) {
48 $c->response->content_type('text/html; charset=utf-8');
49 }
50
51 $c->forward('MyApp::View::TT');
52 }
53
54You can manually set errors in your code to trigger this page by calling
55
56 $c->error( 'You broke me!' );
57
58=head2 Disable statistics
59
c718cfb6 60Just add this line to your application class if you don't want those
61nifty statistics in your debug messages.
cb93c9d7 62
63 sub Catalyst::Log::info { }
64
65=head2 Enable debug status in the environment
66
67Normally you enable the debugging info by adding the C<-Debug> flag to
b411df01 68your C<use Catalyst> statement . However, you can also enable it using
69environment variable, so you can (for example) get debug info without
70modifying your application scripts. Just set C<CATALYST_DEBUG> or
7c098817 71C<E<lt>MYAPPE<gt>_DEBUG> to a true value.
cb93c9d7 72
73=head2 Sessions
74
c718cfb6 75When you have your users identified, you will want to somehow remember
76that fact, to save them from having to identify themselves for every
77single page. One way to do this is to send the username and password
78parameters in every single page, but that's ugly, and won't work for
79static pages.
cb93c9d7 80
c718cfb6 81Sessions are a method of saving data related to some transaction, and
82giving the whole collection a single ID. This ID is then given to the
83user to return to us on every page they visit while logged in. The
84usual way to do this is using a browser cookie.
cb93c9d7 85
86Catalyst uses two types of plugins to represent sessions:
87
88=head3 State
89
c718cfb6 90A State module is used to keep track of the state of the session
91between the users browser, and your application.
cb93c9d7 92
c718cfb6 93A common example is the Cookie state module, which sends the browser a
94cookie containing the session ID. It will use default value for the
95cookie name and domain, so will "just work" when used.
cb93c9d7 96
97=head3 Store
98
c718cfb6 99A Store module is used to hold all the data relating to your session,
100for example the users ID, or the items for their shopping cart. You
101can store data in memory (FastMmap), in a file (File) or in a database
102(DBI).
cb93c9d7 103
104=head3 Authentication magic
105
106If you have included the session modules in your application, the
107Authentication modules will automagically use your session to save and
108retrieve the user data for you.
109
110=head3 Using a session
111
112Once the session modules are loaded, the session is available as C<<
c718cfb6 113$c->session >>, and can be writen to and read from as a simple hash
114reference.
cb93c9d7 115
116=head3 EXAMPLE
117
b1a08fe1 118 package MyApp;
119 use Moose;
120 use namespace::autoclean;
121
b411df01 122 use Catalyst qw/
ca7528df 123 Session
124 Session::Store::FastMmap
125 Session::State::Cookie
b411df01 126 /;
b1a08fe1 127 extends 'Catalyst';
128 __PACKAGE__->setup;
cb93c9d7 129
b1a08fe1 130 package MyApp::Controller::Foo;
131 use Moose;
132 use namespace::autoclean;
46a5f2f5 133 BEGIN { extends 'Catalyst::Controller' };
cb93c9d7 134 ## Write data into the session
135
136 sub add_item : Local {
137 my ( $self, $c ) = @_;
138
76776098 139 my $item_id = $c->req->params->{item};
cb93c9d7 140
141 push @{ $c->session->{items} }, $item_id;
142
143 }
144
145 ## A page later we retrieve the data from the session:
146
147 sub get_items : Local {
148 my ( $self, $c ) = @_;
149
150 $c->stash->{items_to_display} = $c->session->{items};
151
152 }
153
154
155=head3 More information
156
157L<http://search.cpan.org/dist/Catalyst-Plugin-Session>
158
159L<http://search.cpan.org/dist/Catalyst-Plugin-Session-State-Cookie>
160
161L<http://search.cpan.org/dist/Catalyst-Plugin-Session-State-URI>
162
163L<http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-FastMmap>
164
165L<http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-File>
166
167L<http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-DBI>
168
169=head2 Configure your application
170
171You configure your application with the C<config> method in your
172application class. This can be hard-coded, or brought in from a
173separate configuration file.
174
c010ae0d 175=head3 Using Config::General
cb93c9d7 176
c010ae0d 177L<Config::General|Config::General> is a method for creating flexible
178and readable configuration files. It's a great way to keep your
179Catalyst application configuration in one easy-to-understand location.
cb93c9d7 180
c010ae0d 181Now create C<myapp.conf> in your application home:
cb93c9d7 182
c010ae0d 183 name MyApp
cb93c9d7 184
185 # session; perldoc Catalyst::Plugin::Session::FastMmap
c010ae0d 186 <Session>
187 expires 3600
188 rewrite 0
189 storage /tmp/myapp.session
190 </Session>
cb93c9d7 191
192 # emails; perldoc Catalyst::Plugin::Email
193 # this passes options as an array :(
c010ae0d 194 Mail SMTP
195 Mail localhost
cb93c9d7 196
197This is equivalent to:
198
199 # configure base package
200 __PACKAGE__->config( name => MyApp );
201 # configure authentication
202 __PACKAGE__->config->{authentication} = {
203 user_class => 'MyApp::Model::MyDB::Customer',
204 ...
205 };
206 # configure sessions
207 __PACKAGE__->config->{session} = {
208 expires => 3600,
209 ...
210 };
211 # configure email sending
212 __PACKAGE__->config->{email} = [qw/SMTP localhost/];
213
c010ae0d 214See also L<Config::General|Config::General>.
cb93c9d7 215
216=head1 Skipping your VCS's directories
217
46a5f2f5 218Catalyst uses Module::Pluggable to load Models, Views, and Controllers.
cb93c9d7 219Module::Pluggable will scan through all directories and load modules
220it finds. Sometimes you might want to skip some of these directories,
221for example when your version control system makes a subdirectory with
222meta-information in every version-controlled directory. While
223Catalyst skips subversion and CVS directories already, there are other
224source control systems. Here is the configuration you need to add
225their directories to the list to skip.
226
46a5f2f5 227You can make Catalyst skip these directories using the Catalyst config:
cb93c9d7 228
229 # Configure the application
230 __PACKAGE__->config(
231 name => 'MyApp',
232 setup_components => { except => qr/SCCS/ },
233 );
234
235See the Module::Pluggable manual page for more information on B<except>
236and other options.
237
238=head1 Users and Access Control
239
46a5f2f5 240Most multiuser, and some single-user web applications require that
cb93c9d7 241users identify themselves, and the application is often required to
242define those roles. The recipes below describe some ways of doing
243this.
244
245=head2 Authentication (logging in)
246
247This is extensively covered in other documentation; see in particular
248L<Catalyst::Plugin::Authentication> and the Authentication chapter
5641c0c1 249of the Tutorial at L<Catalyst::Manual::Tutorial::06_Authorization>.
cb93c9d7 250
251=head2 Pass-through login (and other actions)
252
253An easy way of having assorted actions that occur during the processing
254of a request that are orthogonal to its actual purpose - logins, silent
255commands etc. Provide actions for these, but when they're required for
256something else fill e.g. a form variable __login and have a sub begin
257like so:
258
259 sub begin : Private {
260 my ($self, $c) = @_;
261 foreach my $action (qw/login docommand foo bar whatever/) {
262 if ($c->req->params->{"__${action}"}) {
263 $c->forward($action);
264 }
265 }
266 }
267
cb93c9d7 268=head2 Authentication/Authorization
269
270This is done in several steps:
271
272=over 4
273
274=item Verification
275
276Getting the user to identify themselves, by giving you some piece of
c718cfb6 277information known only to you and the user. Then you can assume that
278the user is who they say they are. This is called B<credential
279verification>.
cb93c9d7 280
281=item Authorization
282
c718cfb6 283Making sure the user only accesses functions you want them to
46a5f2f5 284access. This is done by checking the verified user's data against your
c718cfb6 285internal list of groups, or allowed persons for the current page.
cb93c9d7 286
287=back
288
289=head3 Modules
290
c718cfb6 291The Catalyst Authentication system is made up of many interacting
292modules, to give you the most flexibility possible.
cb93c9d7 293
294=head4 Credential verifiers
295
c718cfb6 296A Credential module tables the user input, and passes it to a Store,
297or some other system, for verification. Typically, a user object is
298created by either this module or the Store and made accessible by a
299C<< $c->user >> call.
cb93c9d7 300
301Examples:
302
303 Password - Simple username/password checking.
304 HTTPD - Checks using basic HTTP auth.
305 TypeKey - Check using the typekey system.
306
307=head3 Storage backends
308
c718cfb6 309A Storage backend contains the actual data representing the users. It
310is queried by the credential verifiers. Updating the store is not done
46a5f2f5 311within this system; you will need to do it yourself.
cb93c9d7 312
313Examples:
314
46a5f2f5 315 DBIC - Storage using a database via DBIx::Class.
cb93c9d7 316 Minimal - Storage using a simple hash (for testing).
317
318=head3 User objects
319
c718cfb6 320A User object is created by either the storage backend or the
46a5f2f5 321credential verifier, and is filled with the retrieved user information.
cb93c9d7 322
323Examples:
324
325 Hash - A simple hash of keys and values.
326
327=head3 ACL authorization
328
c718cfb6 329ACL stands for Access Control List. The ACL plugin allows you to
46a5f2f5 330regulate access on a path-by-path basis, by listing which users, or
c718cfb6 331roles, have access to which paths.
cb93c9d7 332
333=head3 Roles authorization
334
c718cfb6 335Authorization by roles is for assigning users to groups, which can
336then be assigned to ACLs, or just checked when needed.
cb93c9d7 337
338=head3 Logging in
339
340When you have chosen your modules, all you need to do is call the C<<
b1a08fe1 341$c->authenticate >> method. If called with no parameters, it will try to find
c718cfb6 342suitable parameters, such as B<username> and B<password>, or you can
343pass it these values.
cb93c9d7 344
345=head3 Checking roles
346
46a5f2f5 347Role checking is done by using the C<< $c->check_user_roles >> method.
348This will check using the currently logged-in user (via C<< $c->user
c718cfb6 349>>). You pass it the name of a role to check, and it returns true if
350the user is a member.
cb93c9d7 351
352=head3 EXAMPLE
353
bbddff00 354 package MyApp;
355 use Moose;
356 use namespace::autoclean;
357 extends qw/Catalyst/;
358 use Catalyst qw/
359 Authentication
360 Authorization::Roles
361 /;
362
363 __PACKAGE__->config(
364 authentication => {
365 default_realm => 'test',
366 realms => {
367 test => {
368 credential => {
369 class => 'Password',
370 password_field => 'password',
371 password_type => 'self_check',
372 },
373 store => {
374 class => 'Htpasswd',
375 file => 'htpasswd',
376 },
377 },
378 },
31e9c5ef 379 },
bbddff00 380 );
381
382 package MyApp::Controller::Root;
383 use Moose;
384 use namespace::autoclean;
31e9c5ef 385
bbddff00 386 BEGIN { extends 'Catalyst::Controller' }
31e9c5ef 387
bbddff00 388 __PACKAGE__->config(namespace => '');
31e9c5ef 389
bbddff00 390 sub login : Local {
cb93c9d7 391 my ($self, $c) = @_;
392
76776098 393 if ( my $user = $c->req->params->{user}
394 and my $password = $c->req->param->{password} )
cb93c9d7 395 {
b1a08fe1 396 if ( $c->authenticate( username => $user, password => $password ) ) {
cb93c9d7 397 $c->res->body( "hello " . $c->user->name );
398 } else {
399 # login incorrect
400 }
401 }
402 else {
403 # invalid form input
404 }
405 }
406
407 sub restricted : Local {
408 my ( $self, $c ) = @_;
409
410 $c->detach("unauthorized")
411 unless $c->check_user_roles( "admin" );
412
413 # do something restricted here
414 }
415
416=head3 Using authentication in a testing environment
417
46a5f2f5 418Ideally, to write tests for authentication/authorization code one would
419first set up a test database with known data, then use
c718cfb6 420L<Test::WWW::Mechanize::Catalyst> to simulate a user logging
46a5f2f5 421in. Unfortunately this can be rather awkward, which is why it's a good
422thing that the authentication framework is so flexible.
cb93c9d7 423
c718cfb6 424Instead of using a test database, one can simply change the
425authentication store to something a bit easier to deal with in a
426testing environment. Additionally, this has the advantage of not
427modifying one's database, which can be problematic if one forgets to
428use the testing instead of production database.
cb93c9d7 429
46a5f2f5 430Alternatively, if you want to authenticate real users, but not have to
431worry about their passwords, you can use
432L<Catalyst::Authentication::Credential::Testing> to force all users to
433authenticate with a global password.
cb93c9d7 434
435=head3 More information
436
bbddff00 437L<Catalyst::Plugin::Authentication> has a longer explanation.
cb93c9d7 438
439=head2 Authorization
440
441=head3 Introduction
442
c718cfb6 443Authorization is the step that comes after
46a5f2f5 444authentication. Authentication establishes that the user agent is really
445representing the user we think it's representing, and then authorization
446determines what this user is allowed to do.
cb93c9d7 447
448=head3 Role Based Access Control
449
c718cfb6 450Under role based access control each user is allowed to perform any
451number of roles. For example, at a zoo no one but specially trained
bfa445ed 452personnel can enter the moose cage (Mynd you, møøse bites kan be
c718cfb6 453pretty nasti!). For example:
cb93c9d7 454
455 package Zoo::Controller::MooseCage;
456
457 sub feed_moose : Local {
458 my ( $self, $c ) = @_;
459
76776098 460 $c->model( "Moose" )->eat( $c->req->params->{food} );
cb93c9d7 461 }
462
c718cfb6 463With this action, anyone can just come into the moose cage and feed
464the moose, which is a very dangerous thing. We need to restrict this
465action, so that only a qualified moose feeder can perform that action.
cb93c9d7 466
46a5f2f5 467The Authorization::Roles plugin lets us perform role based access
c718cfb6 468control checks. Let's load it:
cb93c9d7 469
ca7528df 470 use parent qw/Catalyst/;
b411df01 471 use Catalyst qw/
b1a08fe1 472 Authentication
b411df01 473 Authorization::Roles
474 /;
cb93c9d7 475
476And now our action should look like this:
477
478 sub feed_moose : Local {
479 my ( $self, $c ) = @_;
480
481 if ( $c->check_roles( "moose_feeder" ) ) {
76776098 482 $c->model( "Moose" )->eat( $c->req->params->{food} );
cb93c9d7 483 } else {
484 $c->stash->{error} = "unauthorized";
485 }
486 }
487
c718cfb6 488This checks C<< $c->user >>, and only if the user has B<all> the roles
489in the list, a true value is returned.
cb93c9d7 490
c718cfb6 491C<check_roles> has a sister method, C<assert_roles>, which throws an
492exception if any roles are missing.
cb93c9d7 493
494Some roles that might actually make sense in, say, a forum application:
495
496=over 4
497
498=item *
499
500administrator
501
502=item *
503
504moderator
505
506=back
507
c718cfb6 508each with a distinct task (system administration versus content
509administration).
cb93c9d7 510
511=head3 Access Control Lists
512
513Checking for roles all the time can be tedious and error prone.
514
46a5f2f5 515The Authorization::ACL plugin lets us declare where we'd like checks
c718cfb6 516to be done automatically for us.
cb93c9d7 517
518For example, we may want to completely block out anyone who isn't a
519C<moose_feeder> from the entire C<MooseCage> controller:
520
521 Zoo->deny_access_unless( "/moose_cage", [qw/moose_feeder/] );
522
c718cfb6 523The role list behaves in the same way as C<check_roles>. However, the
524ACL plugin isn't limited to just interacting with the Roles plugin. We
525can use a code reference instead. For example, to allow either moose
526trainers or moose feeders into the moose cage, we can create a more
527complex check:
cb93c9d7 528
529 Zoo->deny_access_unless( "/moose_cage", sub {
530 my $c = shift;
531 $c->check_roles( "moose_trainer" ) || $c->check_roles( "moose_feeder" );
532 });
533
c718cfb6 534The more specific a role, the earlier it will be checked. Let's say
535moose feeders are now restricted to only the C<feed_moose> action,
536while moose trainers get access everywhere:
cb93c9d7 537
538 Zoo->deny_access_unless( "/moose_cage", [qw/moose_trainer/] );
539 Zoo->allow_access_if( "/moose_cage/feed_moose", [qw/moose_feeder/]);
540
c718cfb6 541When the C<feed_moose> action is accessed the second check will be
542made. If the user is a C<moose_feeder>, then access will be
543immediately granted. Otherwise, the next rule in line will be tested -
544the one checking for a C<moose_trainer>. If this rule is not
545satisfied, access will be immediately denied.
cb93c9d7 546
c718cfb6 547Rules applied to the same path will be checked in the order they were
548added.
cb93c9d7 549
c718cfb6 550Lastly, handling access denial events is done by creating an
551C<access_denied> private action:
cb93c9d7 552
553 sub access_denied : Private {
554 my ( $self, $c, $action ) = @_;
cb93c9d7 555 }
556
c718cfb6 557This action works much like auto, in that it is inherited across
558namespaces (not like object oriented code). This means that the
559C<access_denied> action which is B<nearest> to the action which was
560blocked will be triggered.
cb93c9d7 561
c718cfb6 562If this action does not exist, an error will be thrown, which you can
563clean up in your C<end> private action instead.
cb93c9d7 564
c718cfb6 565Also, it's important to note that if you restrict access to "/" then
46a5f2f5 566C<end>, C<default>, etc. will also be restricted.
cb93c9d7 567
568 MyApp->acl_allow_root_internals;
569
570will create rules that permit access to C<end>, C<begin>, and C<auto> in the
571root of your app (but not in any other controller).
572
573=head1 Models
574
575Models are where application data belongs. Catalyst is exteremely
576flexible with the kind of models that it can use. The recipes here
577are just the start.
578
579=head2 Using existing DBIC (etc.) classes with Catalyst
580
c718cfb6 581Many people have existing Model classes that they would like to use
582with Catalyst (or, conversely, they want to write Catalyst models that
583can be used outside of Catalyst, e.g. in a cron job). It's trivial to
584write a simple component in Catalyst that slurps in an outside Model:
cb93c9d7 585
586 package MyApp::Model::DB;
46a5f2f5 587
cb93c9d7 588 use base qw/Catalyst::Model::DBIC::Schema/;
46a5f2f5 589
cb93c9d7 590 __PACKAGE__->config(
591 schema_class => 'Some::DBIC::Schema',
592 connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}];
593 );
46a5f2f5 594
cb93c9d7 595 1;
596
597and that's it! Now C<Some::DBIC::Schema> is part of your
598Cat app as C<MyApp::Model::DB>.
599
600=head2 DBIx::Class as a Catalyst Model
601
602See L<Catalyst::Model::DBIC::Schema>.
603
8428e94d 604=head2 Create accessors to preload static data once per server instance
605
606When you have data that you want to load just once from the model at
46a5f2f5 607startup, instead of for each request, use mk_group_accessors to
8428e94d 608create accessors and tie them to resultsets in your package that
46a5f2f5 609inherits from DBIx::Class::Schema:
8428e94d 610
611 package My::Schema;
612 use base qw/DBIx::Class::Schema/;
613 __PACKAGE__->register_class('RESULTSOURCEMONIKER',
614 'My::Schema::RESULTSOURCE');
615 __PACKAGE__->mk_group_accessors('simple' =>
616 qw(ACCESSORNAME1 ACCESSORNAME2 ACCESSORNAMEn));
617
618 sub connection {
619 my ($self, @rest) = @_;
620 $self->next::method(@rest);
b1a08fe1 621 # $self is now a live My::Schema object, complete with DB connection
8428e94d 622
623 $self->ACCESSORNAME1([ $self->resultset('RESULTSOURCEMONIKER')->all ]);
624 $self->ACCESSORNAME2([ $self->resultset('RESULTSOURCEMONIKER')->search({ COLUMN => { '<' => '30' } })->all ]);
625 $self->ACCESSORNAMEn([ $self->resultset('RESULTSOURCEMONIKER')->find(1) ]);
626 }
627
628 1;
629
630and now in the controller, you can now access any of these without a
631per-request fetch:
632
46a5f2f5 633 $c->stash->{something} = $c->model('My::Schema')->schema->ACCESSORNAME;
8428e94d 634
635
cb93c9d7 636=head2 XMLRPC
637
46a5f2f5 638Unlike SOAP, XMLRPC is a very simple (and elegant) web-services
cb93c9d7 639protocol, exchanging small XML messages like these:
640
641Request:
642
643 POST /api HTTP/1.1
644 TE: deflate,gzip;q=0.3
645 Connection: TE, close
646 Accept: text/xml
647 Accept: multipart/*
648 Host: 127.0.0.1:3000
649 User-Agent: SOAP::Lite/Perl/0.60
650 Content-Length: 192
651 Content-Type: text/xml
652
653 <?xml version="1.0" encoding="UTF-8"?>
654 <methodCall>
655 <methodName>add</methodName>
656 <params>
657 <param><value><int>1</int></value></param>
658 <param><value><int>2</int></value></param>
659 </params>
660 </methodCall>
661
662Response:
663
664 Connection: close
665 Date: Tue, 20 Dec 2005 07:45:55 GMT
666 Content-Length: 133
667 Content-Type: text/xml
668 Status: 200
669 X-Catalyst: 5.70
670
671 <?xml version="1.0" encoding="us-ascii"?>
672 <methodResponse>
673 <params>
674 <param><value><int>3</int></value></param>
675 </params>
676 </methodResponse>
677
678Now follow these few steps to implement the application:
679
6801. Install Catalyst (5.61 or later), Catalyst::Plugin::XMLRPC (0.06 or
681later) and SOAP::Lite (for XMLRPCsh.pl).
682
6832. Create an application framework:
684
685 % catalyst.pl MyApp
686 ...
687 % cd MyApp
688
6893. Add the XMLRPC plugin to MyApp.pm
690
b411df01 691 use Catalyst qw/-Debug Static::Simple XMLRPC/;
cb93c9d7 692
6934. Add an API controller
694
695 % ./script/myapp_create.pl controller API
696
6975. Add a XMLRPC redispatch method and an add method with Remote
698attribute to lib/MyApp/Controller/API.pm
699
85d49fb6 700 sub default :Path {
cb93c9d7 701 my ( $self, $c ) = @_;
702 $c->xmlrpc;
703 }
704
705 sub add : Remote {
706 my ( $self, $c, $a, $b ) = @_;
707 return $a + $b;
708 }
709
710The default action is the entry point for each XMLRPC request. It will
711redispatch every request to methods with Remote attribute in the same
712class.
713
714The C<add> method is not a traditional action; it has no private or
715public path. Only the XMLRPC dispatcher knows it exists.
716
7176. That's it! You have built your first web service. Let's test it with
718XMLRPCsh.pl (part of SOAP::Lite):
719
720 % ./script/myapp_server.pl
721 ...
722 % XMLRPCsh.pl http://127.0.0.1:3000/api
723 Usage: method[(parameters)]
724 > add( 1, 2 )
725 --- XMLRPC RESULT ---
726 '3'
727
728=head3 Tip
729
730Your return data type is usually auto-detected, but you can easily
731enforce a specific one.
732
733 sub add : Remote {
734 my ( $self, $c, $a, $b ) = @_;
735 return RPC::XML::int->new( $a + $b );
736 }
cb93c9d7 737
738=head1 Views
739
740Views pertain to the display of your application. As with models,
46a5f2f5 741Catalyst is uncommonly flexible. The recipes below are just a start.
cb93c9d7 742
743=head2 Catalyst::View::TT
744
745One of the first things you probably want to do when starting a new
746Catalyst application is set up your View. Catalyst doesn't care how you
747display your data; you can choose to generate HTML, PDF files, or plain
748text if you wanted.
749
750Most Catalyst applications use a template system to generate their HTML,
31e9c5ef 751and though there are several template systems available,
1febc43a 752L<Template Toolkit|Template> is probably the most popular.
cb93c9d7 753
754Once again, the Catalyst developers have done all the hard work, and
755made things easy for the rest of us. Catalyst::View::TT provides the
756interface to Template Toolkit, and provides Helpers which let us set it
757up that much more easily.
758
759=head3 Creating your View
760
761Catalyst::View::TT provides two different helpers for us to use: TT and
762TTSite.
763
764=head4 TT
765
766Create a basic Template Toolkit View using the provided helper script:
767
768 script/myapp_create.pl view TT TT
769
770This will create lib/MyApp/View/MyView.pm, which is going to be pretty
771empty to start. However, it sets everything up that you need to get
772started. You can now define which template you want and forward to your
773view. For instance:
774
775 sub hello : Local {
776 my ( $self, $c ) = @_;
777
778 $c->stash->{template} = 'hello.tt';
779
780 $c->forward( $c->view('TT') );
781 }
782
783In practice you wouldn't do the forwarding manually, but would
784use L<Catalyst::Action::RenderView>.
785
786=head4 TTSite
787
788Although the TT helper does create a functional, working view, you may
789find yourself having to create the same template files and changing the
790same options every time you create a new application. The TTSite helper
791saves us even more time by creating the basic templates and setting some
792common options for us.
793
794Once again, you can use the helper script:
795
796 script/myapp_create.pl view TT TTSite
797
798This time, the helper sets several options for us in the generated View.
799
800 __PACKAGE__->config({
801 CATALYST_VAR => 'Catalyst',
802 INCLUDE_PATH => [
803 MyApp->path_to( 'root', 'src' ),
804 MyApp->path_to( 'root', 'lib' )
805 ],
806 PRE_PROCESS => 'config/main',
807 WRAPPER => 'site/wrapper',
808 ERROR => 'error.tt2',
809 TIMER => 0
810 });
811
812=over
813
b1a08fe1 814=item
cb93c9d7 815
816INCLUDE_PATH defines the directories that Template Toolkit should search
817for the template files.
818
819=item
820
821PRE_PROCESS is used to process configuration options which are common to
822every template file.
823
824=item
825
826WRAPPER is a file which is processed with each template, usually used to
827easily provide a common header and footer for every page.
828
829=back
830
831In addition to setting these options, the TTSite helper also created the
832template and config files for us! In the 'root' directory, you'll notice
833two new directories: src and lib.
834
835Several configuration files in root/lib/config are called by PRE_PROCESS.
836
837The files in root/lib/site are the site-wide templates, called by
838WRAPPER, and display the html framework, control the layout, and provide
839the templates for the header and footer of your page. Using the template
840organization provided makes it much easier to standardize pages and make
841changes when they are (inevitably) needed.
842
843The template files that you will create for your application will go
844into root/src, and you don't need to worry about putting the the <html>
845or <head> sections; just put in the content. The WRAPPER will the rest
846of the page around your template for you.
847
848
849=head3 $c->stash
850
851Of course, having the template system include the header and footer for
852you isn't all that we want our templates to do. We need to be able to
853put data into our templates, and have it appear where and how we want
854it, right? That's where the stash comes in.
855
856In our controllers, we can add data to the stash, and then access it
857from the template. For instance:
858
859 sub hello : Local {
860 my ( $self, $c ) = @_;
861
862 $c->stash->{name} = 'Adam';
863
864 $c->stash->{template} = 'hello.tt';
865
866 $c->forward( $c->view('TT') );
867 }
868
869Then, in hello.tt:
870
871 <strong>Hello, [% name %]!</strong>
872
873When you view this page, it will display "Hello, Adam!"
874
875All of the information in your stash is available, by its name/key, in
876your templates. And your data don't have to be plain, old, boring
877scalars. You can pass array references and hash references, too.
878
879In your controller:
880
881 sub hello : Local {
882 my ( $self, $c ) = @_;
883
884 $c->stash->{names} = [ 'Adam', 'Dave', 'John' ];
885
886 $c->stash->{template} = 'hello.tt';
887
888 $c->forward( $c->view('TT') );
889 }
890
891In hello.tt:
892
893 [% FOREACH name IN names %]
894 <strong>Hello, [% name %]!</strong><br />
895 [% END %]
896
897This allowed us to loop through each item in the arrayref, and display a
898line for each name that we have.
899
900This is the most basic usage, but Template Toolkit is quite powerful,
901and allows you to truly keep your presentation logic separate from the
902rest of your application.
903
904=head3 $c->uri_for()
905
906One of my favorite things about Catalyst is the ability to move an
907application around without having to worry that everything is going to
908break. One of the areas that used to be a problem was with the http
909links in your template files. For example, suppose you have an
910application installed at http://www.domain.com/Calendar. The links point
911to "/Calendar", "/Calendar/2005", "/Calendar/2005/10", etc. If you move
912the application to be at http://www.mydomain.com/Tools/Calendar, then
913all of those links will suddenly break.
914
915That's where $c->uri_for() comes in. This function will merge its
916parameters with either the base location for the app, or its current
917namespace. Let's take a look at a couple of examples.
918
919In your template, you can use the following:
920
921 <a href="[% c.uri_for('/login') %]">Login Here</a>
922
c718cfb6 923Although the parameter starts with a forward slash, this is relative
924to the application root, not the webserver root. This is important to
925remember. So, if your application is installed at
926http://www.domain.com/Calendar, then the link would be
927http://www.mydomain.com/Calendar/Login. If you move your application
928to a different domain or path, then that link will still be correct.
cb93c9d7 929
930Likewise,
931
932 <a href="[% c.uri_for('2005','10', '24') %]">October, 24 2005</a>
933
c718cfb6 934The first parameter does NOT have a forward slash, and so it will be
935relative to the current namespace. If the application is installed at
936http://www.domain.com/Calendar. and if the template is called from
937MyApp::Controller::Display, then the link would become
938http://www.domain.com/Calendar/Display/2005/10/24.
939
940If you want to link to a parent uri of your current namespace you can
941prefix the arguments with multiple '../':
942
943 <a href="[% c.uri_for('../../view', stashed_object.id) %]">User view</a>
cb93c9d7 944
c718cfb6 945Once again, this allows you to move your application around without
946having to worry about broken links. But there's something else, as
947well. Since the links are generated by uri_for, you can use the same
948template file by several different controllers, and each controller
949will get the links that its supposed to. Since we believe in Don't
950Repeat Yourself, this is particularly helpful if you have common
951elements in your site that you want to keep in one file.
cb93c9d7 952
953Further Reading:
954
955L<http://search.cpan.org/perldoc?Catalyst>
956
957L<http://search.cpan.org/perldoc?Catalyst%3A%3AView%3A%3ATT>
958
959L<http://search.cpan.org/perldoc?Template>
960
b1a08fe1 961=head2 Adding RSS feeds
cb93c9d7 962
963Adding RSS feeds to your Catalyst applications is simple. We'll see two
964different aproaches here, but the basic premise is that you forward to
965the normal view action first to get the objects, then handle the output
966differently.
967
968=head3 Using TT templates
969
970This is the aproach used in Agave (L<http://dev.rawmode.org/>).
971
972 sub rss : Local {
973 my ($self,$c) = @_;
974 $c->forward('view');
975 $c->stash->{template}='rss.tt';
976 }
977
b1a08fe1 978Then you need a template. Here's the one from Agave:
cb93c9d7 979
980 <?xml version="1.0" encoding="UTF-8"?>
981 <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
982 <channel>
983 <title>[ [% blog.name || c.config.name || "Agave" %] ] RSS Feed</title>
984 <link>[% base %]</link>
985 <description>Recent posts</description>
986 <language>en-us</language>
987 <ttl>40</ttl>
988 [% WHILE (post = posts.next) %]
989 <item>
990 <title>[% post.title %]</title>
b1a08fe1 991 <description>[% post.formatted_teaser|html%]</description>
cb93c9d7 992 <pubDate>[% post.pub_date %]</pubDate>
993 <guid>[% post.full_uri %]</guid>
994 <link>[% post.full_uri %]</link>
995 <dc:creator>[% post.author.screenname %]</dc:creator>
996 </item>
997 [% END %]
998 </channel>
b1a08fe1 999 </rss>
cb93c9d7 1000
1001=head3 Using XML::Feed
1002
a75d00fb 1003A more robust solution is to use L<XML::Feed>, as was done in the Catalyst
cb93c9d7 1004Advent Calendar. Assuming we have a C<view> action that populates
1005'entries' with some DBIx::Class iterator, the code would look something
1006like this:
1007
1008 sub rss : Local {
1009 my ($self,$c) = @_;
1010 $c->forward('view'); # get the entries
1011
1012 my $feed = XML::Feed->new('RSS');
1013 $feed->title( $c->config->{name} . ' RSS Feed' );
1014 $feed->link( $c->req->base ); # link to the site.
1015 $feed->description('Catalyst advent calendar'); Some description
1016
1017 # Process the entries
1018 while( my $entry = $c->stash->{entries}->next ) {
1019 my $feed_entry = XML::Feed::Entry->new('RSS');
1020 $feed_entry->title($entry->title);
1021 $feed_entry->link( $c->uri_for($entry->link) );
1022 $feed_entry->issued( DateTime->from_epoch(epoch => $entry->created) );
1023 $feed->add_entry($feed_entry);
1024 }
1025 $c->res->body( $feed->as_xml );
1026 }
1027
1028A little more code in the controller, but with this approach you're
b1a08fe1 1029pretty sure to get something that validates.
cb93c9d7 1030
1031Note that for both of the above aproaches, you'll need to set the
1032content type like this:
1033
1034 $c->res->content_type('application/rss+xml');
1035
1036=head3 Final words
1037
1038You could generalize the second variant easily by replacing 'RSS' with a
1039variable, so you can generate Atom feeds with the same code.
1040
1041Now, go ahead and make RSS feeds for all your stuff. The world *needs*
1042updates on your goldfish!
1043
1044=head2 Forcing the browser to download content
1045
1046Sometimes you need your application to send content for download. For
1047example, you can generate a comma-separated values (CSV) file for your
1048users to download and import into their spreadsheet program.
1049
1050Let's say you have an C<Orders> controller which generates a CSV file
1051in the C<export> action (i.e., C<http://localhost:3000/orders/export>):
1052
1053 sub export : Local Args(0) {
1054 my ( $self, $c ) = @_;
1055
1056 # In a real application, you'd generate this from the database
1057 my $csv = "1,5.99\n2,29.99\n3,3.99\n";
1058
1059 $c->res->content_type('text/comma-separated-values');
1060 $c->res->body($csv);
1061 }
1062
1063Normally the browser uses the last part of the URI to generate a
1064filename for data it cannot display. In this case your browser would
1065likely ask you to save a file named C<export>.
1066
1067Luckily you can have the browser download the content with a specific
1068filename by setting the C<Content-Disposition> header:
1069
1070 my $filename = 'Important Orders.csv';
1071 $c->res->header('Content-Disposition', qq[attachment; filename="$filename"]);
1072
1073Note the use of quotes around the filename; this ensures that any
1074spaces in the filename are handled by the browser.
1075
1076Put this right before calling C<< $c->res->body >> and your browser
1077will download a file named C<Important Orders.csv> instead of
1078C<export>.
1079
1080You can also use this to have the browser download content which it
1081normally displays, such as JPEG images or even HTML. Just be sure to
1082set the appropriate content type and disposition.
1083
1084
1085=head1 Controllers
1086
1087Controllers are the main point of communication between the web server
1088and your application. Here we explore some aspects of how they work.
1089
cb93c9d7 1090=head2 Action Types
1091
1092=head3 Introduction
1093
c718cfb6 1094A Catalyst application is driven by one or more Controller
1095modules. There are a number of ways that Catalyst can decide which of
1096the methods in your controller modules it should call. Controller
1097methods are also called actions, because they determine how your
1098catalyst application should (re-)act to any given URL. When the
1099application is started up, catalyst looks at all your actions, and
1100decides which URLs they map to.
cb93c9d7 1101
1102=head3 Type attributes
1103
1104Each action is a normal method in your controller, except that it has an
a7b39a0c 1105L<attribute|attributes>
cb93c9d7 1106attached. These can be one of several types.
1107
1108Assume our Controller module starts with the following package declaration:
1109
1110 package MyApp::Controller::Buckets;
1111
1112and we are running our application on localhost, port 3000 (the test
1113server default).
1114
1115=over 4
1116
1117=item Path
1118
1119A Path attribute also takes an argument, this can be either a relative
c718cfb6 1120or an absolute path. A relative path will be relative to the
1121controller namespace, an absolute path will represent an exact
1122matching URL.
cb93c9d7 1123
1124 sub my_handles : Path('handles') { .. }
1125
1126becomes
1127
1128 http://localhost:3000/buckets/handles
1129
1130and
1131
1132 sub my_handles : Path('/handles') { .. }
1133
b1a08fe1 1134becomes
cb93c9d7 1135
1136 http://localhost:3000/handles
1137
6daaedc0 1138See also: L<Catalyst::DispatchType::Path>
1139
cb93c9d7 1140=item Local
1141
c718cfb6 1142When using a Local attribute, no parameters are needed, instead, the
1143name of the action is matched in the URL. The namespaces created by
1144the name of the controller package is always part of the URL.
cb93c9d7 1145
1146 sub my_handles : Local { .. }
1147
1148becomes
1149
1150 http://localhost:3000/buckets/my_handles
1151
1152=item Global
1153
c718cfb6 1154A Global attribute is similar to a Local attribute, except that the
1155namespace of the controller is ignored, and matching starts at root.
cb93c9d7 1156
1157 sub my_handles : Global { .. }
1158
1159becomes
1160
1161 http://localhost:3000/my_handles
1162
1163=item Regex
1164
c718cfb6 1165By now you should have figured that a Regex attribute is just what it
1166sounds like. This one takes a regular expression, and matches starting
1167from root. These differ from the rest as they can match multiple URLs.
cb93c9d7 1168
1169 sub my_handles : Regex('^handles') { .. }
1170
1171matches
1172
1173 http://localhost:3000/handles
1174
b1a08fe1 1175and
cb93c9d7 1176
1177 http://localhost:3000/handles_and_other_parts
1178
1179etc.
1180
6daaedc0 1181See also: L<Catalyst::DispatchType::Regex>
1182
cb93c9d7 1183=item LocalRegex
1184
1185A LocalRegex is similar to a Regex, except it only matches below the current
1186controller namespace.
1187
1188 sub my_handles : LocalRegex(^handles') { .. }
1189
1190matches
1191
1192 http://localhost:3000/buckets/handles
1193
1194and
1195
1196 http://localhost:3000/buckets/handles_and_other_parts
1197
1198etc.
1199
6daaedc0 1200=item Chained
1201
1202See L<Catalyst::DispatchType::Chained> for a description of how the chained
1203dispatch type works.
1204
cb93c9d7 1205=item Private
1206
c718cfb6 1207Last but not least, there is the Private attribute, which allows you
1208to create your own internal actions, which can be forwarded to, but
1209won't be matched as URLs.
cb93c9d7 1210
1211 sub my_handles : Private { .. }
1212
1213becomes nothing at all..
1214
c718cfb6 1215Catalyst also predefines some special Private actions, which you can
1216override, these are:
cb93c9d7 1217
1218=over 4
1219
1220=item default
1221
c718cfb6 1222The default action will be called, if no other matching action is
1223found. If you don't have one of these in your namespace, or any sub
1224part of your namespace, you'll get an error page instead. If you want
1225to find out where it was the user was trying to go, you can look in
1226the request object using C<< $c->req->path >>.
cb93c9d7 1227
85d49fb6 1228 sub default :Path { .. }
cb93c9d7 1229
c718cfb6 1230works for all unknown URLs, in this controller namespace, or every one
1231if put directly into MyApp.pm.
cb93c9d7 1232
b1a08fe1 1233=item index
cb93c9d7 1234
c718cfb6 1235The index action is called when someone tries to visit the exact
1236namespace of your controller. If index, default and matching Path
1237actions are defined, then index will be used instead of default and
1238Path.
cb93c9d7 1239
85d49fb6 1240 sub index :Path :Args(0) { .. }
cb93c9d7 1241
1242becomes
1243
1244 http://localhost:3000/buckets
1245
1246=item begin
1247
c718cfb6 1248The begin action is called at the beginning of every request involving
1249this namespace directly, before other matching actions are called. It
1250can be used to set up variables/data for this particular part of your
1251app. A single begin action is called, its always the one most relevant
1252to the current namespace.
cb93c9d7 1253
1254 sub begin : Private { .. }
1255
b1a08fe1 1256is called once when
cb93c9d7 1257
1258 http://localhost:3000/bucket/(anything)?
1259
1260is visited.
1261
1262=item end
1263
c718cfb6 1264Like begin, this action is always called for the namespace it is in,
1265after every other action has finished. It is commonly used to forward
1266processing to the View component. A single end action is called, its
1267always the one most relevant to the current namespace.
cb93c9d7 1268
1269
1270 sub end : Private { .. }
1271
1272is called once after any actions when
1273
1274 http://localhost:3000/bucket/(anything)?
1275
1276is visited.
1277
1278=item auto
1279
c718cfb6 1280Lastly, the auto action is magic in that B<every> auto action in the
1281chain of paths up to and including the ending namespace, will be
1282called. (In contrast, only one of the begin/end/default actions will
1283be called, the relevant one).
cb93c9d7 1284
b1a08fe1 1285 package MyApp::Controller::Root;
cb93c9d7 1286 sub auto : Private { .. }
1287
b1a08fe1 1288and
cb93c9d7 1289
1290 sub auto : Private { .. }
1291
b1a08fe1 1292will both be called when visiting
cb93c9d7 1293
1294 http://localhost:3000/bucket/(anything)?
1295
1296=back
1297
1298=back
1299
1300=head3 A word of warning
1301
b1a08fe1 1302You can put root actions in your main MyApp.pm file, but this is deprecated,
1303please put your actions into your Root controller.
cb93c9d7 1304
7cfce6e1 1305=head3 Flowchart
cb93c9d7 1306
7cfce6e1 1307A graphical flowchart of how the dispatcher works can be found on the wiki at
1308L<http://dev.catalyst.perl.org/attachment/wiki/WikiStart/catalyst-flow.png>.
cb93c9d7 1309
7cfce6e1 1310=head2 DRY Controllers with Chained actions
6daaedc0 1311
1312Imagine that you would like the following paths in your application:
1313
1314=over
1315
1b4425c5 1316=item B<< /cd/<ID>/track/<ID> >>
6daaedc0 1317
1318Displays info on a particular track.
b1a08fe1 1319
6daaedc0 1320In the case of a multi-volume CD, this is the track sequence.
1321
1b4425c5 1322=item B<< /cd/<ID>/volume/<ID>/track/<ID> >>
6daaedc0 1323
1324Displays info on a track on a specific volume.
1325
1326=back
1327
1328Here is some example code, showing how to do this with chained controllers:
1329
1330 package CD::Controller;
1331 use base qw/Catalyst::Controller/;
b1a08fe1 1332
6daaedc0 1333 sub root : Chained('/') PathPart('/cd') CaptureArgs(1) {
1334 my ($self, $c, $cd_id) = @_;
1335 $c->stash->{cd_id} = $cd_id;
1336 $c->stash->{cd} = $self->model('CD')->find_by_id($cd_id);
1337 }
b1a08fe1 1338
6daaedc0 1339 sub trackinfo : Chained('track') PathPart('') Args(0) RenderView {
1340 my ($self, $c) = @_;
1341 }
b1a08fe1 1342
6daaedc0 1343 package CD::Controller::ByTrackSeq;
1344 use base qw/CD::Controller/;
b1a08fe1 1345
6daaedc0 1346 sub track : Chained('root') PathPart('track') CaptureArgs(1) {
1347 my ($self, $c, $track_seq) = @_;
1348 $c->stash->{track} = $self->stash->{cd}->find_track_by_seq($track_seq);
1349 }
b1a08fe1 1350
6daaedc0 1351 package CD::Controller::ByTrackVolNo;
1352 use base qw/CD::Controller/;
b1a08fe1 1353
6daaedc0 1354 sub volume : Chained('root') PathPart('volume') CaptureArgs(1) {
1355 my ($self, $c, $volume) = @_;
1356 $c->stash->{volume} = $volume;
1357 }
b1a08fe1 1358
6daaedc0 1359 sub track : Chained('volume') PathPart('track') CaptureArgs(1) {
1360 my ($self, $c, $track_no) = @_;
1361 $c->stash->{track} = $self->stash->{cd}->find_track_by_vol_and_track_no(
1362 $c->stash->{volume}, $track_no
1363 );
1364 }
b1a08fe1 1365
1366Note that adding other actions (i.e. chain endpoints) which operate on a track
6daaedc0 1367is simply a matter of adding a new sub to CD::Controller - no code is duplicated,
1368even though there are two different methods of looking up a track.
1369
1370This technique can be expanded as needed to fulfil your requirements - for example,
1371if you inherit the first action of a chain from a base class, then mixing in a
1372different base class can be used to duplicate an entire URL hieratchy at a different
1373point within your application.
1374
cb93c9d7 1375=head2 Component-based Subrequests
1376
1377See L<Catalyst::Plugin::SubRequest>.
1378
1379=head2 File uploads
1380
1381=head3 Single file upload with Catalyst
1382
1383To implement uploads in Catalyst, you need to have a HTML form similar to
1384this:
1385
1386 <form action="/upload" method="post" enctype="multipart/form-data">
1387 <input type="hidden" name="form_submit" value="yes">
1388 <input type="file" name="my_file">
1389 <input type="submit" value="Send">
1390 </form>
1391
1392It's very important not to forget C<enctype="multipart/form-data"> in
1393the form.
1394
1395Catalyst Controller module 'upload' action:
1396
1397 sub upload : Global {
1398 my ($self, $c) = @_;
1399
1400 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1401
1402 if ( my $upload = $c->request->upload('my_file') ) {
1403
1404 my $filename = $upload->filename;
1405 my $target = "/tmp/upload/$filename";
1406
1407 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1408 die( "Failed to copy '$filename' to '$target': $!" );
1409 }
1410 }
1411 }
1412
1413 $c->stash->{template} = 'file_upload.html';
1414 }
1415
1416=head3 Multiple file upload with Catalyst
1417
1418Code for uploading multiple files from one form needs a few changes:
1419
1420The form should have this basic structure:
1421
1422 <form action="/upload" method="post" enctype="multipart/form-data">
1423 <input type="hidden" name="form_submit" value="yes">
1424 <input type="file" name="file1" size="50"><br>
1425 <input type="file" name="file2" size="50"><br>
1426 <input type="file" name="file3" size="50"><br>
1427 <input type="submit" value="Send">
1428 </form>
1429
1430And in the controller:
1431
1432 sub upload : Local {
1433 my ($self, $c) = @_;
1434
1435 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1436
1437 for my $field ( $c->req->upload ) {
1438
1439 my $upload = $c->req->upload($field);
1440 my $filename = $upload->filename;
1441 my $target = "/tmp/upload/$filename";
1442
1443 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1444 die( "Failed to copy '$filename' to '$target': $!" );
1445 }
1446 }
1447 }
1448
1449 $c->stash->{template} = 'file_upload.html';
1450 }
1451
1452C<for my $field ($c-E<gt>req->upload)> loops automatically over all file
1453input fields and gets input names. After that is basic file saving code,
1454just like in single file upload.
1455
1456Notice: C<die>ing might not be what you want to do, when an error
1457occurs, but it works as an example. A better idea would be to store
1458error C<$!> in $c->stash->{error} and show a custom error template
1459displaying this message.
1460
1461For more information about uploads and usable methods look at
1462L<Catalyst::Request::Upload> and L<Catalyst::Request>.
1463
1464=head2 Forwarding with arguments
1465
1466Sometimes you want to pass along arguments when forwarding to another
1467action. As of version 5.30, arguments can be passed in the call to
1468C<forward>; in earlier versions, you can manually set the arguments in
1469the Catalyst Request object:
1470
1471 # version 5.30 and later:
1472 $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
1473
1474 # pre-5.30
1475 $c->req->args([qw/arg1 arg2 arg3/]);
1476 $c->forward('/wherever');
1477
b1a08fe1 1478(See the L<Catalyst::Manual::Intro> Flow_Control section for more
cb93c9d7 1479information on passing arguments via C<forward>.)
1480
6daaedc0 1481=head2 Chained dispatch using base classes, and inner packages.
1482
1483 package MyApp::Controller::Base;
1484 use base qw/Catalyst::Controller/;
1485
b1a08fe1 1486 sub key1 : Chained('/')
31e9c5ef 1487
e2728084 1488=head2 Extending RenderView (formerly DefaultEnd)
1489
1490The recommended approach for an C<end> action is to use
1491L<Catalyst::Action::RenderView> (taking the place of
1492L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
1493However there are times when you need to add a bit to it, but don't want
1494to write your own C<end> action.
1495
1496You can extend it like this:
1497
1498To add something to an C<end> action that is called before rendering
1499(this is likely to be what you want), simply place it in the C<end>
1500method:
1501
1502 sub end : ActionClass('RenderView') {
1503 my ( $self, $c ) = @_;
1504 # do stuff here; the RenderView action is called afterwards
1505 }
1506
1507To add things to an C<end> action that are called I<after> rendering,
1508you can set it up like this:
1509
1510 sub render : ActionClass('RenderView') { }
1511
1512 sub end : Private {
1513 my ( $self, $c ) = @_;
1514 $c->forward('render');
1515 # do stuff here
1516 }
1517
31e9c5ef 1518
cb93c9d7 1519
1520=head1 Deployment
1521
1522The recipes below describe aspects of the deployment process,
1523including web server engines and tips to improve application efficiency.
1524
1525=head2 mod_perl Deployment
1526
97e6fe89 1527mod_perl is not the best solution for many applications, but we'll list some
1528pros and cons so you can decide for yourself. The other (recommended)
1529deployment option is FastCGI, for which see below.
cb93c9d7 1530
1531=head3 Pros
1532
1533=head4 Speed
1534
97e6fe89 1535mod_perl is fast and your app will be loaded in memory
cb93c9d7 1536within each Apache process.
1537
1538=head4 Shared memory for multiple apps
1539
1540If you need to run several Catalyst apps on the same server, mod_perl will
1541share the memory for common modules.
1542
1543=head3 Cons
1544
1545=head4 Memory usage
1546
1547Since your application is fully loaded in memory, every Apache process will
1548be rather large. This means a large Apache process will be tied up while
1549serving static files, large files, or dealing with slow clients. For this
1550reason, it is best to run a two-tiered web architecture with a lightweight
1551frontend server passing dynamic requests to a large backend mod_perl
1552server.
1553
1554=head4 Reloading
1555
1556Any changes made to the core code of your app require a full Apache restart.
1557Catalyst does not support Apache::Reload or StatINC. This is another good
1558reason to run a frontend web server where you can set up an
1559C<ErrorDocument 502> page to report that your app is down for maintenance.
1560
1561=head4 Cannot run multiple versions of the same app
1562
1563It is not possible to run two different versions of the same application in
1564the same Apache instance because the namespaces will collide.
1565
97e6fe89 1566=head4 Cannot run different versions of libraries.
1567
1568If you have two differnet applications which run on the same machine,
1569which need two different versions of a library then the only way to do
1570this is to have per-vhost perl interpreters (with different library paths).
1571This is entirely possible, but nullifies all the memory sharing benefits that
1572you get from having multiple applications sharing the same interpreter.
1573
cb93c9d7 1574=head4 Setup
1575
1576Now that we have that out of the way, let's talk about setting up mod_perl
1577to run a Catalyst app.
1578
1579=head4 1. Install Catalyst::Engine::Apache
1580
b1a08fe1 1581You should install the latest versions of both Catalyst and
cb93c9d7 1582Catalyst::Engine::Apache. The Apache engines were separated from the
1583Catalyst core in version 5.50 to allow for updates to the engine without
1584requiring a new Catalyst release.
1585
1586=head4 2. Install Apache with mod_perl
1587
1588Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly
1589recommended. With Apache 2, make sure you are using the prefork MPM and not
1590the worker MPM. The reason for this is that many Perl modules are not
1591thread-safe and may have problems running within the threaded worker
1592environment. Catalyst is thread-safe however, so if you know what you're
1593doing, you may be able to run using worker.
1594
1595In Debian, the following commands should get you going.
1596
1597 apt-get install apache2-mpm-prefork
1598 apt-get install libapache2-mod-perl2
1599
1600=head4 3. Configure your application
1601
1602Every Catalyst application will automagically become a mod_perl handler
1603when run within mod_perl. This makes the configuration extremely easy.
1604Here is a basic Apache 2 configuration.
1605
1606 PerlSwitches -I/var/www/MyApp/lib
1607 PerlModule MyApp
b1a08fe1 1608
cb93c9d7 1609 <Location />
1610 SetHandler modperl
1611 PerlResponseHandler MyApp
1612 </Location>
1613
1614The most important line here is C<PerlModule MyApp>. This causes mod_perl
1615to preload your entire application into shared memory, including all of your
1616controller, model, and view classes and configuration. If you have -Debug
1617mode enabled, you will see the startup output scroll by when you first
1618start Apache.
1619
1620For an example Apache 1.3 configuration, please see the documentation for
1621L<Catalyst::Engine::Apache::MP13>.
1622
1623=head3 Test It
1624
1625That's it, your app is now a full-fledged mod_perl application! Try it out
1626by going to http://your.server.com/.
1627
1628=head3 Other Options
1629
1630=head4 Non-root location
1631
1632You may not always want to run your app at the root of your server or virtual
1633host. In this case, it's a simple change to run at any non-root location
1634of your choice.
1635
1636 <Location /myapp>
1637 SetHandler modperl
1638 PerlResponseHandler MyApp
1639 </Location>
b1a08fe1 1640
cb93c9d7 1641When running this way, it is best to make use of the C<uri_for> method in
1642Catalyst for constructing correct links.
1643
1644=head4 Static file handling
1645
1646Static files can be served directly by Apache for a performance boost.
1647
1648 DocumentRoot /var/www/MyApp/root
1649 <Location /static>
1650 SetHandler default-handler
1651 </Location>
b1a08fe1 1652
cb93c9d7 1653This will let all files within root/static be handled directly by Apache. In
1654a two-tiered setup, the frontend server should handle static files.
1655The configuration to do this on the frontend will vary.
1656
3cca8359 1657The same is accomplished in lighttpd with the following snippet:
1658
1659 $HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" {
1660 fastcgi.server = (
1661 "" => (
1662 "MyApp" => (
1663 "socket" => "/tmp/myapp.socket",
1664 "check-local" => "disable",
1665 )
1666 )
1667 )
1668 }
1669
1670Which serves everything in the img, static, css directories
1671statically, as well as the favicon file.
1672
c1c35b01 1673Note the path of the application needs to be stated explicitly in the
1674web server configuration for both these recipes.
3cca8359 1675
cb93c9d7 1676=head2 Catalyst on shared hosting
1677
1678So, you want to put your Catalyst app out there for the whole world to
1679see, but you don't want to break the bank. There is an answer - if you
1680can get shared hosting with FastCGI and a shell, you can install your
1681Catalyst app in a local directory on your shared host. First, run
1682
1683 perl -MCPAN -e shell
1684
1685and go through the standard CPAN configuration process. Then exit out
1686without installing anything. Next, open your .bashrc and add
1687
1688 export PATH=$HOME/local/bin:$HOME/local/script:$PATH
1689 perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'`
1690 export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB
1691
1692and log out, then back in again (or run C<". .bashrc"> if you
1693prefer). Finally, edit C<.cpan/CPAN/MyConfig.pm> and add
1694
1695 'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local],
1696 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local],
1697
1698Now you can install the modules you need using CPAN as normal; they
1699will be installed into your local directory, and perl will pick them
1700up. Finally, change directory into the root of your virtual host and
1701symlink your application's script directory in:
1702
1703 cd path/to/mydomain.com
1704 ln -s ~/lib/MyApp/script script
1705
1706And add the following lines to your .htaccess file (assuming the server
1707is setup to handle .pl as fcgi - you may need to rename the script to
1708myapp_fastcgi.fcgi and/or use a SetHandler directive):
1709
1710 RewriteEngine On
1711 RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl
1712 RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
1713
1714Now C<http://mydomain.com/> should now Just Work. Congratulations, now
1715you can tell your friends about your new website (or in our case, tell
1716the client it's time to pay the invoice :) )
1717
1718=head2 FastCGI Deployment
1719
1720FastCGI is a high-performance extension to CGI. It is suitable
1721for production environments.
1722
1723=head3 Pros
1724
1725=head4 Speed
1726
1727FastCGI performs equally as well as mod_perl. Don't let the 'CGI' fool you;
1728your app runs as multiple persistent processes ready to receive connections
1729from the web server.
1730
1731=head4 App Server
1732
1733When using external FastCGI servers, your application runs as a standalone
1734application server. It may be restarted independently from the web server.
1735This allows for a more robust environment and faster reload times when
1736pushing new app changes. The frontend server can even be configured to
1737display a friendly "down for maintenance" page while the application is
1738restarting.
1739
1740=head4 Load-balancing
1741
1742You can launch your application on multiple backend servers and allow the
1743frontend web server to load-balance between all of them. And of course, if
1744one goes down, your app continues to run fine.
1745
1746=head4 Multiple versions of the same app
1747
1748Each FastCGI application is a separate process, so you can run different
1749versions of the same app on a single server.
1750
1751=head4 Can run with threaded Apache
1752
1753Since your app is not running inside of Apache, the faster mpm_worker module
1754can be used without worrying about the thread safety of your application.
1755
1756=head3 Cons
1757
278f816d 1758You may have to disable mod_deflate. If you experience page hangs with
1759mod_fastcgi then remove deflate.load and deflate.conf from mods-enabled/
1760
cb93c9d7 1761=head4 More complex environment
1762
1763With FastCGI, there are more things to monitor and more processes running
1764than when using mod_perl.
1765
1766=head3 Setup
1767
1768=head4 1. Install Apache with mod_fastcgi
1769
1770mod_fastcgi for Apache is a third party module, and can be found at
1771L<http://www.fastcgi.com/>. It is also packaged in many distributions,
31e9c5ef 1772for example, libapache2-mod-fastcgi in Debian. You will also need to install
1773the L<FCGI> module from cpan.
cb93c9d7 1774
b1d4f0ad 1775Important Note! If you experience difficulty properly rendering pages,
1776try disabling Apache's mod_deflate (Deflate Module), e.g. 'a2dismod deflate'.
1777
cb93c9d7 1778=head4 2. Configure your application
1779
1780 # Serve static content directly
1781 DocumentRoot /var/www/MyApp/root
1782 Alias /static /var/www/MyApp/root/static
1783
1784 FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3
1785 Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/
b1a08fe1 1786
cb93c9d7 1787 # Or, run at the root
1788 Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
b1a08fe1 1789
cb93c9d7 1790The above commands will launch 3 app processes and make the app available at
1791/myapp/
1792
1793=head3 Standalone server mode
1794
1795While not as easy as the previous method, running your app as an external
1796server gives you much more flexibility.
1797
1798First, launch your app as a standalone server listening on a socket.
1799
1800 script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
b1a08fe1 1801
cb93c9d7 1802You can also listen on a TCP port if your web server is not on the same
1803machine.
1804
1805 script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
b1a08fe1 1806
cb93c9d7 1807You will probably want to write an init script to handle starting/stopping
1808of the app using the pid file.
1809
1810Now, we simply configure Apache to connect to the running server.
1811
1812 # 502 is a Bad Gateway error, and will occur if the backend server is down
1813 # This allows us to display a friendly static page that says "down for
1814 # maintenance"
1815 Alias /_errors /var/www/MyApp/root/error-pages
1816 ErrorDocument 502 /_errors/502.html
1817
31bdf270 1818 FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
1819 Alias /myapp/ /tmp/myapp.fcgi/
b1a08fe1 1820
cb93c9d7 1821 # Or, run at the root
31bdf270 1822 Alias / /tmp/myapp.fcgi/
b1a08fe1 1823
cb93c9d7 1824=head3 More Info
1825
1826L<Catalyst::Engine::FastCGI>.
1827
1828=head2 Development server deployment
1829
1830The development server is a mini web server written in perl. If you
1831expect a low number of hits or you don't need mod_perl/FastCGI speed,
1832you could use the development server as the application server with a
ad2a47ab 1833lightweight proxy web server at the front. However, consider using
816fc503 1834L<Catalyst::Engine::HTTP::Prefork> for this kind of deployment instead, since
ad2a47ab 1835it can better handle multiple concurrent requests without forking, or can
1836prefork a set number of servers for improved performance.
cb93c9d7 1837
1838=head3 Pros
1839
1840As this is an application server setup, the pros are the same as
1841FastCGI (with the exception of speed).
1842It is also:
1843
1844=head4 Simple
1845
1846The development server is what you create your code on, so if it works
1847here, it should work in production!
1848
1849=head3 Cons
1850
1851=head4 Speed
1852
1853Not as fast as mod_perl or FastCGI. Needs to fork for each request
1854that comes in - make sure static files are served by the web server to
1855save forking.
1856
1857=head3 Setup
1858
1859=head4 Start up the development server
1860
ad2a47ab 1861 script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid
cb93c9d7 1862
1863You will probably want to write an init script to handle stop/starting
1864the app using the pid file.
1865
1866=head4 Configuring Apache
1867
1868Make sure mod_proxy is enabled and add:
1869
1870 # Serve static content directly
1871 DocumentRoot /var/www/MyApp/root
1872 Alias /static /var/www/MyApp/root/static
1873
1874 ProxyRequests Off
1875 <Proxy *>
1876 Order deny,allow
1877 Allow from all
1878 </Proxy>
816fc503 1879
1880 # Need to specifically stop these paths from being passed to proxy
1881 ProxyPass /static !
1882 ProxyPass /favicon.ico !
1883
cb93c9d7 1884 ProxyPass / http://localhost:8080/
1885 ProxyPassReverse / http://localhost:8080/
1886
b1a08fe1 1887 # This is optional if you'd like to show a custom error page
816fc503 1888 # if the proxy is not available
1889 ErrorDocument 502 /static/error_pages/http502.html
1890
cb93c9d7 1891You can wrap the above within a VirtualHost container if you want
1892different apps served on the same host.
1893
1894=head2 Quick deployment: Building PAR Packages
1895
1896You have an application running on your development box, but then you
1897have to quickly move it to another one for
1898demonstration/deployment/testing...
1899
1900PAR packages can save you from a lot of trouble here. They are usual Zip
1901files that contain a blib tree; you can even include all prereqs and a
1902perl interpreter by setting a few flags!
1903
1904=head3 Follow these few points to try it out!
1905
19061. Install Catalyst and PAR 0.89 (or later)
1907
1908 % perl -MCPAN -e 'install Catalyst'
1909 ...
1910 % perl -MCPAN -e 'install PAR'
1911 ...
1912
19132. Create a application
1914
1915 % catalyst.pl MyApp
1916 ...
1917 % cd MyApp
1918
1919Recent versions of Catalyst (5.62 and up) include
1920L<Module::Install::Catalyst>, which simplifies the process greatly. From the shell in your application directory:
1921
1922 % perl Makefile.PL
1923 % make catalyst_par
1924
b1a08fe1 1925You can customise the PAR creation process by special "catalyst_par_*" commands
1926available from L<Module::Install::Catalyst>. You can add these commands in your
3f3d414b 1927Makefile.PL just before the line containing "catalyst;"
1928
b1a08fe1 1929 #Makefile.PL example with extra PAR options
3f3d414b 1930 use inc::Module::Install;
1931
1932 name 'MyApp';
1933 all_from 'lib\MyApp.pm';
1934
1935 requires 'Catalyst::Runtime' => '5.80005';
1936 <snip>
1937 ...
1938 <snip>
1939
1940 catalyst_par_core(1); # bundle perl core modules in the resulting PAR
1941 catalyst_par_multiarch(1); # build a multi-architecture PAR file
1942 catalyst_par_classes(qw/
1943 Some::Additional::Module
1944 Some::Other::Module
1945 /); # specify additional modules you want to be included into PAR
1946 catalyst;
1947
1948 install_script glob('script/*.pl');
1949 auto_install;
1950 WriteAll;
1951
cb93c9d7 1952Congratulations! Your package "myapp.par" is ready, the following
1953steps are just optional.
1954
19553. Test your PAR package with "parl" (no typo)
1956
1957 % parl myapp.par
1958 Usage:
1959 [parl] myapp[.par] [script] [arguments]
1960
1961 Examples:
1962 parl myapp.par myapp_server.pl -r
1963 myapp myapp_cgi.pl
1964
1965 Available scripts:
1966 myapp_cgi.pl
1967 myapp_create.pl
1968 myapp_fastcgi.pl
1969 myapp_server.pl
1970 myapp_test.pl
1971
1972 % parl myapp.par myapp_server.pl
1973 You can connect to your server at http://localhost:3000
1974
1975Yes, this nifty little starter application gets automatically included.
1976You can also use "catalyst_par_script('myapp_server.pl')" to set a
1977default script to execute.
1978
19796. Want to create a binary that includes the Perl interpreter?
1980
1981 % pp -o myapp myapp.par
1982 % ./myapp myapp_server.pl
1983 You can connect to your server at http://localhost:3000
1984
1985=head2 Serving static content
1986
1987Serving static content in Catalyst used to be somewhat tricky; the use
1988of L<Catalyst::Plugin::Static::Simple> makes everything much easier.
1989This plugin will automatically serve your static content during development,
1990but allows you to easily switch to Apache (or other server) in a
1991production environment.
1992
1993=head3 Introduction to Static::Simple
1994
1995Static::Simple is a plugin that will help to serve static content for your
1996application. By default, it will serve most types of files, excluding some
1997standard Template Toolkit extensions, out of your B<root> file directory. All
1998files are served by path, so if B<images/me.jpg> is requested, then
1999B<root/images/me.jpg> is found and served.
2000
2001=head3 Usage
2002
2003Using the plugin is as simple as setting your use line in MyApp.pm to include:
2004
b411df01 2005 use Catalyst qw/Static::Simple/;
cb93c9d7 2006
2007and already files will be served.
2008
2009=head3 Configuring
2010
2011Static content is best served from a single directory within your root
2012directory. Having many different directories such as C<root/css> and
2013C<root/images> requires more code to manage, because you must separately
2014identify each static directory--if you decide to add a C<root/js>
2015directory, you'll need to change your code to account for it. In
2016contrast, keeping all static directories as subdirectories of a main
2017C<root/static> directory makes things much easier to manage. Here's an
2018example of a typical root directory structure:
2019
2020 root/
2021 root/content.tt
2022 root/controller/stuff.tt
2023 root/header.tt
2024 root/static/
2025 root/static/css/main.css
2026 root/static/images/logo.jpg
2027 root/static/js/code.js
2028
2029
2030All static content lives under C<root/static>, with everything else being
2031Template Toolkit files.
2032
2033=over 4
2034
2035=item Include Path
2036
2037You may of course want to change the default locations, and make
2038Static::Simple look somewhere else, this is as easy as:
2039
2040 MyApp->config->{static}->{include_path} = [
2041 MyApp->config->{root},
b1a08fe1 2042 '/path/to/my/files'
cb93c9d7 2043 ];
2044
2045When you override include_path, it will not automatically append the
2046normal root path, so you need to add it yourself if you still want
2047it. These will be searched in order given, and the first matching file
2048served.
2049
2050=item Static directories
2051
2052If you want to force some directories to be only static, you can set
2053them using paths relative to the root dir, or regular expressions:
2054
2055 MyApp->config->{static}->{dirs} = [
2056 'static',
2057 qr/^(images|css)/,
2058 ];
2059
2060=item File extensions
2061
2062By default, the following extensions are not served (that is, they will
2063be processed by Catalyst): B<tmpl, tt, tt2, html, xhtml>. This list can
2064be replaced easily:
2065
2066 MyApp->config->{static}->{ignore_extensions} = [
b1a08fe1 2067 qw/tmpl tt tt2 html xhtml/
cb93c9d7 2068 ];
2069
2070=item Ignoring directories
2071
2072Entire directories can be ignored. If used with include_path,
2073directories relative to the include_path dirs will also be ignored:
2074
2075 MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
2076
2077=back
2078
2079=head3 More information
2080
2081L<http://search.cpan.org/dist/Catalyst-Plugin-Static-Simple/>
2082
2083=head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
2084
2085In some situations you might want to control things more directly,
2086using L<Catalyst::Plugin::Static>.
2087
2088In your main application class (MyApp.pm), load the plugin:
2089
b411df01 2090 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
cb93c9d7 2091
2092You will also need to make sure your end method does I<not> forward
2093static content to the view, perhaps like this:
2094
2095 sub end : Private {
2096 my ( $self, $c ) = @_;
2097
b1a08fe1 2098 $c->forward( 'MyApp::View::TT' )
cb93c9d7 2099 unless ( $c->res->body || !$c->stash->{template} );
2100 }
2101
2102This code will only forward to the view if a template has been
2103previously defined by a controller and if there is not already data in
2104C<$c-E<gt>res-E<gt>body>.
2105
2106Next, create a controller to handle requests for the /static path. Use
2107the Helper to save time. This command will create a stub controller as
2108C<lib/MyApp/Controller/Static.pm>.
2109
2110 $ script/myapp_create.pl controller Static
2111
2112Edit the file and add the following methods:
2113
2114 # serve all files under /static as static files
2115 sub default : Path('/static') {
2116 my ( $self, $c ) = @_;
2117
2118 # Optional, allow the browser to cache the content
2119 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
2120
2121 $c->serve_static; # from Catalyst::Plugin::Static
2122 }
2123
2124 # also handle requests for /favicon.ico
2125 sub favicon : Path('/favicon.ico') {
2126 my ( $self, $c ) = @_;
2127
2128 $c->serve_static;
2129 }
2130
2131You can also define a different icon for the browser to use instead of
2132favicon.ico by using this in your HTML header:
2133
2134 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
2135
2136=head3 Common problems with the Static plugin
2137
2138The Static plugin makes use of the C<shared-mime-info> package to
2139automatically determine MIME types. This package is notoriously
2140difficult to install, especially on win32 and OS X. For OS X the easiest
2141path might be to install Fink, then use C<apt-get install
2142shared-mime-info>. Restart the server, and everything should be fine.
2143
2144Make sure you are using the latest version (>= 0.16) for best
2145results. If you are having errors serving CSS files, or if they get
2146served as text/plain instead of text/css, you may have an outdated
2147shared-mime-info version. You may also wish to simply use the following
2148code in your Static controller:
2149
2150 if ($c->req->path =~ /css$/i) {
2151 $c->serve_static( "text/css" );
2152 } else {
2153 $c->serve_static;
2154 }
2155
2156=head3 Serving Static Files with Apache
2157
2158When using Apache, you can bypass Catalyst and any Static
2159plugins/controllers controller by intercepting requests for the
2160C<root/static> path at the server level. All that is required is to
2161define a DocumentRoot and add a separate Location block for your static
2162content. Here is a complete config for this application under mod_perl
21631.x:
2164
2165 <Perl>
2166 use lib qw(/var/www/MyApp/lib);
2167 </Perl>
2168 PerlModule MyApp
2169
2170 <VirtualHost *>
2171 ServerName myapp.example.com
2172 DocumentRoot /var/www/MyApp/root
2173 <Location />
2174 SetHandler perl-script
2175 PerlHandler MyApp
2176 </Location>
2177 <LocationMatch "/(static|favicon.ico)">
2178 SetHandler default-handler
2179 </LocationMatch>
2180 </VirtualHost>
2181
2182And here's a simpler example that'll get you started:
2183
2184 Alias /static/ "/my/static/files/"
2185 <Location "/static">
2186 SetHandler none
2187 </Location>
2188
2189=head2 Caching
2190
2191Catalyst makes it easy to employ several different types of caching to
2192speed up your applications.
2193
2194=head3 Cache Plugins
2195
2196There are three wrapper plugins around common CPAN cache modules:
2197Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be
2198used to cache the result of slow operations.
2199
ca7528df 2200The Catalyst Advent Calendar uses the FileCache plugin to cache the
cb93c9d7 2201rendered XHTML version of the source POD document. This is an ideal
ca7528df 2202application for a cache because the source document changes
2203infrequently but may be viewed many times.
cb93c9d7 2204
b411df01 2205 use Catalyst qw/Cache::FileCache/;
b1a08fe1 2206
cb93c9d7 2207 ...
b1a08fe1 2208
cb93c9d7 2209 use File::stat;
2210 sub render_pod : Local {
2211 my ( self, $c ) = @_;
b1a08fe1 2212
cb93c9d7 2213 # the cache is keyed on the filename and the modification time
2214 # to check for updates to the file.
2215 my $file = $c->path_to( 'root', '2005', '11.pod' );
2216 my $mtime = ( stat $file )->mtime;
b1a08fe1 2217
cb93c9d7 2218 my $cached_pod = $c->cache->get("$file $mtime");
2219 if ( !$cached_pod ) {
2220 $cached_pod = do_slow_pod_rendering();
2221 # cache the result for 12 hours
2222 $c->cache->set( "$file $mtime", $cached_pod, '12h' );
2223 }
2224 $c->stash->{pod} = $cached_pod;
2225 }
b1a08fe1 2226
cb93c9d7 2227We could actually cache the result forever, but using a value such as 12 hours
2228allows old entries to be automatically expired when they are no longer needed.
2229
2230=head3 Page Caching
2231
2232Another method of caching is to cache the entire HTML page. While this is
2233traditionally handled by a front-end proxy server like Squid, the Catalyst
2234PageCache plugin makes it trivial to cache the entire output from
2235frequently-used or slow actions.
2236
2237Many sites have a busy content-filled front page that might look something
2238like this. It probably takes a while to process, and will do the exact same
2239thing for every single user who views the page.
2240
2241 sub front_page : Path('/') {
2242 my ( $self, $c ) = @_;
b1a08fe1 2243
cb93c9d7 2244 $c->forward( 'get_news_articles' );
2245 $c->forward( 'build_lots_of_boxes' );
2246 $c->forward( 'more_slow_stuff' );
b1a08fe1 2247
cb93c9d7 2248 $c->stash->{template} = 'index.tt';
2249 }
2250
2251We can add the PageCache plugin to speed things up.
2252
b411df01 2253 use Catalyst qw/Cache::FileCache PageCache/;
b1a08fe1 2254
cb93c9d7 2255 sub front_page : Path ('/') {
2256 my ( $self, $c ) = @_;
b1a08fe1 2257
cb93c9d7 2258 $c->cache_page( 300 );
b1a08fe1 2259
cb93c9d7 2260 # same processing as above
2261 }
b1a08fe1 2262
cb93c9d7 2263Now the entire output of the front page, from <html> to </html>, will be
2264cached for 5 minutes. After 5 minutes, the next request will rebuild the
2265page and it will be re-cached.
2266
2267Note that the page cache is keyed on the page URI plus all parameters, so
2268requests for / and /?foo=bar will result in different cache items. Also,
2269only GET requests will be cached by the plugin.
2270
2271You can even get that front-end Squid proxy to help out by enabling HTTP
2272headers for the cached page.
2273
2274 MyApp->config->{page_cache}->{set_http_headers} = 1;
b1a08fe1 2275
cb93c9d7 2276This would now set the following headers so proxies and browsers may cache
2277the content themselves.
2278
2279 Cache-Control: max-age=($expire_time - time)
2280 Expires: $expire_time
2281 Last-Modified: $cache_created_time
b1a08fe1 2282
cb93c9d7 2283=head3 Template Caching
2284
2285Template Toolkit provides support for caching compiled versions of your
2286templates. To enable this in Catalyst, use the following configuration.
2287TT will cache compiled templates keyed on the file mtime, so changes will
2288still be automatically detected.
2289
2290 package MyApp::View::TT;
b1a08fe1 2291
cb93c9d7 2292 use strict;
2293 use warnings;
2294 use base 'Catalyst::View::TT';
b1a08fe1 2295
cb93c9d7 2296 __PACKAGE__->config(
2297 COMPILE_DIR => '/tmp/template_cache',
2298 );
b1a08fe1 2299
cb93c9d7 2300 1;
b1a08fe1 2301
cb93c9d7 2302=head3 More Info
2303
2304See the documentation for each cache plugin for more details and other
2305available configuration options.
2306
2307L<Catalyst::Plugin::Cache::FastMmap>
2308L<Catalyst::Plugin::Cache::FileCache>
2309L<Catalyst::Plugin::Cache::Memcached>
2310L<Catalyst::Plugin::PageCache>
2311L<http://search.cpan.org/dist/Template-Toolkit/lib/Template/Manual/Config.pod#Caching_and_Compiling_Options>
2312
2313=head1 Testing
2314
2315Testing is an integral part of the web application development
2316process. Tests make multi developer teams easier to coordinate, and
2317they help ensure that there are no nasty surprises after upgrades or
2318alterations.
2319
2320=head2 Testing
2321
b1a08fe1 2322Catalyst provides a convenient way of testing your application during
cb93c9d7 2323development and before deployment in a real environment.
2324
b1a08fe1 2325C<Catalyst::Test> makes it possible to run the same tests both locally
cb93c9d7 2326(without an external daemon) and against a remote server via HTTP.
2327
2328=head3 Tests
2329
2330Let's examine a skeleton application's C<t/> directory:
2331
2332 mundus:~/MyApp chansen$ ls -l t/
2333 total 24
2334 -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t
2335 -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t
2336 -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t
2337
2338=over 4
2339
2340=item C<01app.t>
2341
2342Verifies that the application loads, compiles, and returns a successful
2343response.
2344
2345=item C<02pod.t>
2346
b1a08fe1 2347Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
cb93c9d7 2348environment variable is true.
2349
2350=item C<03podcoverage.t>
2351
2352Verifies that all methods/functions have POD coverage. Only executed if the
2353C<TEST_POD> environment variable is true.
2354
2355=back
2356
2357=head3 Creating tests
2358
2359 mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )'
2360 1 use Test::More tests => 2;
e5415384 2361 2 BEGIN { use_ok( Catalyst::Test, 'MyApp' ) }
cb93c9d7 2362 3
2363 4 ok( request('/')->is_success );
2364
2365The first line declares how many tests we are going to run, in this case
2366two. The second line tests and loads our application in test mode. The
2367fourth line verifies that our application returns a successful response.
2368
2369C<Catalyst::Test> exports two functions, C<request> and C<get>. Each can
2370take three different arguments:
2371
2372=over 4
2373
2374=item A string which is a relative or absolute URI.
2375
2376 request('/my/path');
2377 request('http://www.host.com/my/path');
2378
2379=item An instance of C<URI>.
2380
2381 request( URI->new('http://www.host.com/my/path') );
2382
2383=item An instance of C<HTTP::Request>.
2384
2385 request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
2386
2387=back
2388
b1a08fe1 2389C<request> returns an instance of C<HTTP::Response> and C<get> returns the
cb93c9d7 2390content (body) of the response.
2391
2392=head3 Running tests locally
2393
2394 mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
b1a08fe1 2395 t/01app............ok
2396 t/02pod............ok
2397 t/03podcoverage....ok
cb93c9d7 2398 All tests successful.
2399 Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
b1a08fe1 2400
cb93c9d7 2401C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
2402will see debug logs between tests.
2403
2404C<TEST_POD=1> enables POD checking and coverage.
2405
2406C<prove> A command-line tool that makes it easy to run tests. You can
2407find out more about it from the links below.
2408
2409=head3 Running tests remotely
2410
2411 mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
b1a08fe1 2412 t/01app....ok
cb93c9d7 2413 All tests successful.
2414 Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
2415
b1a08fe1 2416C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
2417your application. In C<CGI> or C<FastCGI> it should be the host and path
cb93c9d7 2418to the script.
2419
2420=head3 C<Test::WWW::Mechanize> and Catalyst
2421
2422Be sure to check out C<Test::WWW::Mechanize::Catalyst>. It makes it easy to
2423test HTML, forms and links. A short example of usage:
2424
2425 use Test::More tests => 6;
e5415384 2426 BEGIN { use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' ) }
cb93c9d7 2427
2428 my $mech = Test::WWW::Mechanize::Catalyst->new;
2429 $mech->get_ok("http://localhost/", 'Got index page');
2430 $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
2431 ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
2432 ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
2433 ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
2434
2435=head3 Further Reading
2436
2437=over 4
2438
2439=item Catalyst::Test
2440
e5415384 2441L<Catalyst::Test>
cb93c9d7 2442
2443=item Test::WWW::Mechanize::Catalyst
2444
2445L<http://search.cpan.org/dist/Test-WWW-Mechanize-Catalyst/lib/Test/WWW/Mechanize/Catalyst.pm>
2446
2447=item Test::WWW::Mechanize
2448
2449L<http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm>
2450
2451=item WWW::Mechanize
2452
2453L<http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm>
2454
2455=item LWP::UserAgent
2456
2457L<http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm>
2458
2459=item HTML::Form
2460
2461L<http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm>
2462
2463=item HTTP::Message
2464
2465L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm>
2466
2467=item HTTP::Request
2468
2469L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm>
2470
2471=item HTTP::Request::Common
2472
2473L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request/Common.pm>
2474
2475=item HTTP::Response
2476
2477L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm>
2478
2479=item HTTP::Status
2480
2481L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm>
2482
2483=item URI
2484
2485L<http://search.cpan.org/dist/URI/URI.pm>
2486
2487=item Test::More
2488
2489L<http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm>
2490
2491=item Test::Pod
2492
2493L<http://search.cpan.org/dist/Test-Pod/Pod.pm>
2494
2495=item Test::Pod::Coverage
2496
2497L<http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm>
2498
2499=item prove (Test::Harness)
2500
2501L<http://search.cpan.org/dist/Test-Harness/bin/prove>
2502
2503=back
2504
2505=head3 More Information
2506
2507L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::Roles>
2508L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::ACL>
2509
2510=head1 AUTHORS
2511
bbddff00 2512Catalyst Contributors, see Catalyst.pm
cb93c9d7 2513
2514=head1 COPYRIGHT
2515
bbddff00 2516This library is free software. You can redistribute it and/or modify it under
2517the same terms as Perl itself.
cb93c9d7 2518
bbddff00 2519=cut