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