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