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