Patch from osfameron++
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Cookbook.pod
CommitLineData
cb93c9d7 1=head1 NAME
2
3Catalyst::Manual::Cookbook - Cooking with Catalyst
4
5=head1 DESCRIPTION
6
7Yummy code like your mum used to bake!
8
9=head1 RECIPES
10
11=head1 Basics
12
c718cfb6 13These recipes cover some basic stuff that is worth knowing for
46a5f2f5 14Catalyst developers.
cb93c9d7 15
16=head2 Delivering a Custom Error Page
17
18By default, Catalyst will display its own error page whenever it
19encounters an error in your application. When running under C<-Debug>
c718cfb6 20mode, the error page is a useful screen including the error message
21and L<Data::Dump> output of the relevant parts of the C<$c> context
22object. When not in C<-Debug>, users see a simple "Please come back
23later" screen.
cb93c9d7 24
c718cfb6 25To use a custom error page, use a special C<end> method to
26short-circuit the error processing. The following is an example; you
27might want to adjust it further depending on the needs of your
28application (for example, any calls to C<fillform> will probably need
29to go into this C<end> method; see L<Catalyst::Plugin::FillInForm>).
cb93c9d7 30
31 sub end : Private {
32 my ( $self, $c ) = @_;
33
34 if ( scalar @{ $c->error } ) {
35 $c->stash->{errors} = $c->error;
36 $c->stash->{template} = 'errors.tt';
37 $c->forward('MyApp::View::TT');
38 $c->error(0);
39 }
40
41 return 1 if $c->response->status =~ /^3\d\d$/;
42 return 1 if $c->response->body;
43
44 unless ( $c->response->content_type ) {
45 $c->response->content_type('text/html; charset=utf-8');
46 }
47
48 $c->forward('MyApp::View::TT');
49 }
50
51You can manually set errors in your code to trigger this page by calling
52
53 $c->error( 'You broke me!' );
54
55=head2 Disable statistics
56
c718cfb6 57Just add this line to your application class if you don't want those
58nifty statistics in your debug messages.
cb93c9d7 59
60 sub Catalyst::Log::info { }
61
62=head2 Enable debug status in the environment
63
64Normally you enable the debugging info by adding the C<-Debug> flag to
b411df01 65your C<use Catalyst> statement . However, you can also enable it using
66environment variable, so you can (for example) get debug info without
67modifying your application scripts. Just set C<CATALYST_DEBUG> or
7c098817 68C<E<lt>MYAPPE<gt>_DEBUG> to a true value.
cb93c9d7 69
70=head2 Sessions
71
c718cfb6 72When you have your users identified, you will want to somehow remember
73that fact, to save them from having to identify themselves for every
74single page. One way to do this is to send the username and password
75parameters in every single page, but that's ugly, and won't work for
76static pages.
cb93c9d7 77
c718cfb6 78Sessions are a method of saving data related to some transaction, and
79giving the whole collection a single ID. This ID is then given to the
80user to return to us on every page they visit while logged in. The
81usual way to do this is using a browser cookie.
cb93c9d7 82
83Catalyst uses two types of plugins to represent sessions:
84
85=head3 State
86
c718cfb6 87A State module is used to keep track of the state of the session
88between the users browser, and your application.
cb93c9d7 89
c718cfb6 90A common example is the Cookie state module, which sends the browser a
91cookie containing the session ID. It will use default value for the
92cookie name and domain, so will "just work" when used.
cb93c9d7 93
94=head3 Store
95
c718cfb6 96A Store module is used to hold all the data relating to your session,
97for example the users ID, or the items for their shopping cart. You
98can store data in memory (FastMmap), in a file (File) or in a database
99(DBI).
cb93c9d7 100
101=head3 Authentication magic
102
103If you have included the session modules in your application, the
104Authentication modules will automagically use your session to save and
105retrieve the user data for you.
106
107=head3 Using a session
108
109Once the session modules are loaded, the session is available as C<<
c718cfb6 110$c->session >>, and can be writen to and read from as a simple hash
111reference.
cb93c9d7 112
113=head3 EXAMPLE
114
b1a08fe1 115 package MyApp;
116 use Moose;
117 use namespace::autoclean;
118
b411df01 119 use Catalyst qw/
ca7528df 120 Session
121 Session::Store::FastMmap
122 Session::State::Cookie
b411df01 123 /;
b1a08fe1 124 extends 'Catalyst';
125 __PACKAGE__->setup;
cb93c9d7 126
b1a08fe1 127 package MyApp::Controller::Foo;
128 use Moose;
129 use namespace::autoclean;
46a5f2f5 130 BEGIN { extends 'Catalyst::Controller' };
cb93c9d7 131 ## Write data into the session
132
133 sub add_item : Local {
134 my ( $self, $c ) = @_;
135
136 my $item_id = $c->req->param("item");
137
138 push @{ $c->session->{items} }, $item_id;
139
140 }
141
142 ## A page later we retrieve the data from the session:
143
144 sub get_items : Local {
145 my ( $self, $c ) = @_;
146
147 $c->stash->{items_to_display} = $c->session->{items};
148
149 }
150
151
152=head3 More information
153
154L<http://search.cpan.org/dist/Catalyst-Plugin-Session>
155
156L<http://search.cpan.org/dist/Catalyst-Plugin-Session-State-Cookie>
157
158L<http://search.cpan.org/dist/Catalyst-Plugin-Session-State-URI>
159
160L<http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-FastMmap>
161
162L<http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-File>
163
164L<http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-DBI>
165
166=head2 Configure your application
167
168You configure your application with the C<config> method in your
169application class. This can be hard-coded, or brought in from a
170separate configuration file.
171
c010ae0d 172=head3 Using Config::General
cb93c9d7 173
c010ae0d 174L<Config::General|Config::General> is a method for creating flexible
175and readable configuration files. It's a great way to keep your
176Catalyst application configuration in one easy-to-understand location.
cb93c9d7 177
c010ae0d 178Now create C<myapp.conf> in your application home:
cb93c9d7 179
c010ae0d 180 name MyApp
cb93c9d7 181
182 # session; perldoc Catalyst::Plugin::Session::FastMmap
c010ae0d 183 <Session>
184 expires 3600
185 rewrite 0
186 storage /tmp/myapp.session
187 </Session>
cb93c9d7 188
189 # emails; perldoc Catalyst::Plugin::Email
190 # this passes options as an array :(
c010ae0d 191 Mail SMTP
192 Mail localhost
cb93c9d7 193
194This is equivalent to:
195
196 # configure base package
197 __PACKAGE__->config( name => MyApp );
198 # configure authentication
199 __PACKAGE__->config->{authentication} = {
200 user_class => 'MyApp::Model::MyDB::Customer',
201 ...
202 };
203 # configure sessions
204 __PACKAGE__->config->{session} = {
205 expires => 3600,
206 ...
207 };
208 # configure email sending
209 __PACKAGE__->config->{email} = [qw/SMTP localhost/];
210
c010ae0d 211See also L<Config::General|Config::General>.
cb93c9d7 212
213=head1 Skipping your VCS's directories
214
46a5f2f5 215Catalyst uses Module::Pluggable to load Models, Views, and Controllers.
cb93c9d7 216Module::Pluggable will scan through all directories and load modules
217it finds. Sometimes you might want to skip some of these directories,
218for example when your version control system makes a subdirectory with
219meta-information in every version-controlled directory. While
220Catalyst skips subversion and CVS directories already, there are other
221source control systems. Here is the configuration you need to add
222their directories to the list to skip.
223
46a5f2f5 224You can make Catalyst skip these directories using the Catalyst config:
cb93c9d7 225
226 # Configure the application
227 __PACKAGE__->config(
228 name => 'MyApp',
229 setup_components => { except => qr/SCCS/ },
230 );
231
232See the Module::Pluggable manual page for more information on B<except>
233and other options.
234
235=head1 Users and Access Control
236
46a5f2f5 237Most multiuser, and some single-user web applications require that
cb93c9d7 238users identify themselves, and the application is often required to
239define those roles. The recipes below describe some ways of doing
240this.
241
242=head2 Authentication (logging in)
243
244This is extensively covered in other documentation; see in particular
245L<Catalyst::Plugin::Authentication> and the Authentication chapter
5641c0c1 246of the Tutorial at L<Catalyst::Manual::Tutorial::06_Authorization>.
cb93c9d7 247
248=head2 Pass-through login (and other actions)
249
250An easy way of having assorted actions that occur during the processing
251of a request that are orthogonal to its actual purpose - logins, silent
252commands etc. Provide actions for these, but when they're required for
253something else fill e.g. a form variable __login and have a sub begin
254like so:
255
256 sub begin : Private {
257 my ($self, $c) = @_;
258 foreach my $action (qw/login docommand foo bar whatever/) {
259 if ($c->req->params->{"__${action}"}) {
260 $c->forward($action);
261 }
262 }
263 }
264
cb93c9d7 265=head2 Authentication/Authorization
266
267This is done in several steps:
268
269=over 4
270
271=item Verification
272
273Getting the user to identify themselves, by giving you some piece of
c718cfb6 274information known only to you and the user. Then you can assume that
275the user is who they say they are. This is called B<credential
276verification>.
cb93c9d7 277
278=item Authorization
279
c718cfb6 280Making sure the user only accesses functions you want them to
46a5f2f5 281access. This is done by checking the verified user's data against your
c718cfb6 282internal list of groups, or allowed persons for the current page.
cb93c9d7 283
284=back
285
286=head3 Modules
287
c718cfb6 288The Catalyst Authentication system is made up of many interacting
289modules, to give you the most flexibility possible.
cb93c9d7 290
291=head4 Credential verifiers
292
c718cfb6 293A Credential module tables the user input, and passes it to a Store,
294or some other system, for verification. Typically, a user object is
295created by either this module or the Store and made accessible by a
296C<< $c->user >> call.
cb93c9d7 297
298Examples:
299
300 Password - Simple username/password checking.
301 HTTPD - Checks using basic HTTP auth.
302 TypeKey - Check using the typekey system.
303
304=head3 Storage backends
305
c718cfb6 306A Storage backend contains the actual data representing the users. It
307is queried by the credential verifiers. Updating the store is not done
46a5f2f5 308within this system; you will need to do it yourself.
cb93c9d7 309
310Examples:
311
46a5f2f5 312 DBIC - Storage using a database via DBIx::Class.
cb93c9d7 313 Minimal - Storage using a simple hash (for testing).
314
315=head3 User objects
316
c718cfb6 317A User object is created by either the storage backend or the
46a5f2f5 318credential verifier, and is filled with the retrieved user information.
cb93c9d7 319
320Examples:
321
322 Hash - A simple hash of keys and values.
323
324=head3 ACL authorization
325
c718cfb6 326ACL stands for Access Control List. The ACL plugin allows you to
46a5f2f5 327regulate access on a path-by-path basis, by listing which users, or
c718cfb6 328roles, have access to which paths.
cb93c9d7 329
330=head3 Roles authorization
331
c718cfb6 332Authorization by roles is for assigning users to groups, which can
333then be assigned to ACLs, or just checked when needed.
cb93c9d7 334
335=head3 Logging in
336
337When you have chosen your modules, all you need to do is call the C<<
b1a08fe1 338$c->authenticate >> method. If called with no parameters, it will try to find
c718cfb6 339suitable parameters, such as B<username> and B<password>, or you can
340pass it these values.
cb93c9d7 341
342=head3 Checking roles
343
46a5f2f5 344Role checking is done by using the C<< $c->check_user_roles >> method.
345This will check using the currently logged-in user (via C<< $c->user
c718cfb6 346>>). You pass it the name of a role to check, and it returns true if
347the user is a member.
cb93c9d7 348
349=head3 EXAMPLE
350
bbddff00 351 package MyApp;
352 use Moose;
353 use namespace::autoclean;
354 extends qw/Catalyst/;
355 use Catalyst qw/
356 Authentication
357 Authorization::Roles
358 /;
359
360 __PACKAGE__->config(
361 authentication => {
362 default_realm => 'test',
363 realms => {
364 test => {
365 credential => {
366 class => 'Password',
367 password_field => 'password',
368 password_type => 'self_check',
369 },
370 store => {
371 class => 'Htpasswd',
372 file => 'htpasswd',
373 },
374 },
375 },
376 },
377 );
378
379 package MyApp::Controller::Root;
380 use Moose;
381 use namespace::autoclean;
382
383 BEGIN { extends 'Catalyst::Controller' }
384
385 __PACKAGE__->config(namespace => '');
386
387 sub login : Local {
cb93c9d7 388 my ($self, $c) = @_;
389
390 if ( my $user = $c->req->param("user")
391 and my $password = $c->req->param("password") )
392 {
b1a08fe1 393 if ( $c->authenticate( username => $user, password => $password ) ) {
cb93c9d7 394 $c->res->body( "hello " . $c->user->name );
395 } else {
396 # login incorrect
397 }
398 }
399 else {
400 # invalid form input
401 }
402 }
403
404 sub restricted : Local {
405 my ( $self, $c ) = @_;
406
407 $c->detach("unauthorized")
408 unless $c->check_user_roles( "admin" );
409
410 # do something restricted here
411 }
412
413=head3 Using authentication in a testing environment
414
46a5f2f5 415Ideally, to write tests for authentication/authorization code one would
416first set up a test database with known data, then use
c718cfb6 417L<Test::WWW::Mechanize::Catalyst> to simulate a user logging
46a5f2f5 418in. Unfortunately this can be rather awkward, which is why it's a good
419thing that the authentication framework is so flexible.
cb93c9d7 420
c718cfb6 421Instead of using a test database, one can simply change the
422authentication store to something a bit easier to deal with in a
423testing environment. Additionally, this has the advantage of not
424modifying one's database, which can be problematic if one forgets to
425use the testing instead of production database.
cb93c9d7 426
46a5f2f5 427Alternatively, if you want to authenticate real users, but not have to
428worry about their passwords, you can use
429L<Catalyst::Authentication::Credential::Testing> to force all users to
430authenticate with a global password.
cb93c9d7 431
432=head3 More information
433
bbddff00 434L<Catalyst::Plugin::Authentication> has a longer explanation.
cb93c9d7 435
436=head2 Authorization
437
438=head3 Introduction
439
c718cfb6 440Authorization is the step that comes after
46a5f2f5 441authentication. Authentication establishes that the user agent is really
442representing the user we think it's representing, and then authorization
443determines what this user is allowed to do.
cb93c9d7 444
445=head3 Role Based Access Control
446
c718cfb6 447Under role based access control each user is allowed to perform any
448number of roles. For example, at a zoo no one but specially trained
46a5f2f5 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,
748and though there are several template systems available, Template
749Toolkit is probably the most popular.
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
1087=head2 Extending RenderView (formerly DefaultEnd)
1088
1089The recommended approach for an C<end> action is to use
1090L<Catalyst::Action::RenderView> (taking the place of
1091L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
1092However there are times when you need to add a bit to it, but don't want
1093to write your own C<end> action.
1094
1095You can extend it like this:
1096
1097To add something to an C<end> action that is called before rendering
1098(this is likely to be what you want), simply place it in the C<end>
1099method:
1100
1101 sub end : ActionClass('RenderView') {
1102 my ( $self, $c ) = @_;
1103 # do stuff here; the RenderView action is called afterwards
1104 }
1105
1106To add things to an C<end> action that are called I<after> rendering,
1107you can set it up like this:
1108
1109 sub render : ActionClass('RenderView') { }
1110
b1a08fe1 1111 sub end : Private {
cb93c9d7 1112 my ( $self, $c ) = @_;
1113 $c->forward('render');
1114 # do stuff here
1115 }
b1a08fe1 1116
cb93c9d7 1117=head2 Action Types
1118
1119=head3 Introduction
1120
c718cfb6 1121A Catalyst application is driven by one or more Controller
1122modules. There are a number of ways that Catalyst can decide which of
1123the methods in your controller modules it should call. Controller
1124methods are also called actions, because they determine how your
1125catalyst application should (re-)act to any given URL. When the
1126application is started up, catalyst looks at all your actions, and
1127decides which URLs they map to.
cb93c9d7 1128
1129=head3 Type attributes
1130
1131Each action is a normal method in your controller, except that it has an
a7b39a0c 1132L<attribute|attributes>
cb93c9d7 1133attached. These can be one of several types.
1134
1135Assume our Controller module starts with the following package declaration:
1136
1137 package MyApp::Controller::Buckets;
1138
1139and we are running our application on localhost, port 3000 (the test
1140server default).
1141
1142=over 4
1143
1144=item Path
1145
1146A Path attribute also takes an argument, this can be either a relative
c718cfb6 1147or an absolute path. A relative path will be relative to the
1148controller namespace, an absolute path will represent an exact
1149matching URL.
cb93c9d7 1150
1151 sub my_handles : Path('handles') { .. }
1152
1153becomes
1154
1155 http://localhost:3000/buckets/handles
1156
1157and
1158
1159 sub my_handles : Path('/handles') { .. }
1160
b1a08fe1 1161becomes
cb93c9d7 1162
1163 http://localhost:3000/handles
1164
6daaedc0 1165See also: L<Catalyst::DispatchType::Path>
1166
cb93c9d7 1167=item Local
1168
c718cfb6 1169When using a Local attribute, no parameters are needed, instead, the
1170name of the action is matched in the URL. The namespaces created by
1171the name of the controller package is always part of the URL.
cb93c9d7 1172
1173 sub my_handles : Local { .. }
1174
1175becomes
1176
1177 http://localhost:3000/buckets/my_handles
1178
1179=item Global
1180
c718cfb6 1181A Global attribute is similar to a Local attribute, except that the
1182namespace of the controller is ignored, and matching starts at root.
cb93c9d7 1183
1184 sub my_handles : Global { .. }
1185
1186becomes
1187
1188 http://localhost:3000/my_handles
1189
1190=item Regex
1191
c718cfb6 1192By now you should have figured that a Regex attribute is just what it
1193sounds like. This one takes a regular expression, and matches starting
1194from root. These differ from the rest as they can match multiple URLs.
cb93c9d7 1195
1196 sub my_handles : Regex('^handles') { .. }
1197
1198matches
1199
1200 http://localhost:3000/handles
1201
b1a08fe1 1202and
cb93c9d7 1203
1204 http://localhost:3000/handles_and_other_parts
1205
1206etc.
1207
6daaedc0 1208See also: L<Catalyst::DispatchType::Regex>
1209
cb93c9d7 1210=item LocalRegex
1211
1212A LocalRegex is similar to a Regex, except it only matches below the current
1213controller namespace.
1214
1215 sub my_handles : LocalRegex(^handles') { .. }
1216
1217matches
1218
1219 http://localhost:3000/buckets/handles
1220
1221and
1222
1223 http://localhost:3000/buckets/handles_and_other_parts
1224
1225etc.
1226
6daaedc0 1227=item Chained
1228
1229See L<Catalyst::DispatchType::Chained> for a description of how the chained
1230dispatch type works.
1231
cb93c9d7 1232=item Private
1233
c718cfb6 1234Last but not least, there is the Private attribute, which allows you
1235to create your own internal actions, which can be forwarded to, but
1236won't be matched as URLs.
cb93c9d7 1237
1238 sub my_handles : Private { .. }
1239
1240becomes nothing at all..
1241
c718cfb6 1242Catalyst also predefines some special Private actions, which you can
1243override, these are:
cb93c9d7 1244
1245=over 4
1246
1247=item default
1248
c718cfb6 1249The default action will be called, if no other matching action is
1250found. If you don't have one of these in your namespace, or any sub
1251part of your namespace, you'll get an error page instead. If you want
1252to find out where it was the user was trying to go, you can look in
1253the request object using C<< $c->req->path >>.
cb93c9d7 1254
85d49fb6 1255 sub default :Path { .. }
cb93c9d7 1256
c718cfb6 1257works for all unknown URLs, in this controller namespace, or every one
1258if put directly into MyApp.pm.
cb93c9d7 1259
b1a08fe1 1260=item index
cb93c9d7 1261
c718cfb6 1262The index action is called when someone tries to visit the exact
1263namespace of your controller. If index, default and matching Path
1264actions are defined, then index will be used instead of default and
1265Path.
cb93c9d7 1266
85d49fb6 1267 sub index :Path :Args(0) { .. }
cb93c9d7 1268
1269becomes
1270
1271 http://localhost:3000/buckets
1272
1273=item begin
1274
c718cfb6 1275The begin action is called at the beginning of every request involving
1276this namespace directly, before other matching actions are called. It
1277can be used to set up variables/data for this particular part of your
1278app. A single begin action is called, its always the one most relevant
1279to the current namespace.
cb93c9d7 1280
1281 sub begin : Private { .. }
1282
b1a08fe1 1283is called once when
cb93c9d7 1284
1285 http://localhost:3000/bucket/(anything)?
1286
1287is visited.
1288
1289=item end
1290
c718cfb6 1291Like begin, this action is always called for the namespace it is in,
1292after every other action has finished. It is commonly used to forward
1293processing to the View component. A single end action is called, its
1294always the one most relevant to the current namespace.
cb93c9d7 1295
1296
1297 sub end : Private { .. }
1298
1299is called once after any actions when
1300
1301 http://localhost:3000/bucket/(anything)?
1302
1303is visited.
1304
1305=item auto
1306
c718cfb6 1307Lastly, the auto action is magic in that B<every> auto action in the
1308chain of paths up to and including the ending namespace, will be
1309called. (In contrast, only one of the begin/end/default actions will
1310be called, the relevant one).
cb93c9d7 1311
b1a08fe1 1312 package MyApp::Controller::Root;
cb93c9d7 1313 sub auto : Private { .. }
1314
b1a08fe1 1315and
cb93c9d7 1316
1317 sub auto : Private { .. }
1318
b1a08fe1 1319will both be called when visiting
cb93c9d7 1320
1321 http://localhost:3000/bucket/(anything)?
1322
1323=back
1324
1325=back
1326
1327=head3 A word of warning
1328
b1a08fe1 1329You can put root actions in your main MyApp.pm file, but this is deprecated,
1330please put your actions into your Root controller.
cb93c9d7 1331
1332=head3 More Information
1333
cb93c9d7 1334L<http://dev.catalyst.perl.org/wiki/FlowChart>
1335
6daaedc0 1336=head2 DRY Controllers with Chained actions.
1337
1338Imagine that you would like the following paths in your application:
1339
1340=over
1341
1b4425c5 1342=item B<< /cd/<ID>/track/<ID> >>
6daaedc0 1343
1344Displays info on a particular track.
b1a08fe1 1345
6daaedc0 1346In the case of a multi-volume CD, this is the track sequence.
1347
1b4425c5 1348=item B<< /cd/<ID>/volume/<ID>/track/<ID> >>
6daaedc0 1349
1350Displays info on a track on a specific volume.
1351
1352=back
1353
1354Here is some example code, showing how to do this with chained controllers:
1355
1356 package CD::Controller;
1357 use base qw/Catalyst::Controller/;
b1a08fe1 1358
6daaedc0 1359 sub root : Chained('/') PathPart('/cd') CaptureArgs(1) {
1360 my ($self, $c, $cd_id) = @_;
1361 $c->stash->{cd_id} = $cd_id;
1362 $c->stash->{cd} = $self->model('CD')->find_by_id($cd_id);
1363 }
b1a08fe1 1364
6daaedc0 1365 sub trackinfo : Chained('track') PathPart('') Args(0) RenderView {
1366 my ($self, $c) = @_;
1367 }
b1a08fe1 1368
6daaedc0 1369 package CD::Controller::ByTrackSeq;
1370 use base qw/CD::Controller/;
b1a08fe1 1371
6daaedc0 1372 sub track : Chained('root') PathPart('track') CaptureArgs(1) {
1373 my ($self, $c, $track_seq) = @_;
1374 $c->stash->{track} = $self->stash->{cd}->find_track_by_seq($track_seq);
1375 }
b1a08fe1 1376
6daaedc0 1377 package CD::Controller::ByTrackVolNo;
1378 use base qw/CD::Controller/;
b1a08fe1 1379
6daaedc0 1380 sub volume : Chained('root') PathPart('volume') CaptureArgs(1) {
1381 my ($self, $c, $volume) = @_;
1382 $c->stash->{volume} = $volume;
1383 }
b1a08fe1 1384
6daaedc0 1385 sub track : Chained('volume') PathPart('track') CaptureArgs(1) {
1386 my ($self, $c, $track_no) = @_;
1387 $c->stash->{track} = $self->stash->{cd}->find_track_by_vol_and_track_no(
1388 $c->stash->{volume}, $track_no
1389 );
1390 }
b1a08fe1 1391
1392Note that adding other actions (i.e. chain endpoints) which operate on a track
6daaedc0 1393is simply a matter of adding a new sub to CD::Controller - no code is duplicated,
1394even though there are two different methods of looking up a track.
1395
1396This technique can be expanded as needed to fulfil your requirements - for example,
1397if you inherit the first action of a chain from a base class, then mixing in a
1398different base class can be used to duplicate an entire URL hieratchy at a different
1399point within your application.
1400
cb93c9d7 1401=head2 Component-based Subrequests
1402
1403See L<Catalyst::Plugin::SubRequest>.
1404
1405=head2 File uploads
1406
1407=head3 Single file upload with Catalyst
1408
1409To implement uploads in Catalyst, you need to have a HTML form similar to
1410this:
1411
1412 <form action="/upload" method="post" enctype="multipart/form-data">
1413 <input type="hidden" name="form_submit" value="yes">
1414 <input type="file" name="my_file">
1415 <input type="submit" value="Send">
1416 </form>
1417
1418It's very important not to forget C<enctype="multipart/form-data"> in
1419the form.
1420
1421Catalyst Controller module 'upload' action:
1422
1423 sub upload : Global {
1424 my ($self, $c) = @_;
1425
1426 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1427
1428 if ( my $upload = $c->request->upload('my_file') ) {
1429
1430 my $filename = $upload->filename;
1431 my $target = "/tmp/upload/$filename";
1432
1433 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1434 die( "Failed to copy '$filename' to '$target': $!" );
1435 }
1436 }
1437 }
1438
1439 $c->stash->{template} = 'file_upload.html';
1440 }
1441
1442=head3 Multiple file upload with Catalyst
1443
1444Code for uploading multiple files from one form needs a few changes:
1445
1446The form should have this basic structure:
1447
1448 <form action="/upload" method="post" enctype="multipart/form-data">
1449 <input type="hidden" name="form_submit" value="yes">
1450 <input type="file" name="file1" size="50"><br>
1451 <input type="file" name="file2" size="50"><br>
1452 <input type="file" name="file3" size="50"><br>
1453 <input type="submit" value="Send">
1454 </form>
1455
1456And in the controller:
1457
1458 sub upload : Local {
1459 my ($self, $c) = @_;
1460
1461 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1462
1463 for my $field ( $c->req->upload ) {
1464
1465 my $upload = $c->req->upload($field);
1466 my $filename = $upload->filename;
1467 my $target = "/tmp/upload/$filename";
1468
1469 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1470 die( "Failed to copy '$filename' to '$target': $!" );
1471 }
1472 }
1473 }
1474
1475 $c->stash->{template} = 'file_upload.html';
1476 }
1477
1478C<for my $field ($c-E<gt>req->upload)> loops automatically over all file
1479input fields and gets input names. After that is basic file saving code,
1480just like in single file upload.
1481
1482Notice: C<die>ing might not be what you want to do, when an error
1483occurs, but it works as an example. A better idea would be to store
1484error C<$!> in $c->stash->{error} and show a custom error template
1485displaying this message.
1486
1487For more information about uploads and usable methods look at
1488L<Catalyst::Request::Upload> and L<Catalyst::Request>.
1489
1490=head2 Forwarding with arguments
1491
1492Sometimes you want to pass along arguments when forwarding to another
1493action. As of version 5.30, arguments can be passed in the call to
1494C<forward>; in earlier versions, you can manually set the arguments in
1495the Catalyst Request object:
1496
1497 # version 5.30 and later:
1498 $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
1499
1500 # pre-5.30
1501 $c->req->args([qw/arg1 arg2 arg3/]);
1502 $c->forward('/wherever');
1503
b1a08fe1 1504(See the L<Catalyst::Manual::Intro> Flow_Control section for more
cb93c9d7 1505information on passing arguments via C<forward>.)
1506
6daaedc0 1507=head2 Chained dispatch using base classes, and inner packages.
1508
1509 package MyApp::Controller::Base;
1510 use base qw/Catalyst::Controller/;
1511
b1a08fe1 1512 sub key1 : Chained('/')
cb93c9d7 1513
1514=head1 Deployment
1515
1516The recipes below describe aspects of the deployment process,
1517including web server engines and tips to improve application efficiency.
1518
1519=head2 mod_perl Deployment
1520
1521mod_perl is the best solution for many applications, but we'll list some pros
1522and cons so you can decide for yourself. The other production deployment
1523option is FastCGI, for which see below.
1524
1525=head3 Pros
1526
1527=head4 Speed
1528
1529mod_perl is very fast and your app will benefit from being loaded in memory
1530within each Apache process.
1531
1532=head4 Shared memory for multiple apps
1533
1534If you need to run several Catalyst apps on the same server, mod_perl will
1535share the memory for common modules.
1536
1537=head3 Cons
1538
1539=head4 Memory usage
1540
1541Since your application is fully loaded in memory, every Apache process will
1542be rather large. This means a large Apache process will be tied up while
1543serving static files, large files, or dealing with slow clients. For this
1544reason, it is best to run a two-tiered web architecture with a lightweight
1545frontend server passing dynamic requests to a large backend mod_perl
1546server.
1547
1548=head4 Reloading
1549
1550Any changes made to the core code of your app require a full Apache restart.
1551Catalyst does not support Apache::Reload or StatINC. This is another good
1552reason to run a frontend web server where you can set up an
1553C<ErrorDocument 502> page to report that your app is down for maintenance.
1554
1555=head4 Cannot run multiple versions of the same app
1556
1557It is not possible to run two different versions of the same application in
1558the same Apache instance because the namespaces will collide.
1559
1560=head4 Setup
1561
1562Now that we have that out of the way, let's talk about setting up mod_perl
1563to run a Catalyst app.
1564
1565=head4 1. Install Catalyst::Engine::Apache
1566
b1a08fe1 1567You should install the latest versions of both Catalyst and
cb93c9d7 1568Catalyst::Engine::Apache. The Apache engines were separated from the
1569Catalyst core in version 5.50 to allow for updates to the engine without
1570requiring a new Catalyst release.
1571
1572=head4 2. Install Apache with mod_perl
1573
1574Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly
1575recommended. With Apache 2, make sure you are using the prefork MPM and not
1576the worker MPM. The reason for this is that many Perl modules are not
1577thread-safe and may have problems running within the threaded worker
1578environment. Catalyst is thread-safe however, so if you know what you're
1579doing, you may be able to run using worker.
1580
1581In Debian, the following commands should get you going.
1582
1583 apt-get install apache2-mpm-prefork
1584 apt-get install libapache2-mod-perl2
1585
1586=head4 3. Configure your application
1587
1588Every Catalyst application will automagically become a mod_perl handler
1589when run within mod_perl. This makes the configuration extremely easy.
1590Here is a basic Apache 2 configuration.
1591
1592 PerlSwitches -I/var/www/MyApp/lib
1593 PerlModule MyApp
b1a08fe1 1594
cb93c9d7 1595 <Location />
1596 SetHandler modperl
1597 PerlResponseHandler MyApp
1598 </Location>
1599
1600The most important line here is C<PerlModule MyApp>. This causes mod_perl
1601to preload your entire application into shared memory, including all of your
1602controller, model, and view classes and configuration. If you have -Debug
1603mode enabled, you will see the startup output scroll by when you first
1604start Apache.
1605
1606For an example Apache 1.3 configuration, please see the documentation for
1607L<Catalyst::Engine::Apache::MP13>.
1608
1609=head3 Test It
1610
1611That's it, your app is now a full-fledged mod_perl application! Try it out
1612by going to http://your.server.com/.
1613
1614=head3 Other Options
1615
1616=head4 Non-root location
1617
1618You may not always want to run your app at the root of your server or virtual
1619host. In this case, it's a simple change to run at any non-root location
1620of your choice.
1621
1622 <Location /myapp>
1623 SetHandler modperl
1624 PerlResponseHandler MyApp
1625 </Location>
b1a08fe1 1626
cb93c9d7 1627When running this way, it is best to make use of the C<uri_for> method in
1628Catalyst for constructing correct links.
1629
1630=head4 Static file handling
1631
1632Static files can be served directly by Apache for a performance boost.
1633
1634 DocumentRoot /var/www/MyApp/root
1635 <Location /static>
1636 SetHandler default-handler
1637 </Location>
b1a08fe1 1638
cb93c9d7 1639This will let all files within root/static be handled directly by Apache. In
1640a two-tiered setup, the frontend server should handle static files.
1641The configuration to do this on the frontend will vary.
1642
3cca8359 1643The same is accomplished in lighttpd with the following snippet:
1644
1645 $HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" {
1646 fastcgi.server = (
1647 "" => (
1648 "MyApp" => (
1649 "socket" => "/tmp/myapp.socket",
1650 "check-local" => "disable",
1651 )
1652 )
1653 )
1654 }
1655
1656Which serves everything in the img, static, css directories
1657statically, as well as the favicon file.
1658
c1c35b01 1659Note the path of the application needs to be stated explicitly in the
1660web server configuration for both these recipes.
3cca8359 1661
cb93c9d7 1662=head2 Catalyst on shared hosting
1663
1664So, you want to put your Catalyst app out there for the whole world to
1665see, but you don't want to break the bank. There is an answer - if you
1666can get shared hosting with FastCGI and a shell, you can install your
1667Catalyst app in a local directory on your shared host. First, run
1668
1669 perl -MCPAN -e shell
1670
1671and go through the standard CPAN configuration process. Then exit out
1672without installing anything. Next, open your .bashrc and add
1673
1674 export PATH=$HOME/local/bin:$HOME/local/script:$PATH
1675 perlversion=`perl -v | grep 'built for' | awk '{print $4}' | sed -e 's/v//;'`
1676 export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB
1677
1678and log out, then back in again (or run C<". .bashrc"> if you
1679prefer). Finally, edit C<.cpan/CPAN/MyConfig.pm> and add
1680
1681 'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local],
1682 'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local],
1683
1684Now you can install the modules you need using CPAN as normal; they
1685will be installed into your local directory, and perl will pick them
1686up. Finally, change directory into the root of your virtual host and
1687symlink your application's script directory in:
1688
1689 cd path/to/mydomain.com
1690 ln -s ~/lib/MyApp/script script
1691
1692And add the following lines to your .htaccess file (assuming the server
1693is setup to handle .pl as fcgi - you may need to rename the script to
1694myapp_fastcgi.fcgi and/or use a SetHandler directive):
1695
1696 RewriteEngine On
1697 RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl
1698 RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
1699
1700Now C<http://mydomain.com/> should now Just Work. Congratulations, now
1701you can tell your friends about your new website (or in our case, tell
1702the client it's time to pay the invoice :) )
1703
1704=head2 FastCGI Deployment
1705
1706FastCGI is a high-performance extension to CGI. It is suitable
1707for production environments.
1708
1709=head3 Pros
1710
1711=head4 Speed
1712
1713FastCGI performs equally as well as mod_perl. Don't let the 'CGI' fool you;
1714your app runs as multiple persistent processes ready to receive connections
1715from the web server.
1716
1717=head4 App Server
1718
1719When using external FastCGI servers, your application runs as a standalone
1720application server. It may be restarted independently from the web server.
1721This allows for a more robust environment and faster reload times when
1722pushing new app changes. The frontend server can even be configured to
1723display a friendly "down for maintenance" page while the application is
1724restarting.
1725
1726=head4 Load-balancing
1727
1728You can launch your application on multiple backend servers and allow the
1729frontend web server to load-balance between all of them. And of course, if
1730one goes down, your app continues to run fine.
1731
1732=head4 Multiple versions of the same app
1733
1734Each FastCGI application is a separate process, so you can run different
1735versions of the same app on a single server.
1736
1737=head4 Can run with threaded Apache
1738
1739Since your app is not running inside of Apache, the faster mpm_worker module
1740can be used without worrying about the thread safety of your application.
1741
1742=head3 Cons
1743
278f816d 1744You may have to disable mod_deflate. If you experience page hangs with
1745mod_fastcgi then remove deflate.load and deflate.conf from mods-enabled/
1746
cb93c9d7 1747=head4 More complex environment
1748
1749With FastCGI, there are more things to monitor and more processes running
1750than when using mod_perl.
1751
1752=head3 Setup
1753
1754=head4 1. Install Apache with mod_fastcgi
1755
1756mod_fastcgi for Apache is a third party module, and can be found at
1757L<http://www.fastcgi.com/>. It is also packaged in many distributions,
1758for example, libapache2-mod-fastcgi in Debian.
1759
1760=head4 2. Configure your application
1761
1762 # Serve static content directly
1763 DocumentRoot /var/www/MyApp/root
1764 Alias /static /var/www/MyApp/root/static
1765
1766 FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3
1767 Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/
b1a08fe1 1768
cb93c9d7 1769 # Or, run at the root
1770 Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
b1a08fe1 1771
cb93c9d7 1772The above commands will launch 3 app processes and make the app available at
1773/myapp/
1774
1775=head3 Standalone server mode
1776
1777While not as easy as the previous method, running your app as an external
1778server gives you much more flexibility.
1779
1780First, launch your app as a standalone server listening on a socket.
1781
1782 script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
b1a08fe1 1783
cb93c9d7 1784You can also listen on a TCP port if your web server is not on the same
1785machine.
1786
1787 script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
b1a08fe1 1788
cb93c9d7 1789You will probably want to write an init script to handle starting/stopping
1790of the app using the pid file.
1791
1792Now, we simply configure Apache to connect to the running server.
1793
1794 # 502 is a Bad Gateway error, and will occur if the backend server is down
1795 # This allows us to display a friendly static page that says "down for
1796 # maintenance"
1797 Alias /_errors /var/www/MyApp/root/error-pages
1798 ErrorDocument 502 /_errors/502.html
1799
31bdf270 1800 FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
1801 Alias /myapp/ /tmp/myapp.fcgi/
b1a08fe1 1802
cb93c9d7 1803 # Or, run at the root
31bdf270 1804 Alias / /tmp/myapp.fcgi/
b1a08fe1 1805
cb93c9d7 1806=head3 More Info
1807
1808L<Catalyst::Engine::FastCGI>.
1809
1810=head2 Development server deployment
1811
1812The development server is a mini web server written in perl. If you
1813expect a low number of hits or you don't need mod_perl/FastCGI speed,
1814you could use the development server as the application server with a
ad2a47ab 1815lightweight proxy web server at the front. However, consider using
816fc503 1816L<Catalyst::Engine::HTTP::Prefork> for this kind of deployment instead, since
ad2a47ab 1817it can better handle multiple concurrent requests without forking, or can
1818prefork a set number of servers for improved performance.
cb93c9d7 1819
1820=head3 Pros
1821
1822As this is an application server setup, the pros are the same as
1823FastCGI (with the exception of speed).
1824It is also:
1825
1826=head4 Simple
1827
1828The development server is what you create your code on, so if it works
1829here, it should work in production!
1830
1831=head3 Cons
1832
1833=head4 Speed
1834
1835Not as fast as mod_perl or FastCGI. Needs to fork for each request
1836that comes in - make sure static files are served by the web server to
1837save forking.
1838
1839=head3 Setup
1840
1841=head4 Start up the development server
1842
ad2a47ab 1843 script/myapp_server.pl -p 8080 -k -f -pidfile=/tmp/myapp.pid
cb93c9d7 1844
1845You will probably want to write an init script to handle stop/starting
1846the app using the pid file.
1847
1848=head4 Configuring Apache
1849
1850Make sure mod_proxy is enabled and add:
1851
1852 # Serve static content directly
1853 DocumentRoot /var/www/MyApp/root
1854 Alias /static /var/www/MyApp/root/static
1855
1856 ProxyRequests Off
1857 <Proxy *>
1858 Order deny,allow
1859 Allow from all
1860 </Proxy>
816fc503 1861
1862 # Need to specifically stop these paths from being passed to proxy
1863 ProxyPass /static !
1864 ProxyPass /favicon.ico !
1865
cb93c9d7 1866 ProxyPass / http://localhost:8080/
1867 ProxyPassReverse / http://localhost:8080/
1868
b1a08fe1 1869 # This is optional if you'd like to show a custom error page
816fc503 1870 # if the proxy is not available
1871 ErrorDocument 502 /static/error_pages/http502.html
1872
cb93c9d7 1873You can wrap the above within a VirtualHost container if you want
1874different apps served on the same host.
1875
1876=head2 Quick deployment: Building PAR Packages
1877
1878You have an application running on your development box, but then you
1879have to quickly move it to another one for
1880demonstration/deployment/testing...
1881
1882PAR packages can save you from a lot of trouble here. They are usual Zip
1883files that contain a blib tree; you can even include all prereqs and a
1884perl interpreter by setting a few flags!
1885
1886=head3 Follow these few points to try it out!
1887
18881. Install Catalyst and PAR 0.89 (or later)
1889
1890 % perl -MCPAN -e 'install Catalyst'
1891 ...
1892 % perl -MCPAN -e 'install PAR'
1893 ...
1894
18952. Create a application
1896
1897 % catalyst.pl MyApp
1898 ...
1899 % cd MyApp
1900
1901Recent versions of Catalyst (5.62 and up) include
1902L<Module::Install::Catalyst>, which simplifies the process greatly. From the shell in your application directory:
1903
1904 % perl Makefile.PL
1905 % make catalyst_par
1906
b1a08fe1 1907You can customise the PAR creation process by special "catalyst_par_*" commands
1908available from L<Module::Install::Catalyst>. You can add these commands in your
3f3d414b 1909Makefile.PL just before the line containing "catalyst;"
1910
b1a08fe1 1911 #Makefile.PL example with extra PAR options
3f3d414b 1912 use inc::Module::Install;
1913
1914 name 'MyApp';
1915 all_from 'lib\MyApp.pm';
1916
1917 requires 'Catalyst::Runtime' => '5.80005';
1918 <snip>
1919 ...
1920 <snip>
1921
1922 catalyst_par_core(1); # bundle perl core modules in the resulting PAR
1923 catalyst_par_multiarch(1); # build a multi-architecture PAR file
1924 catalyst_par_classes(qw/
1925 Some::Additional::Module
1926 Some::Other::Module
1927 /); # specify additional modules you want to be included into PAR
1928 catalyst;
1929
1930 install_script glob('script/*.pl');
1931 auto_install;
1932 WriteAll;
1933
cb93c9d7 1934Congratulations! Your package "myapp.par" is ready, the following
1935steps are just optional.
1936
19373. Test your PAR package with "parl" (no typo)
1938
1939 % parl myapp.par
1940 Usage:
1941 [parl] myapp[.par] [script] [arguments]
1942
1943 Examples:
1944 parl myapp.par myapp_server.pl -r
1945 myapp myapp_cgi.pl
1946
1947 Available scripts:
1948 myapp_cgi.pl
1949 myapp_create.pl
1950 myapp_fastcgi.pl
1951 myapp_server.pl
1952 myapp_test.pl
1953
1954 % parl myapp.par myapp_server.pl
1955 You can connect to your server at http://localhost:3000
1956
1957Yes, this nifty little starter application gets automatically included.
1958You can also use "catalyst_par_script('myapp_server.pl')" to set a
1959default script to execute.
1960
19616. Want to create a binary that includes the Perl interpreter?
1962
1963 % pp -o myapp myapp.par
1964 % ./myapp myapp_server.pl
1965 You can connect to your server at http://localhost:3000
1966
1967=head2 Serving static content
1968
1969Serving static content in Catalyst used to be somewhat tricky; the use
1970of L<Catalyst::Plugin::Static::Simple> makes everything much easier.
1971This plugin will automatically serve your static content during development,
1972but allows you to easily switch to Apache (or other server) in a
1973production environment.
1974
1975=head3 Introduction to Static::Simple
1976
1977Static::Simple is a plugin that will help to serve static content for your
1978application. By default, it will serve most types of files, excluding some
1979standard Template Toolkit extensions, out of your B<root> file directory. All
1980files are served by path, so if B<images/me.jpg> is requested, then
1981B<root/images/me.jpg> is found and served.
1982
1983=head3 Usage
1984
1985Using the plugin is as simple as setting your use line in MyApp.pm to include:
1986
b411df01 1987 use Catalyst qw/Static::Simple/;
cb93c9d7 1988
1989and already files will be served.
1990
1991=head3 Configuring
1992
1993Static content is best served from a single directory within your root
1994directory. Having many different directories such as C<root/css> and
1995C<root/images> requires more code to manage, because you must separately
1996identify each static directory--if you decide to add a C<root/js>
1997directory, you'll need to change your code to account for it. In
1998contrast, keeping all static directories as subdirectories of a main
1999C<root/static> directory makes things much easier to manage. Here's an
2000example of a typical root directory structure:
2001
2002 root/
2003 root/content.tt
2004 root/controller/stuff.tt
2005 root/header.tt
2006 root/static/
2007 root/static/css/main.css
2008 root/static/images/logo.jpg
2009 root/static/js/code.js
2010
2011
2012All static content lives under C<root/static>, with everything else being
2013Template Toolkit files.
2014
2015=over 4
2016
2017=item Include Path
2018
2019You may of course want to change the default locations, and make
2020Static::Simple look somewhere else, this is as easy as:
2021
2022 MyApp->config->{static}->{include_path} = [
2023 MyApp->config->{root},
b1a08fe1 2024 '/path/to/my/files'
cb93c9d7 2025 ];
2026
2027When you override include_path, it will not automatically append the
2028normal root path, so you need to add it yourself if you still want
2029it. These will be searched in order given, and the first matching file
2030served.
2031
2032=item Static directories
2033
2034If you want to force some directories to be only static, you can set
2035them using paths relative to the root dir, or regular expressions:
2036
2037 MyApp->config->{static}->{dirs} = [
2038 'static',
2039 qr/^(images|css)/,
2040 ];
2041
2042=item File extensions
2043
2044By default, the following extensions are not served (that is, they will
2045be processed by Catalyst): B<tmpl, tt, tt2, html, xhtml>. This list can
2046be replaced easily:
2047
2048 MyApp->config->{static}->{ignore_extensions} = [
b1a08fe1 2049 qw/tmpl tt tt2 html xhtml/
cb93c9d7 2050 ];
2051
2052=item Ignoring directories
2053
2054Entire directories can be ignored. If used with include_path,
2055directories relative to the include_path dirs will also be ignored:
2056
2057 MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
2058
2059=back
2060
2061=head3 More information
2062
2063L<http://search.cpan.org/dist/Catalyst-Plugin-Static-Simple/>
2064
2065=head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
2066
2067In some situations you might want to control things more directly,
2068using L<Catalyst::Plugin::Static>.
2069
2070In your main application class (MyApp.pm), load the plugin:
2071
b411df01 2072 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
cb93c9d7 2073
2074You will also need to make sure your end method does I<not> forward
2075static content to the view, perhaps like this:
2076
2077 sub end : Private {
2078 my ( $self, $c ) = @_;
2079
b1a08fe1 2080 $c->forward( 'MyApp::View::TT' )
cb93c9d7 2081 unless ( $c->res->body || !$c->stash->{template} );
2082 }
2083
2084This code will only forward to the view if a template has been
2085previously defined by a controller and if there is not already data in
2086C<$c-E<gt>res-E<gt>body>.
2087
2088Next, create a controller to handle requests for the /static path. Use
2089the Helper to save time. This command will create a stub controller as
2090C<lib/MyApp/Controller/Static.pm>.
2091
2092 $ script/myapp_create.pl controller Static
2093
2094Edit the file and add the following methods:
2095
2096 # serve all files under /static as static files
2097 sub default : Path('/static') {
2098 my ( $self, $c ) = @_;
2099
2100 # Optional, allow the browser to cache the content
2101 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
2102
2103 $c->serve_static; # from Catalyst::Plugin::Static
2104 }
2105
2106 # also handle requests for /favicon.ico
2107 sub favicon : Path('/favicon.ico') {
2108 my ( $self, $c ) = @_;
2109
2110 $c->serve_static;
2111 }
2112
2113You can also define a different icon for the browser to use instead of
2114favicon.ico by using this in your HTML header:
2115
2116 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
2117
2118=head3 Common problems with the Static plugin
2119
2120The Static plugin makes use of the C<shared-mime-info> package to
2121automatically determine MIME types. This package is notoriously
2122difficult to install, especially on win32 and OS X. For OS X the easiest
2123path might be to install Fink, then use C<apt-get install
2124shared-mime-info>. Restart the server, and everything should be fine.
2125
2126Make sure you are using the latest version (>= 0.16) for best
2127results. If you are having errors serving CSS files, or if they get
2128served as text/plain instead of text/css, you may have an outdated
2129shared-mime-info version. You may also wish to simply use the following
2130code in your Static controller:
2131
2132 if ($c->req->path =~ /css$/i) {
2133 $c->serve_static( "text/css" );
2134 } else {
2135 $c->serve_static;
2136 }
2137
2138=head3 Serving Static Files with Apache
2139
2140When using Apache, you can bypass Catalyst and any Static
2141plugins/controllers controller by intercepting requests for the
2142C<root/static> path at the server level. All that is required is to
2143define a DocumentRoot and add a separate Location block for your static
2144content. Here is a complete config for this application under mod_perl
21451.x:
2146
2147 <Perl>
2148 use lib qw(/var/www/MyApp/lib);
2149 </Perl>
2150 PerlModule MyApp
2151
2152 <VirtualHost *>
2153 ServerName myapp.example.com
2154 DocumentRoot /var/www/MyApp/root
2155 <Location />
2156 SetHandler perl-script
2157 PerlHandler MyApp
2158 </Location>
2159 <LocationMatch "/(static|favicon.ico)">
2160 SetHandler default-handler
2161 </LocationMatch>
2162 </VirtualHost>
2163
2164And here's a simpler example that'll get you started:
2165
2166 Alias /static/ "/my/static/files/"
2167 <Location "/static">
2168 SetHandler none
2169 </Location>
2170
2171=head2 Caching
2172
2173Catalyst makes it easy to employ several different types of caching to
2174speed up your applications.
2175
2176=head3 Cache Plugins
2177
2178There are three wrapper plugins around common CPAN cache modules:
2179Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be
2180used to cache the result of slow operations.
2181
ca7528df 2182The Catalyst Advent Calendar uses the FileCache plugin to cache the
cb93c9d7 2183rendered XHTML version of the source POD document. This is an ideal
ca7528df 2184application for a cache because the source document changes
2185infrequently but may be viewed many times.
cb93c9d7 2186
b411df01 2187 use Catalyst qw/Cache::FileCache/;
b1a08fe1 2188
cb93c9d7 2189 ...
b1a08fe1 2190
cb93c9d7 2191 use File::stat;
2192 sub render_pod : Local {
2193 my ( self, $c ) = @_;
b1a08fe1 2194
cb93c9d7 2195 # the cache is keyed on the filename and the modification time
2196 # to check for updates to the file.
2197 my $file = $c->path_to( 'root', '2005', '11.pod' );
2198 my $mtime = ( stat $file )->mtime;
b1a08fe1 2199
cb93c9d7 2200 my $cached_pod = $c->cache->get("$file $mtime");
2201 if ( !$cached_pod ) {
2202 $cached_pod = do_slow_pod_rendering();
2203 # cache the result for 12 hours
2204 $c->cache->set( "$file $mtime", $cached_pod, '12h' );
2205 }
2206 $c->stash->{pod} = $cached_pod;
2207 }
b1a08fe1 2208
cb93c9d7 2209We could actually cache the result forever, but using a value such as 12 hours
2210allows old entries to be automatically expired when they are no longer needed.
2211
2212=head3 Page Caching
2213
2214Another method of caching is to cache the entire HTML page. While this is
2215traditionally handled by a front-end proxy server like Squid, the Catalyst
2216PageCache plugin makes it trivial to cache the entire output from
2217frequently-used or slow actions.
2218
2219Many sites have a busy content-filled front page that might look something
2220like this. It probably takes a while to process, and will do the exact same
2221thing for every single user who views the page.
2222
2223 sub front_page : Path('/') {
2224 my ( $self, $c ) = @_;
b1a08fe1 2225
cb93c9d7 2226 $c->forward( 'get_news_articles' );
2227 $c->forward( 'build_lots_of_boxes' );
2228 $c->forward( 'more_slow_stuff' );
b1a08fe1 2229
cb93c9d7 2230 $c->stash->{template} = 'index.tt';
2231 }
2232
2233We can add the PageCache plugin to speed things up.
2234
b411df01 2235 use Catalyst qw/Cache::FileCache PageCache/;
b1a08fe1 2236
cb93c9d7 2237 sub front_page : Path ('/') {
2238 my ( $self, $c ) = @_;
b1a08fe1 2239
cb93c9d7 2240 $c->cache_page( 300 );
b1a08fe1 2241
cb93c9d7 2242 # same processing as above
2243 }
b1a08fe1 2244
cb93c9d7 2245Now the entire output of the front page, from <html> to </html>, will be
2246cached for 5 minutes. After 5 minutes, the next request will rebuild the
2247page and it will be re-cached.
2248
2249Note that the page cache is keyed on the page URI plus all parameters, so
2250requests for / and /?foo=bar will result in different cache items. Also,
2251only GET requests will be cached by the plugin.
2252
2253You can even get that front-end Squid proxy to help out by enabling HTTP
2254headers for the cached page.
2255
2256 MyApp->config->{page_cache}->{set_http_headers} = 1;
b1a08fe1 2257
cb93c9d7 2258This would now set the following headers so proxies and browsers may cache
2259the content themselves.
2260
2261 Cache-Control: max-age=($expire_time - time)
2262 Expires: $expire_time
2263 Last-Modified: $cache_created_time
b1a08fe1 2264
cb93c9d7 2265=head3 Template Caching
2266
2267Template Toolkit provides support for caching compiled versions of your
2268templates. To enable this in Catalyst, use the following configuration.
2269TT will cache compiled templates keyed on the file mtime, so changes will
2270still be automatically detected.
2271
2272 package MyApp::View::TT;
b1a08fe1 2273
cb93c9d7 2274 use strict;
2275 use warnings;
2276 use base 'Catalyst::View::TT';
b1a08fe1 2277
cb93c9d7 2278 __PACKAGE__->config(
2279 COMPILE_DIR => '/tmp/template_cache',
2280 );
b1a08fe1 2281
cb93c9d7 2282 1;
b1a08fe1 2283
cb93c9d7 2284=head3 More Info
2285
2286See the documentation for each cache plugin for more details and other
2287available configuration options.
2288
2289L<Catalyst::Plugin::Cache::FastMmap>
2290L<Catalyst::Plugin::Cache::FileCache>
2291L<Catalyst::Plugin::Cache::Memcached>
2292L<Catalyst::Plugin::PageCache>
2293L<http://search.cpan.org/dist/Template-Toolkit/lib/Template/Manual/Config.pod#Caching_and_Compiling_Options>
2294
2295=head1 Testing
2296
2297Testing is an integral part of the web application development
2298process. Tests make multi developer teams easier to coordinate, and
2299they help ensure that there are no nasty surprises after upgrades or
2300alterations.
2301
2302=head2 Testing
2303
b1a08fe1 2304Catalyst provides a convenient way of testing your application during
cb93c9d7 2305development and before deployment in a real environment.
2306
b1a08fe1 2307C<Catalyst::Test> makes it possible to run the same tests both locally
cb93c9d7 2308(without an external daemon) and against a remote server via HTTP.
2309
2310=head3 Tests
2311
2312Let's examine a skeleton application's C<t/> directory:
2313
2314 mundus:~/MyApp chansen$ ls -l t/
2315 total 24
2316 -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t
2317 -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t
2318 -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t
2319
2320=over 4
2321
2322=item C<01app.t>
2323
2324Verifies that the application loads, compiles, and returns a successful
2325response.
2326
2327=item C<02pod.t>
2328
b1a08fe1 2329Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
cb93c9d7 2330environment variable is true.
2331
2332=item C<03podcoverage.t>
2333
2334Verifies that all methods/functions have POD coverage. Only executed if the
2335C<TEST_POD> environment variable is true.
2336
2337=back
2338
2339=head3 Creating tests
2340
2341 mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )'
2342 1 use Test::More tests => 2;
2343 2 use_ok( Catalyst::Test, 'MyApp' );
2344 3
2345 4 ok( request('/')->is_success );
2346
2347The first line declares how many tests we are going to run, in this case
2348two. The second line tests and loads our application in test mode. The
2349fourth line verifies that our application returns a successful response.
2350
2351C<Catalyst::Test> exports two functions, C<request> and C<get>. Each can
2352take three different arguments:
2353
2354=over 4
2355
2356=item A string which is a relative or absolute URI.
2357
2358 request('/my/path');
2359 request('http://www.host.com/my/path');
2360
2361=item An instance of C<URI>.
2362
2363 request( URI->new('http://www.host.com/my/path') );
2364
2365=item An instance of C<HTTP::Request>.
2366
2367 request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
2368
2369=back
2370
b1a08fe1 2371C<request> returns an instance of C<HTTP::Response> and C<get> returns the
cb93c9d7 2372content (body) of the response.
2373
2374=head3 Running tests locally
2375
2376 mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
b1a08fe1 2377 t/01app............ok
2378 t/02pod............ok
2379 t/03podcoverage....ok
cb93c9d7 2380 All tests successful.
2381 Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
b1a08fe1 2382
cb93c9d7 2383C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
2384will see debug logs between tests.
2385
2386C<TEST_POD=1> enables POD checking and coverage.
2387
2388C<prove> A command-line tool that makes it easy to run tests. You can
2389find out more about it from the links below.
2390
2391=head3 Running tests remotely
2392
2393 mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
b1a08fe1 2394 t/01app....ok
cb93c9d7 2395 All tests successful.
2396 Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
2397
b1a08fe1 2398C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
2399your application. In C<CGI> or C<FastCGI> it should be the host and path
cb93c9d7 2400to the script.
2401
2402=head3 C<Test::WWW::Mechanize> and Catalyst
2403
2404Be sure to check out C<Test::WWW::Mechanize::Catalyst>. It makes it easy to
2405test HTML, forms and links. A short example of usage:
2406
2407 use Test::More tests => 6;
2408 use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' );
2409
2410 my $mech = Test::WWW::Mechanize::Catalyst->new;
2411 $mech->get_ok("http://localhost/", 'Got index page');
2412 $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
2413 ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
2414 ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
2415 ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
2416
2417=head3 Further Reading
2418
2419=over 4
2420
2421=item Catalyst::Test
2422
2423L<http://search.cpan.org/dist/Catalyst/lib/Catalyst/Test.pm>
2424
2425=item Test::WWW::Mechanize::Catalyst
2426
2427L<http://search.cpan.org/dist/Test-WWW-Mechanize-Catalyst/lib/Test/WWW/Mechanize/Catalyst.pm>
2428
2429=item Test::WWW::Mechanize
2430
2431L<http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm>
2432
2433=item WWW::Mechanize
2434
2435L<http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm>
2436
2437=item LWP::UserAgent
2438
2439L<http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm>
2440
2441=item HTML::Form
2442
2443L<http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm>
2444
2445=item HTTP::Message
2446
2447L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm>
2448
2449=item HTTP::Request
2450
2451L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm>
2452
2453=item HTTP::Request::Common
2454
2455L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request/Common.pm>
2456
2457=item HTTP::Response
2458
2459L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm>
2460
2461=item HTTP::Status
2462
2463L<http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm>
2464
2465=item URI
2466
2467L<http://search.cpan.org/dist/URI/URI.pm>
2468
2469=item Test::More
2470
2471L<http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm>
2472
2473=item Test::Pod
2474
2475L<http://search.cpan.org/dist/Test-Pod/Pod.pm>
2476
2477=item Test::Pod::Coverage
2478
2479L<http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm>
2480
2481=item prove (Test::Harness)
2482
2483L<http://search.cpan.org/dist/Test-Harness/bin/prove>
2484
2485=back
2486
2487=head3 More Information
2488
2489L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::Roles>
2490L<http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::ACL>
2491
2492=head1 AUTHORS
2493
bbddff00 2494Catalyst Contributors, see Catalyst.pm
cb93c9d7 2495
2496=head1 COPYRIGHT
2497
bbddff00 2498This library is free software. You can redistribute it and/or modify it under
2499the same terms as Perl itself.
cb93c9d7 2500
bbddff00 2501=cut