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