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