added documentation reminder to install FCGI.pm when deploying to fastcgi
[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 },
31e9c5ef 376 },
bbddff00 377 );
378
379 package MyApp::Controller::Root;
380 use Moose;
381 use namespace::autoclean;
31e9c5ef 382
bbddff00 383 BEGIN { extends 'Catalyst::Controller' }
31e9c5ef 384
bbddff00 385 __PACKAGE__->config(namespace => '');
31e9c5ef 386
bbddff00 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,
31e9c5ef 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
7cfce6e1 1302=head3 Flowchart
cb93c9d7 1303
7cfce6e1 1304A graphical flowchart of how the dispatcher works can be found on the wiki at
1305L<http://dev.catalyst.perl.org/attachment/wiki/WikiStart/catalyst-flow.png>.
cb93c9d7 1306
7cfce6e1 1307=head2 DRY Controllers with Chained actions
6daaedc0 1308
1309Imagine that you would like the following paths in your application:
1310
1311=over
1312
1b4425c5 1313=item B<< /cd/<ID>/track/<ID> >>
6daaedc0 1314
1315Displays info on a particular track.
b1a08fe1 1316
6daaedc0 1317In the case of a multi-volume CD, this is the track sequence.
1318
1b4425c5 1319=item B<< /cd/<ID>/volume/<ID>/track/<ID> >>
6daaedc0 1320
1321Displays info on a track on a specific volume.
1322
1323=back
1324
1325Here is some example code, showing how to do this with chained controllers:
1326
1327 package CD::Controller;
1328 use base qw/Catalyst::Controller/;
b1a08fe1 1329
6daaedc0 1330 sub root : Chained('/') PathPart('/cd') CaptureArgs(1) {
1331 my ($self, $c, $cd_id) = @_;
1332 $c->stash->{cd_id} = $cd_id;
1333 $c->stash->{cd} = $self->model('CD')->find_by_id($cd_id);
1334 }
b1a08fe1 1335
6daaedc0 1336 sub trackinfo : Chained('track') PathPart('') Args(0) RenderView {
1337 my ($self, $c) = @_;
1338 }
b1a08fe1 1339
6daaedc0 1340 package CD::Controller::ByTrackSeq;
1341 use base qw/CD::Controller/;
b1a08fe1 1342
6daaedc0 1343 sub track : Chained('root') PathPart('track') CaptureArgs(1) {
1344 my ($self, $c, $track_seq) = @_;
1345 $c->stash->{track} = $self->stash->{cd}->find_track_by_seq($track_seq);
1346 }
b1a08fe1 1347
6daaedc0 1348 package CD::Controller::ByTrackVolNo;
1349 use base qw/CD::Controller/;
b1a08fe1 1350
6daaedc0 1351 sub volume : Chained('root') PathPart('volume') CaptureArgs(1) {
1352 my ($self, $c, $volume) = @_;
1353 $c->stash->{volume} = $volume;
1354 }
b1a08fe1 1355
6daaedc0 1356 sub track : Chained('volume') PathPart('track') CaptureArgs(1) {
1357 my ($self, $c, $track_no) = @_;
1358 $c->stash->{track} = $self->stash->{cd}->find_track_by_vol_and_track_no(
1359 $c->stash->{volume}, $track_no
1360 );
1361 }
b1a08fe1 1362
1363Note that adding other actions (i.e. chain endpoints) which operate on a track
6daaedc0 1364is simply a matter of adding a new sub to CD::Controller - no code is duplicated,
1365even though there are two different methods of looking up a track.
1366
1367This technique can be expanded as needed to fulfil your requirements - for example,
1368if you inherit the first action of a chain from a base class, then mixing in a
1369different base class can be used to duplicate an entire URL hieratchy at a different
1370point within your application.
1371
cb93c9d7 1372=head2 Component-based Subrequests
1373
1374See L<Catalyst::Plugin::SubRequest>.
1375
1376=head2 File uploads
1377
1378=head3 Single file upload with Catalyst
1379
1380To implement uploads in Catalyst, you need to have a HTML form similar to
1381this:
1382
1383 <form action="/upload" method="post" enctype="multipart/form-data">
1384 <input type="hidden" name="form_submit" value="yes">
1385 <input type="file" name="my_file">
1386 <input type="submit" value="Send">
1387 </form>
1388
1389It's very important not to forget C<enctype="multipart/form-data"> in
1390the form.
1391
1392Catalyst Controller module 'upload' action:
1393
1394 sub upload : Global {
1395 my ($self, $c) = @_;
1396
1397 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1398
1399 if ( my $upload = $c->request->upload('my_file') ) {
1400
1401 my $filename = $upload->filename;
1402 my $target = "/tmp/upload/$filename";
1403
1404 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1405 die( "Failed to copy '$filename' to '$target': $!" );
1406 }
1407 }
1408 }
1409
1410 $c->stash->{template} = 'file_upload.html';
1411 }
1412
1413=head3 Multiple file upload with Catalyst
1414
1415Code for uploading multiple files from one form needs a few changes:
1416
1417The form should have this basic structure:
1418
1419 <form action="/upload" method="post" enctype="multipart/form-data">
1420 <input type="hidden" name="form_submit" value="yes">
1421 <input type="file" name="file1" size="50"><br>
1422 <input type="file" name="file2" size="50"><br>
1423 <input type="file" name="file3" size="50"><br>
1424 <input type="submit" value="Send">
1425 </form>
1426
1427And in the controller:
1428
1429 sub upload : Local {
1430 my ($self, $c) = @_;
1431
1432 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1433
1434 for my $field ( $c->req->upload ) {
1435
1436 my $upload = $c->req->upload($field);
1437 my $filename = $upload->filename;
1438 my $target = "/tmp/upload/$filename";
1439
1440 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1441 die( "Failed to copy '$filename' to '$target': $!" );
1442 }
1443 }
1444 }
1445
1446 $c->stash->{template} = 'file_upload.html';
1447 }
1448
1449C<for my $field ($c-E<gt>req->upload)> loops automatically over all file
1450input fields and gets input names. After that is basic file saving code,
1451just like in single file upload.
1452
1453Notice: C<die>ing might not be what you want to do, when an error
1454occurs, but it works as an example. A better idea would be to store
1455error C<$!> in $c->stash->{error} and show a custom error template
1456displaying this message.
1457
1458For more information about uploads and usable methods look at
1459L<Catalyst::Request::Upload> and L<Catalyst::Request>.
1460
1461=head2 Forwarding with arguments
1462
1463Sometimes you want to pass along arguments when forwarding to another
1464action. As of version 5.30, arguments can be passed in the call to
1465C<forward>; in earlier versions, you can manually set the arguments in
1466the Catalyst Request object:
1467
1468 # version 5.30 and later:
1469 $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
1470
1471 # pre-5.30
1472 $c->req->args([qw/arg1 arg2 arg3/]);
1473 $c->forward('/wherever');
1474
b1a08fe1 1475(See the L<Catalyst::Manual::Intro> Flow_Control section for more
cb93c9d7 1476information on passing arguments via C<forward>.)
1477
6daaedc0 1478=head2 Chained dispatch using base classes, and inner packages.
1479
1480 package MyApp::Controller::Base;
1481 use base qw/Catalyst::Controller/;
1482
b1a08fe1 1483 sub key1 : Chained('/')
31e9c5ef 1484
e2728084 1485=head2 Extending RenderView (formerly DefaultEnd)
1486
1487The recommended approach for an C<end> action is to use
1488L<Catalyst::Action::RenderView> (taking the place of
1489L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
1490However there are times when you need to add a bit to it, but don't want
1491to write your own C<end> action.
1492
1493You can extend it like this:
1494
1495To add something to an C<end> action that is called before rendering
1496(this is likely to be what you want), simply place it in the C<end>
1497method:
1498
1499 sub end : ActionClass('RenderView') {
1500 my ( $self, $c ) = @_;
1501 # do stuff here; the RenderView action is called afterwards
1502 }
1503
1504To add things to an C<end> action that are called I<after> rendering,
1505you can set it up like this:
1506
1507 sub render : ActionClass('RenderView') { }
1508
1509 sub end : Private {
1510 my ( $self, $c ) = @_;
1511 $c->forward('render');
1512 # do stuff here
1513 }
1514
31e9c5ef 1515
cb93c9d7 1516
1517=head1 Deployment
1518
1519The recipes below describe aspects of the deployment process,
1520including web server engines and tips to improve application efficiency.
1521
1522=head2 mod_perl Deployment
1523
1524mod_perl is the best solution for many applications, but we'll list some pros
1525and cons so you can decide for yourself. The other production deployment
1526option is FastCGI, for which see below.
1527
1528=head3 Pros
1529
1530=head4 Speed
1531
1532mod_perl is very fast and your app will benefit from being loaded in memory
1533within each Apache process.
1534
1535=head4 Shared memory for multiple apps
1536
1537If you need to run several Catalyst apps on the same server, mod_perl will
1538share the memory for common modules.
1539
1540=head3 Cons
1541
1542=head4 Memory usage
1543
1544Since your application is fully loaded in memory, every Apache process will
1545be rather large. This means a large Apache process will be tied up while
1546serving static files, large files, or dealing with slow clients. For this
1547reason, it is best to run a two-tiered web architecture with a lightweight
1548frontend server passing dynamic requests to a large backend mod_perl
1549server.
1550
1551=head4 Reloading
1552
1553Any changes made to the core code of your app require a full Apache restart.
1554Catalyst does not support Apache::Reload or StatINC. This is another good
1555reason to run a frontend web server where you can set up an
1556C<ErrorDocument 502> page to report that your app is down for maintenance.
1557
1558=head4 Cannot run multiple versions of the same app
1559
1560It is not possible to run two different versions of the same application in
1561the same Apache instance because the namespaces will collide.
1562
1563=head4 Setup
1564
1565Now that we have that out of the way, let's talk about setting up mod_perl
1566to run a Catalyst app.
1567
1568=head4 1. Install Catalyst::Engine::Apache
1569
b1a08fe1 1570You should install the latest versions of both Catalyst and
cb93c9d7 1571Catalyst::Engine::Apache. The Apache engines were separated from the
1572Catalyst core in version 5.50 to allow for updates to the engine without
1573requiring a new Catalyst release.
1574
1575=head4 2. Install Apache with mod_perl
1576
1577Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly
1578recommended. With Apache 2, make sure you are using the prefork MPM and not
1579the worker MPM. The reason for this is that many Perl modules are not
1580thread-safe and may have problems running within the threaded worker
1581environment. Catalyst is thread-safe however, so if you know what you're
1582doing, you may be able to run using worker.
1583
1584In Debian, the following commands should get you going.
1585
1586 apt-get install apache2-mpm-prefork
1587 apt-get install libapache2-mod-perl2
1588
1589=head4 3. Configure your application
1590
1591Every Catalyst application will automagically become a mod_perl handler
1592when run within mod_perl. This makes the configuration extremely easy.
1593Here is a basic Apache 2 configuration.
1594
1595 PerlSwitches -I/var/www/MyApp/lib
1596 PerlModule MyApp
b1a08fe1 1597
cb93c9d7 1598 <Location />
1599 SetHandler modperl
1600 PerlResponseHandler MyApp
1601 </Location>
1602
1603The most important line here is C<PerlModule MyApp>. This causes mod_perl
1604to preload your entire application into shared memory, including all of your
1605controller, model, and view classes and configuration. If you have -Debug
1606mode enabled, you will see the startup output scroll by when you first
1607start Apache.
1608
1609For an example Apache 1.3 configuration, please see the documentation for
1610L<Catalyst::Engine::Apache::MP13>.
1611
1612=head3 Test It
1613
1614That's it, your app is now a full-fledged mod_perl application! Try it out
1615by going to http://your.server.com/.
1616
1617=head3 Other Options
1618
1619=head4 Non-root location
1620
1621You may not always want to run your app at the root of your server or virtual
1622host. In this case, it's a simple change to run at any non-root location
1623of your choice.
1624
1625 <Location /myapp>
1626 SetHandler modperl
1627 PerlResponseHandler MyApp
1628 </Location>
b1a08fe1 1629
cb93c9d7 1630When running this way, it is best to make use of the C<uri_for> method in
1631Catalyst for constructing correct links.
1632
1633=head4 Static file handling
1634
1635Static files can be served directly by Apache for a performance boost.
1636
1637 DocumentRoot /var/www/MyApp/root
1638 <Location /static>
1639 SetHandler default-handler
1640 </Location>
b1a08fe1 1641
cb93c9d7 1642This will let all files within root/static be handled directly by Apache. In
1643a two-tiered setup, the frontend server should handle static files.
1644The configuration to do this on the frontend will vary.
1645
3cca8359 1646The same is accomplished in lighttpd with the following snippet:
1647
1648 $HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" {
1649 fastcgi.server = (
1650 "" => (
1651 "MyApp" => (
1652 "socket" => "/tmp/myapp.socket",
1653 "check-local" => "disable",
1654 )
1655 )
1656 )
1657 }
1658
1659Which serves everything in the img, static, css directories
1660statically, as well as the favicon file.
1661
c1c35b01 1662Note the path of the application needs to be stated explicitly in the
1663web server configuration for both these recipes.
3cca8359 1664
cb93c9d7 1665=head2 Catalyst on shared hosting
1666
1667So, you want to put your Catalyst app out there for the whole world to
1668see, but you don't want to break the bank. There is an answer - if you
1669can get shared hosting with FastCGI and a shell, you can install your
1670Catalyst app in a local directory on your shared host. First, run
1671
1672 perl -MCPAN -e shell
1673
1674and go through the standard CPAN configuration process. Then exit out
1675without installing anything. Next, open your .bashrc and add
1676
1677 export PATH=$HOME/local/bin:$HOME/local/script:$PATH
1678 perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'`
1679 export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB
1680
1681and log out, then back in again (or run C<". .bashrc"> if you
1682prefer). Finally, edit C<.cpan/CPAN/MyConfig.pm> and add
1683
1684 'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local],
1685 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local],
1686
1687Now you can install the modules you need using CPAN as normal; they
1688will be installed into your local directory, and perl will pick them
1689up. Finally, change directory into the root of your virtual host and
1690symlink your application's script directory in:
1691
1692 cd path/to/mydomain.com
1693 ln -s ~/lib/MyApp/script script
1694
1695And add the following lines to your .htaccess file (assuming the server
1696is setup to handle .pl as fcgi - you may need to rename the script to
1697myapp_fastcgi.fcgi and/or use a SetHandler directive):
1698
1699 RewriteEngine On
1700 RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl
1701 RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
1702
1703Now C<http://mydomain.com/> should now Just Work. Congratulations, now
1704you can tell your friends about your new website (or in our case, tell
1705the client it's time to pay the invoice :) )
1706
1707=head2 FastCGI Deployment
1708
1709FastCGI is a high-performance extension to CGI. It is suitable
1710for production environments.
1711
1712=head3 Pros
1713
1714=head4 Speed
1715
1716FastCGI performs equally as well as mod_perl. Don't let the 'CGI' fool you;
1717your app runs as multiple persistent processes ready to receive connections
1718from the web server.
1719
1720=head4 App Server
1721
1722When using external FastCGI servers, your application runs as a standalone
1723application server. It may be restarted independently from the web server.
1724This allows for a more robust environment and faster reload times when
1725pushing new app changes. The frontend server can even be configured to
1726display a friendly "down for maintenance" page while the application is
1727restarting.
1728
1729=head4 Load-balancing
1730
1731You can launch your application on multiple backend servers and allow the
1732frontend web server to load-balance between all of them. And of course, if
1733one goes down, your app continues to run fine.
1734
1735=head4 Multiple versions of the same app
1736
1737Each FastCGI application is a separate process, so you can run different
1738versions of the same app on a single server.
1739
1740=head4 Can run with threaded Apache
1741
1742Since your app is not running inside of Apache, the faster mpm_worker module
1743can be used without worrying about the thread safety of your application.
1744
1745=head3 Cons
1746
278f816d 1747You may have to disable mod_deflate. If you experience page hangs with
1748mod_fastcgi then remove deflate.load and deflate.conf from mods-enabled/
1749
cb93c9d7 1750=head4 More complex environment
1751
1752With FastCGI, there are more things to monitor and more processes running
1753than when using mod_perl.
1754
1755=head3 Setup
1756
1757=head4 1. Install Apache with mod_fastcgi
1758
1759mod_fastcgi for Apache is a third party module, and can be found at
1760L<http://www.fastcgi.com/>. It is also packaged in many distributions,
31e9c5ef 1761for example, libapache2-mod-fastcgi in Debian. You will also need to install
1762the L<FCGI> module from cpan.
cb93c9d7 1763
b1d4f0ad 1764Important Note! If you experience difficulty properly rendering pages,
1765try disabling Apache's mod_deflate (Deflate Module), e.g. 'a2dismod deflate'.
1766
cb93c9d7 1767=head4 2. Configure your application
1768
1769 # Serve static content directly
1770 DocumentRoot /var/www/MyApp/root
1771 Alias /static /var/www/MyApp/root/static
1772
1773 FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3
1774 Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/
b1a08fe1 1775
cb93c9d7 1776 # Or, run at the root
1777 Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
b1a08fe1 1778
cb93c9d7 1779The above commands will launch 3 app processes and make the app available at
1780/myapp/
1781
1782=head3 Standalone server mode
1783
1784While not as easy as the previous method, running your app as an external
1785server gives you much more flexibility.
1786
1787First, launch your app as a standalone server listening on a socket.
1788
1789 script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
b1a08fe1 1790
cb93c9d7 1791You can also listen on a TCP port if your web server is not on the same
1792machine.
1793
1794 script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
b1a08fe1 1795
cb93c9d7 1796You will probably want to write an init script to handle starting/stopping
1797of the app using the pid file.
1798
1799Now, we simply configure Apache to connect to the running server.
1800
1801 # 502 is a Bad Gateway error, and will occur if the backend server is down
1802 # This allows us to display a friendly static page that says "down for
1803 # maintenance"
1804 Alias /_errors /var/www/MyApp/root/error-pages
1805 ErrorDocument 502 /_errors/502.html
1806
31bdf270 1807 FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
1808 Alias /myapp/ /tmp/myapp.fcgi/
b1a08fe1 1809
cb93c9d7 1810 # Or, run at the root
31bdf270 1811 Alias / /tmp/myapp.fcgi/
b1a08fe1 1812
cb93c9d7 1813=head3 More Info
1814
1815L<Catalyst::Engine::FastCGI>.
1816
1817=head2 Development server deployment
1818
1819The development server is a mini web server written in perl. If you
1820expect a low number of hits or you don't need mod_perl/FastCGI speed,
1821you could use the development server as the application server with a
ad2a47ab 1822lightweight proxy web server at the front. However, consider using
816fc503 1823L<Catalyst::Engine::HTTP::Prefork> for this kind of deployment instead, since
ad2a47ab 1824it can better handle multiple concurrent requests without forking, or can
1825prefork a set number of servers for improved performance.
cb93c9d7 1826
1827=head3 Pros
1828
1829As this is an application server setup, the pros are the same as
1830FastCGI (with the exception of speed).
1831It is also:
1832
1833=head4 Simple
1834
1835The development server is what you create your code on, so if it works
1836here, it should work in production!
1837
1838=head3 Cons
1839
1840=head4 Speed
1841
1842Not as fast as mod_perl or FastCGI. Needs to fork for each request
1843that comes in - make sure static files are served by the web server to
1844save forking.
1845
1846=head3 Setup
1847
1848=head4 Start up the development server
1849
ad2a47ab 1850 script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid
cb93c9d7 1851
1852You will probably want to write an init script to handle stop/starting
1853the app using the pid file.
1854
1855=head4 Configuring Apache
1856
1857Make sure mod_proxy is enabled and add:
1858
1859 # Serve static content directly
1860 DocumentRoot /var/www/MyApp/root
1861 Alias /static /var/www/MyApp/root/static
1862
1863 ProxyRequests Off
1864 <Proxy *>
1865 Order deny,allow
1866 Allow from all
1867 </Proxy>
816fc503 1868
1869 # Need to specifically stop these paths from being passed to proxy
1870 ProxyPass /static !
1871 ProxyPass /favicon.ico !
1872
cb93c9d7 1873 ProxyPass / http://localhost:8080/
1874 ProxyPassReverse / http://localhost:8080/
1875
b1a08fe1 1876 # This is optional if you'd like to show a custom error page
816fc503 1877 # if the proxy is not available
1878 ErrorDocument 502 /static/error_pages/http502.html
1879
cb93c9d7 1880You can wrap the above within a VirtualHost container if you want
1881different apps served on the same host.
1882
1883=head2 Quick deployment: Building PAR Packages
1884
1885You have an application running on your development box, but then you
1886have to quickly move it to another one for
1887demonstration/deployment/testing...
1888
1889PAR packages can save you from a lot of trouble here. They are usual Zip
1890files that contain a blib tree; you can even include all prereqs and a
1891perl interpreter by setting a few flags!
1892
1893=head3 Follow these few points to try it out!
1894
18951. Install Catalyst and PAR 0.89 (or later)
1896
1897 % perl -MCPAN -e 'install Catalyst'
1898 ...
1899 % perl -MCPAN -e 'install PAR'
1900 ...
1901
19022. Create a application
1903
1904 % catalyst.pl MyApp
1905 ...
1906 % cd MyApp
1907
1908Recent versions of Catalyst (5.62 and up) include
1909L<Module::Install::Catalyst>, which simplifies the process greatly. From the shell in your application directory:
1910
1911 % perl Makefile.PL
1912 % make catalyst_par
1913
b1a08fe1 1914You can customise the PAR creation process by special "catalyst_par_*" commands
1915available from L<Module::Install::Catalyst>. You can add these commands in your
3f3d414b 1916Makefile.PL just before the line containing "catalyst;"
1917
b1a08fe1 1918 #Makefile.PL example with extra PAR options
3f3d414b 1919 use inc::Module::Install;
1920
1921 name 'MyApp';
1922 all_from 'lib\MyApp.pm';
1923
1924 requires 'Catalyst::Runtime' => '5.80005';
1925 <snip>
1926 ...
1927 <snip>
1928
1929 catalyst_par_core(1); # bundle perl core modules in the resulting PAR
1930 catalyst_par_multiarch(1); # build a multi-architecture PAR file
1931 catalyst_par_classes(qw/
1932 Some::Additional::Module
1933 Some::Other::Module
1934 /); # specify additional modules you want to be included into PAR
1935 catalyst;
1936
1937 install_script glob('script/*.pl');
1938 auto_install;
1939 WriteAll;
1940
cb93c9d7 1941Congratulations! Your package "myapp.par" is ready, the following
1942steps are just optional.
1943
19443. Test your PAR package with "parl" (no typo)
1945
1946 % parl myapp.par
1947 Usage:
1948 [parl] myapp[.par] [script] [arguments]
1949
1950 Examples:
1951 parl myapp.par myapp_server.pl -r
1952 myapp myapp_cgi.pl
1953
1954 Available scripts:
1955 myapp_cgi.pl
1956 myapp_create.pl
1957 myapp_fastcgi.pl
1958 myapp_server.pl
1959 myapp_test.pl
1960
1961 % parl myapp.par myapp_server.pl
1962 You can connect to your server at http://localhost:3000
1963
1964Yes, this nifty little starter application gets automatically included.
1965You can also use "catalyst_par_script('myapp_server.pl')" to set a
1966default script to execute.
1967
19686. Want to create a binary that includes the Perl interpreter?
1969
1970 % pp -o myapp myapp.par
1971 % ./myapp myapp_server.pl
1972 You can connect to your server at http://localhost:3000
1973
1974=head2 Serving static content
1975
1976Serving static content in Catalyst used to be somewhat tricky; the use
1977of L<Catalyst::Plugin::Static::Simple> makes everything much easier.
1978This plugin will automatically serve your static content during development,
1979but allows you to easily switch to Apache (or other server) in a
1980production environment.
1981
1982=head3 Introduction to Static::Simple
1983
1984Static::Simple is a plugin that will help to serve static content for your
1985application. By default, it will serve most types of files, excluding some
1986standard Template Toolkit extensions, out of your B<root> file directory. All
1987files are served by path, so if B<images/me.jpg> is requested, then
1988B<root/images/me.jpg> is found and served.
1989
1990=head3 Usage
1991
1992Using the plugin is as simple as setting your use line in MyApp.pm to include:
1993
b411df01 1994 use Catalyst qw/Static::Simple/;
cb93c9d7 1995
1996and already files will be served.
1997
1998=head3 Configuring
1999
2000Static content is best served from a single directory within your root
2001directory. Having many different directories such as C<root/css> and
2002C<root/images> requires more code to manage, because you must separately
2003identify each static directory--if you decide to add a C<root/js>
2004directory, you'll need to change your code to account for it. In
2005contrast, keeping all static directories as subdirectories of a main
2006C<root/static> directory makes things much easier to manage. Here's an
2007example of a typical root directory structure:
2008
2009 root/
2010 root/content.tt
2011 root/controller/stuff.tt
2012 root/header.tt
2013 root/static/
2014 root/static/css/main.css
2015 root/static/images/logo.jpg
2016 root/static/js/code.js
2017
2018
2019All static content lives under C<root/static>, with everything else being
2020Template Toolkit files.
2021
2022=over 4
2023
2024=item Include Path
2025
2026You may of course want to change the default locations, and make
2027Static::Simple look somewhere else, this is as easy as:
2028
2029 MyApp->config->{static}->{include_path} = [
2030 MyApp->config->{root},
b1a08fe1 2031 '/path/to/my/files'
cb93c9d7 2032 ];
2033
2034When you override include_path, it will not automatically append the
2035normal root path, so you need to add it yourself if you still want
2036it. These will be searched in order given, and the first matching file
2037served.
2038
2039=item Static directories
2040
2041If you want to force some directories to be only static, you can set
2042them using paths relative to the root dir, or regular expressions:
2043
2044 MyApp->config->{static}->{dirs} = [
2045 'static',
2046 qr/^(images|css)/,
2047 ];
2048
2049=item File extensions
2050
2051By default, the following extensions are not served (that is, they will
2052be processed by Catalyst): B<tmpl, tt, tt2, html, xhtml>. This list can
2053be replaced easily:
2054
2055 MyApp->config->{static}->{ignore_extensions} = [
b1a08fe1 2056 qw/tmpl tt tt2 html xhtml/
cb93c9d7 2057 ];
2058
2059=item Ignoring directories
2060
2061Entire directories can be ignored. If used with include_path,
2062directories relative to the include_path dirs will also be ignored:
2063
2064 MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
2065
2066=back
2067
2068=head3 More information
2069
2070L<http://search.cpan.org/dist/Catalyst-Plugin-Static-Simple/>
2071
2072=head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
2073
2074In some situations you might want to control things more directly,
2075using L<Catalyst::Plugin::Static>.
2076
2077In your main application class (MyApp.pm), load the plugin:
2078
b411df01 2079 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
cb93c9d7 2080
2081You will also need to make sure your end method does I<not> forward
2082static content to the view, perhaps like this:
2083
2084 sub end : Private {
2085 my ( $self, $c ) = @_;
2086
b1a08fe1 2087 $c->forward( 'MyApp::View::TT' )
cb93c9d7 2088 unless ( $c->res->body || !$c->stash->{template} );
2089 }
2090
2091This code will only forward to the view if a template has been
2092previously defined by a controller and if there is not already data in
2093C<$c-E<gt>res-E<gt>body>.
2094
2095Next, create a controller to handle requests for the /static path. Use
2096the Helper to save time. This command will create a stub controller as
2097C<lib/MyApp/Controller/Static.pm>.
2098
2099 $ script/myapp_create.pl controller Static
2100
2101Edit the file and add the following methods:
2102
2103 # serve all files under /static as static files
2104 sub default : Path('/static') {
2105 my ( $self, $c ) = @_;
2106
2107 # Optional, allow the browser to cache the content
2108 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
2109
2110 $c->serve_static; # from Catalyst::Plugin::Static
2111 }
2112
2113 # also handle requests for /favicon.ico
2114 sub favicon : Path('/favicon.ico') {
2115 my ( $self, $c ) = @_;
2116
2117 $c->serve_static;
2118 }
2119
2120You can also define a different icon for the browser to use instead of
2121favicon.ico by using this in your HTML header:
2122
2123 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
2124
2125=head3 Common problems with the Static plugin
2126
2127The Static plugin makes use of the C<shared-mime-info> package to
2128automatically determine MIME types. This package is notoriously
2129difficult to install, especially on win32 and OS X. For OS X the easiest
2130path might be to install Fink, then use C<apt-get install
2131shared-mime-info>. Restart the server, and everything should be fine.
2132
2133Make sure you are using the latest version (>= 0.16) for best
2134results. If you are having errors serving CSS files, or if they get
2135served as text/plain instead of text/css, you may have an outdated
2136shared-mime-info version. You may also wish to simply use the following
2137code in your Static controller:
2138
2139 if ($c->req->path =~ /css$/i) {
2140 $c->serve_static( "text/css" );
2141 } else {
2142 $c->serve_static;
2143 }
2144
2145=head3 Serving Static Files with Apache
2146
2147When using Apache, you can bypass Catalyst and any Static
2148plugins/controllers controller by intercepting requests for the
2149C<root/static> path at the server level. All that is required is to
2150define a DocumentRoot and add a separate Location block for your static
2151content. Here is a complete config for this application under mod_perl
21521.x:
2153
2154 <Perl>
2155 use lib qw(/var/www/MyApp/lib);
2156 </Perl>
2157 PerlModule MyApp
2158
2159 <VirtualHost *>
2160 ServerName myapp.example.com
2161 DocumentRoot /var/www/MyApp/root
2162 <Location />
2163 SetHandler perl-script
2164 PerlHandler MyApp
2165 </Location>
2166 <LocationMatch "/(static|favicon.ico)">
2167 SetHandler default-handler
2168 </LocationMatch>
2169 </VirtualHost>
2170
2171And here's a simpler example that'll get you started:
2172
2173 Alias /static/ "/my/static/files/"
2174 <Location "/static">
2175 SetHandler none
2176 </Location>
2177
2178=head2 Caching
2179
2180Catalyst makes it easy to employ several different types of caching to
2181speed up your applications.
2182
2183=head3 Cache Plugins
2184
2185There are three wrapper plugins around common CPAN cache modules:
2186Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be
2187used to cache the result of slow operations.
2188
ca7528df 2189The Catalyst Advent Calendar uses the FileCache plugin to cache the
cb93c9d7 2190rendered XHTML version of the source POD document. This is an ideal
ca7528df 2191application for a cache because the source document changes
2192infrequently but may be viewed many times.
cb93c9d7 2193
b411df01 2194 use Catalyst qw/Cache::FileCache/;
b1a08fe1 2195
cb93c9d7 2196 ...
b1a08fe1 2197
cb93c9d7 2198 use File::stat;
2199 sub render_pod : Local {
2200 my ( self, $c ) = @_;
b1a08fe1 2201
cb93c9d7 2202 # the cache is keyed on the filename and the modification time
2203 # to check for updates to the file.
2204 my $file = $c->path_to( 'root', '2005', '11.pod' );
2205 my $mtime = ( stat $file )->mtime;
b1a08fe1 2206
cb93c9d7 2207 my $cached_pod = $c->cache->get("$file $mtime");
2208 if ( !$cached_pod ) {
2209 $cached_pod = do_slow_pod_rendering();
2210 # cache the result for 12 hours
2211 $c->cache->set( "$file $mtime", $cached_pod, '12h' );
2212 }
2213 $c->stash->{pod} = $cached_pod;
2214 }
b1a08fe1 2215
cb93c9d7 2216We could actually cache the result forever, but using a value such as 12 hours
2217allows old entries to be automatically expired when they are no longer needed.
2218
2219=head3 Page Caching
2220
2221Another method of caching is to cache the entire HTML page. While this is
2222traditionally handled by a front-end proxy server like Squid, the Catalyst
2223PageCache plugin makes it trivial to cache the entire output from
2224frequently-used or slow actions.
2225
2226Many sites have a busy content-filled front page that might look something
2227like this. It probably takes a while to process, and will do the exact same
2228thing for every single user who views the page.
2229
2230 sub front_page : Path('/') {
2231 my ( $self, $c ) = @_;
b1a08fe1 2232
cb93c9d7 2233 $c->forward( 'get_news_articles' );
2234 $c->forward( 'build_lots_of_boxes' );
2235 $c->forward( 'more_slow_stuff' );
b1a08fe1 2236
cb93c9d7 2237 $c->stash->{template} = 'index.tt';
2238 }
2239
2240We can add the PageCache plugin to speed things up.
2241
b411df01 2242 use Catalyst qw/Cache::FileCache PageCache/;
b1a08fe1 2243
cb93c9d7 2244 sub front_page : Path ('/') {
2245 my ( $self, $c ) = @_;
b1a08fe1 2246
cb93c9d7 2247 $c->cache_page( 300 );
b1a08fe1 2248
cb93c9d7 2249 # same processing as above
2250 }
b1a08fe1 2251
cb93c9d7 2252Now the entire output of the front page, from <html> to </html>, will be
2253cached for 5 minutes. After 5 minutes, the next request will rebuild the
2254page and it will be re-cached.
2255
2256Note that the page cache is keyed on the page URI plus all parameters, so
2257requests for / and /?foo=bar will result in different cache items. Also,
2258only GET requests will be cached by the plugin.
2259
2260You can even get that front-end Squid proxy to help out by enabling HTTP
2261headers for the cached page.
2262
2263 MyApp->config->{page_cache}->{set_http_headers} = 1;
b1a08fe1 2264
cb93c9d7 2265This would now set the following headers so proxies and browsers may cache
2266the content themselves.
2267
2268 Cache-Control: max-age=($expire_time - time)
2269 Expires: $expire_time
2270 Last-Modified: $cache_created_time
b1a08fe1 2271
cb93c9d7 2272=head3 Template Caching
2273
2274Template Toolkit provides support for caching compiled versions of your
2275templates. To enable this in Catalyst, use the following configuration.
2276TT will cache compiled templates keyed on the file mtime, so changes will
2277still be automatically detected.
2278
2279 package MyApp::View::TT;
b1a08fe1 2280
cb93c9d7 2281 use strict;
2282 use warnings;
2283 use base 'Catalyst::View::TT';
b1a08fe1 2284
cb93c9d7 2285 __PACKAGE__->config(
2286 COMPILE_DIR => '/tmp/template_cache',
2287 );
b1a08fe1 2288
cb93c9d7 2289 1;
b1a08fe1 2290
cb93c9d7 2291=head3 More Info
2292
2293See the documentation for each cache plugin for more details and other
2294available configuration options.
2295
2296L<Catalyst::Plugin::Cache::FastMmap>
2297L<Catalyst::Plugin::Cache::FileCache>
2298L<Catalyst::Plugin::Cache::Memcached>
2299L<Catalyst::Plugin::PageCache>
2300L<http://search.cpan.org/dist/Template-Toolkit/lib/Template/Manual/Config.pod#Caching_and_Compiling_Options>
2301
2302=head1 Testing
2303
2304Testing is an integral part of the web application development
2305process. Tests make multi developer teams easier to coordinate, and
2306they help ensure that there are no nasty surprises after upgrades or
2307alterations.
2308
2309=head2 Testing
2310
b1a08fe1 2311Catalyst provides a convenient way of testing your application during
cb93c9d7 2312development and before deployment in a real environment.
2313
b1a08fe1 2314C<Catalyst::Test> makes it possible to run the same tests both locally
cb93c9d7 2315(without an external daemon) and against a remote server via HTTP.
2316
2317=head3 Tests
2318
2319Let's examine a skeleton application's C<t/> directory:
2320
2321 mundus:~/MyApp chansen$ ls -l t/
2322 total 24
2323 -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t
2324 -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t
2325 -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t
2326
2327=over 4
2328
2329=item C<01app.t>
2330
2331Verifies that the application loads, compiles, and returns a successful
2332response.
2333
2334=item C<02pod.t>
2335
b1a08fe1 2336Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
cb93c9d7 2337environment variable is true.
2338
2339=item C<03podcoverage.t>
2340
2341Verifies that all methods/functions have POD coverage. Only executed if the
2342C<TEST_POD> environment variable is true.
2343
2344=back
2345
2346=head3 Creating tests
2347
2348 mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )'
2349 1 use Test::More tests => 2;
2350 2 use_ok( Catalyst::Test, 'MyApp' );
2351 3
2352 4 ok( request('/')->is_success );
2353
2354The first line declares how many tests we are going to run, in this case
2355two. The second line tests and loads our application in test mode. The
2356fourth line verifies that our application returns a successful response.
2357
2358C<Catalyst::Test> exports two functions, C<request> and C<get>. Each can
2359take three different arguments:
2360
2361=over 4
2362
2363=item A string which is a relative or absolute URI.
2364
2365 request('/my/path');
2366 request('http://www.host.com/my/path');
2367
2368=item An instance of C<URI>.
2369
2370 request( URI->new('http://www.host.com/my/path') );
2371
2372=item An instance of C<HTTP::Request>.
2373
2374 request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
2375
2376=back
2377
b1a08fe1 2378C<request> returns an instance of C<HTTP::Response> and C<get> returns the
cb93c9d7 2379content (body) of the response.
2380
2381=head3 Running tests locally
2382
2383 mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
b1a08fe1 2384 t/01app............ok
2385 t/02pod............ok
2386 t/03podcoverage....ok
cb93c9d7 2387 All tests successful.
2388 Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
b1a08fe1 2389
cb93c9d7 2390C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
2391will see debug logs between tests.
2392
2393C<TEST_POD=1> enables POD checking and coverage.
2394
2395C<prove> A command-line tool that makes it easy to run tests. You can
2396find out more about it from the links below.
2397
2398=head3 Running tests remotely
2399
2400 mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
b1a08fe1 2401 t/01app....ok
cb93c9d7 2402 All tests successful.
2403 Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
2404
b1a08fe1 2405C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
2406your application. In C<CGI> or C<FastCGI> it should be the host and path
cb93c9d7 2407to the script.
2408
2409=head3 C<Test::WWW::Mechanize> and Catalyst
2410
2411Be sure to check out C<Test::WWW::Mechanize::Catalyst>. It makes it easy to
2412test HTML, forms and links. A short example of usage:
2413
2414 use Test::More tests => 6;
2415 use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' );
2416
2417 my $mech = Test::WWW::Mechanize::Catalyst->new;
2418 $mech->get_ok("http://localhost/", 'Got index page');
2419 $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
2420 ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
2421 ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
2422 ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
2423
2424=head3 Further Reading
2425
2426=over 4
2427
2428=item Catalyst::Test
2429
2430L<http://search.cpan.org/dist/Catalyst/lib/Catalyst/Test.pm>
2431
2432=item Test::WWW::Mechanize::Catalyst
2433
2434L<http://search.cpan.org/dist/Test-WWW-Mechanize-Catalyst/lib/Test/WWW/Mechanize/Catalyst.pm>
2435
2436=item Test::WWW::Mechanize
2437
2438L<http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm>
2439
2440=item WWW::Mechanize
2441
2442L<http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm>
2443
2444=item LWP::UserAgent
2445
2446L<http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm>
2447
2448=item HTML::Form
2449
2450L<http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm>
2451
2452=item HTTP::Message
2453
2454L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm>
2455
2456=item HTTP::Request
2457
2458L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm>
2459
2460=item HTTP::Request::Common
2461
2462L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request/Common.pm>
2463
2464=item HTTP::Response
2465
2466L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm>
2467
2468=item HTTP::Status
2469
2470L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm>
2471
2472=item URI
2473
2474L<http://search.cpan.org/dist/URI/URI.pm>
2475
2476=item Test::More
2477
2478L<http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm>
2479
2480=item Test::Pod
2481
2482L<http://search.cpan.org/dist/Test-Pod/Pod.pm>
2483
2484=item Test::Pod::Coverage
2485
2486L<http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm>
2487
2488=item prove (Test::Harness)
2489
2490L<http://search.cpan.org/dist/Test-Harness/bin/prove>
2491
2492=back
2493
2494=head3 More Information
2495
2496L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::Roles>
2497L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::ACL>
2498
2499=head1 AUTHORS
2500
bbddff00 2501Catalyst Contributors, see Catalyst.pm
cb93c9d7 2502
2503=head1 COPYRIGHT
2504
bbddff00 2505This library is free software. You can redistribute it and/or modify it under
2506the same terms as Perl itself.
cb93c9d7 2507
bbddff00 2508=cut