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