Release commit for 5.9013
[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
e454845a 750=back
751
cb93c9d7 752=head3 Tip
753
754Your return data type is usually auto-detected, but you can easily
755enforce a specific one.
756
757 sub add : Remote {
758 my ( $self, $c, $a, $b ) = @_;
759 return RPC::XML::int->new( $a + $b );
760 }
cb93c9d7 761
762=head1 Views
763
764Views pertain to the display of your application. As with models,
46a5f2f5 765Catalyst is uncommonly flexible. The recipes below are just a start.
cb93c9d7 766
5efd5cc6 767=head2 L<Catalyst::View::TT>
cb93c9d7 768
769One of the first things you probably want to do when starting a new
770Catalyst application is set up your View. Catalyst doesn't care how you
771display your data; you can choose to generate HTML, PDF files, or plain
772text if you wanted.
773
774Most Catalyst applications use a template system to generate their HTML,
31e9c5ef 775and though there are several template systems available,
1febc43a 776L<Template Toolkit|Template> is probably the most popular.
cb93c9d7 777
778Once again, the Catalyst developers have done all the hard work, and
5efd5cc6 779made things easy for the rest of us. L<Catalyst::View::TT> provides the
cb93c9d7 780interface to Template Toolkit, and provides Helpers which let us set it
781up that much more easily.
782
783=head3 Creating your View
784
5efd5cc6 785L<Catalyst::View::TT> provides two different helpers for us to use: TT and
cb93c9d7 786TTSite.
787
788=head4 TT
789
790Create a basic Template Toolkit View using the provided helper script:
791
792 script/myapp_create.pl view TT TT
793
e8200f38 794This will create F<lib/MyApp/View/MyView.pm>, which is going to be pretty
cb93c9d7 795empty to start. However, it sets everything up that you need to get
796started. You can now define which template you want and forward to your
797view. For instance:
798
799 sub hello : Local {
800 my ( $self, $c ) = @_;
801
802 $c->stash->{template} = 'hello.tt';
803
804 $c->forward( $c->view('TT') );
805 }
806
807In practice you wouldn't do the forwarding manually, but would
808use L<Catalyst::Action::RenderView>.
809
810=head4 TTSite
811
812Although the TT helper does create a functional, working view, you may
813find yourself having to create the same template files and changing the
814same options every time you create a new application. The TTSite helper
815saves us even more time by creating the basic templates and setting some
816common options for us.
817
818Once again, you can use the helper script:
819
820 script/myapp_create.pl view TT TTSite
821
822This time, the helper sets several options for us in the generated View.
823
824 __PACKAGE__->config({
825 CATALYST_VAR => 'Catalyst',
826 INCLUDE_PATH => [
827 MyApp->path_to( 'root', 'src' ),
828 MyApp->path_to( 'root', 'lib' )
829 ],
830 PRE_PROCESS => 'config/main',
831 WRAPPER => 'site/wrapper',
832 ERROR => 'error.tt2',
833 TIMER => 0
834 });
835
836=over
837
080bb620 838=item *
cb93c9d7 839
e8200f38 840C<INCLUDE_PATH> defines the directories that Template Toolkit should search
cb93c9d7 841for the template files.
842
080bb620 843=item *
cb93c9d7 844
e8200f38 845C<PRE_PROCESS> is used to process configuration options which are common to
cb93c9d7 846every template file.
847
080bb620 848=item *
cb93c9d7 849
e8200f38 850C<WRAPPER> is a file which is processed with each template, usually used to
cb93c9d7 851easily provide a common header and footer for every page.
852
853=back
854
855In addition to setting these options, the TTSite helper also created the
856template and config files for us! In the 'root' directory, you'll notice
857two new directories: src and lib.
858
e8200f38 859Several configuration files in F<root/lib/config> are called by C<PRE_PROCESS>.
cb93c9d7 860
e8200f38 861The files in F<root/lib/site> are the site-wide templates, called by
862C<WRAPPER>, and display the html framework, control the layout, and provide
cb93c9d7 863the templates for the header and footer of your page. Using the template
864organization provided makes it much easier to standardize pages and make
865changes when they are (inevitably) needed.
866
867The template files that you will create for your application will go
e8200f38 868into root/src, and you don't need to worry about putting the C<< <html> >>
869or C<< <head> >> sections; just put in the content. The C<WRAPPER> will the rest
cb93c9d7 870of the page around your template for you.
871
872
080bb620 873=head3 C<< $c->stash >>
cb93c9d7 874
875Of course, having the template system include the header and footer for
876you isn't all that we want our templates to do. We need to be able to
877put data into our templates, and have it appear where and how we want
878it, right? That's where the stash comes in.
879
880In our controllers, we can add data to the stash, and then access it
881from the template. For instance:
882
883 sub hello : Local {
884 my ( $self, $c ) = @_;
885
886 $c->stash->{name} = 'Adam';
887
888 $c->stash->{template} = 'hello.tt';
889
890 $c->forward( $c->view('TT') );
891 }
892
e8200f38 893Then, in F<hello.tt>:
cb93c9d7 894
895 <strong>Hello, [% name %]!</strong>
896
897When you view this page, it will display "Hello, Adam!"
898
899All of the information in your stash is available, by its name/key, in
900your templates. And your data don't have to be plain, old, boring
901scalars. You can pass array references and hash references, too.
902
903In your controller:
904
905 sub hello : Local {
906 my ( $self, $c ) = @_;
907
908 $c->stash->{names} = [ 'Adam', 'Dave', 'John' ];
909
910 $c->stash->{template} = 'hello.tt';
911
912 $c->forward( $c->view('TT') );
913 }
914
915In hello.tt:
916
917 [% FOREACH name IN names %]
918 <strong>Hello, [% name %]!</strong><br />
919 [% END %]
920
921This allowed us to loop through each item in the arrayref, and display a
922line for each name that we have.
923
924This is the most basic usage, but Template Toolkit is quite powerful,
925and allows you to truly keep your presentation logic separate from the
926rest of your application.
927
080bb620 928=head3 C<< $c->uri_for() >>
cb93c9d7 929
930One of my favorite things about Catalyst is the ability to move an
931application around without having to worry that everything is going to
932break. One of the areas that used to be a problem was with the http
933links in your template files. For example, suppose you have an
e8200f38 934application installed at C<http://www.domain.com/Calendar>. The links point
935to "C</Calendar>", "C</Calendar/2005>", "C</Calendar/2005/10>", etc. If you move
936the application to be at C<http://www.mydomain.com/Tools/Calendar>, then
cb93c9d7 937all of those links will suddenly break.
938
080bb620 939That's where C<< $c->uri_for() >> comes in. This function will merge its
cb93c9d7 940parameters with either the base location for the app, or its current
941namespace. Let's take a look at a couple of examples.
942
943In your template, you can use the following:
944
945 <a href="[% c.uri_for('/login') %]">Login Here</a>
946
c718cfb6 947Although the parameter starts with a forward slash, this is relative
948to the application root, not the webserver root. This is important to
949remember. So, if your application is installed at
e8200f38 950C<http://www.domain.com/Calendar>, then the link would be
951C<http://www.mydomain.com/Calendar/Login>. If you move your application
c718cfb6 952to a different domain or path, then that link will still be correct.
cb93c9d7 953
954Likewise,
955
956 <a href="[% c.uri_for('2005','10', '24') %]">October, 24 2005</a>
957
c718cfb6 958The first parameter does NOT have a forward slash, and so it will be
959relative to the current namespace. If the application is installed at
e8200f38 960C<http://www.domain.com/Calendar>. and if the template is called from
080bb620 961C<MyApp::Controller::Display>, then the link would become
e8200f38 962C<http://www.domain.com/Calendar/Display/2005/10/24>.
c718cfb6 963
964If you want to link to a parent uri of your current namespace you can
e8200f38 965prefix the arguments with multiple 'C<../>':
c718cfb6 966
967 <a href="[% c.uri_for('../../view', stashed_object.id) %]">User view</a>
cb93c9d7 968
c718cfb6 969Once again, this allows you to move your application around without
970having to worry about broken links. But there's something else, as
e8200f38 971well. Since the links are generated by C<uri_for>, you can use the same
c718cfb6 972template file by several different controllers, and each controller
973will get the links that its supposed to. Since we believe in Don't
974Repeat Yourself, this is particularly helpful if you have common
975elements in your site that you want to keep in one file.
cb93c9d7 976
977Further Reading:
978
6f660c96 979L<Catalyst>
cb93c9d7 980
6f660c96 981L<Catalyst::View::TT>
cb93c9d7 982
6f660c96 983L<Template>
cb93c9d7 984
b1a08fe1 985=head2 Adding RSS feeds
cb93c9d7 986
987Adding RSS feeds to your Catalyst applications is simple. We'll see two
433f1ad4 988different approaches here, but the basic premise is that you forward to
cb93c9d7 989the normal view action first to get the objects, then handle the output
990differently.
991
5efd5cc6 992=head3 Using L<XML::Feed>
cb93c9d7 993
32cebe9b 994Assuming we have a C<view> action that populates
5efd5cc6 995'entries' with some L<DBIx::Class> iterator, the code would look something
cb93c9d7 996like this:
997
998 sub rss : Local {
999 my ($self,$c) = @_;
1000 $c->forward('view'); # get the entries
1001
1002 my $feed = XML::Feed->new('RSS');
1003 $feed->title( $c->config->{name} . ' RSS Feed' );
1004 $feed->link( $c->req->base ); # link to the site.
1005 $feed->description('Catalyst advent calendar'); Some description
1006
1007 # Process the entries
1008 while( my $entry = $c->stash->{entries}->next ) {
1009 my $feed_entry = XML::Feed::Entry->new('RSS');
1010 $feed_entry->title($entry->title);
1011 $feed_entry->link( $c->uri_for($entry->link) );
1012 $feed_entry->issued( DateTime->from_epoch(epoch => $entry->created) );
1013 $feed->add_entry($feed_entry);
1014 }
1015 $c->res->body( $feed->as_xml );
1016 }
1017
32cebe9b 1018With this approach you're
b1a08fe1 1019pretty sure to get something that validates.
cb93c9d7 1020
433f1ad4 1021Note that for both of the above approaches, you'll need to set the
cb93c9d7 1022content type like this:
1023
1024 $c->res->content_type('application/rss+xml');
1025
1026=head3 Final words
1027
1028You could generalize the second variant easily by replacing 'RSS' with a
1029variable, so you can generate Atom feeds with the same code.
1030
1031Now, go ahead and make RSS feeds for all your stuff. The world *needs*
1032updates on your goldfish!
1033
1034=head2 Forcing the browser to download content
1035
1036Sometimes you need your application to send content for download. For
1037example, you can generate a comma-separated values (CSV) file for your
1038users to download and import into their spreadsheet program.
1039
1040Let's say you have an C<Orders> controller which generates a CSV file
1041in the C<export> action (i.e., C<http://localhost:3000/orders/export>):
1042
1043 sub export : Local Args(0) {
1044 my ( $self, $c ) = @_;
1045
1046 # In a real application, you'd generate this from the database
1047 my $csv = "1,5.99\n2,29.99\n3,3.99\n";
1048
1049 $c->res->content_type('text/comma-separated-values');
1050 $c->res->body($csv);
1051 }
1052
1053Normally the browser uses the last part of the URI to generate a
1054filename for data it cannot display. In this case your browser would
1055likely ask you to save a file named C<export>.
1056
1057Luckily you can have the browser download the content with a specific
1058filename by setting the C<Content-Disposition> header:
1059
1060 my $filename = 'Important Orders.csv';
1061 $c->res->header('Content-Disposition', qq[attachment; filename="$filename"]);
1062
1063Note the use of quotes around the filename; this ensures that any
1064spaces in the filename are handled by the browser.
1065
1066Put this right before calling C<< $c->res->body >> and your browser
f4e9de4a 1067will download a file named F<Important Orders.csv> instead of
cb93c9d7 1068C<export>.
1069
1070You can also use this to have the browser download content which it
1071normally displays, such as JPEG images or even HTML. Just be sure to
1072set the appropriate content type and disposition.
1073
1074
1075=head1 Controllers
1076
1077Controllers are the main point of communication between the web server
1078and your application. Here we explore some aspects of how they work.
1079
cb93c9d7 1080=head2 Action Types
1081
1082=head3 Introduction
1083
c718cfb6 1084A Catalyst application is driven by one or more Controller
1085modules. There are a number of ways that Catalyst can decide which of
1086the methods in your controller modules it should call. Controller
1087methods are also called actions, because they determine how your
1088catalyst application should (re-)act to any given URL. When the
1089application is started up, catalyst looks at all your actions, and
1090decides which URLs they map to.
cb93c9d7 1091
1092=head3 Type attributes
1093
1094Each action is a normal method in your controller, except that it has an
a7b39a0c 1095L<attribute|attributes>
cb93c9d7 1096attached. These can be one of several types.
1097
1098Assume our Controller module starts with the following package declaration:
1099
02bb2b5a 1100 package MyApp::Controller::Buckets;
cb93c9d7 1101
1102and we are running our application on localhost, port 3000 (the test
1103server default).
1104
1105=over 4
1106
1107=item Path
1108
1109A Path attribute also takes an argument, this can be either a relative
c718cfb6 1110or an absolute path. A relative path will be relative to the
1111controller namespace, an absolute path will represent an exact
1112matching URL.
cb93c9d7 1113
02bb2b5a 1114 sub my_handles : Path('handles') { .. }
cb93c9d7 1115
1116becomes
1117
02bb2b5a 1118 http://localhost:3000/buckets/handles
cb93c9d7 1119
1120and
1121
02bb2b5a 1122 sub my_handles : Path('/handles') { .. }
cb93c9d7 1123
b1a08fe1 1124becomes
cb93c9d7 1125
02bb2b5a 1126 http://localhost:3000/handles
cb93c9d7 1127
6daaedc0 1128See also: L<Catalyst::DispatchType::Path>
1129
cb93c9d7 1130=item Local
1131
c718cfb6 1132When using a Local attribute, no parameters are needed, instead, the
1133name of the action is matched in the URL. The namespaces created by
1134the name of the controller package is always part of the URL.
cb93c9d7 1135
02bb2b5a 1136 sub my_handles : Local { .. }
cb93c9d7 1137
1138becomes
1139
02bb2b5a 1140 http://localhost:3000/buckets/my_handles
cb93c9d7 1141
1142=item Global
1143
c718cfb6 1144A Global attribute is similar to a Local attribute, except that the
1145namespace of the controller is ignored, and matching starts at root.
cb93c9d7 1146
02bb2b5a 1147 sub my_handles : Global { .. }
cb93c9d7 1148
1149becomes
1150
02bb2b5a 1151 http://localhost:3000/my_handles
cb93c9d7 1152
1153=item Regex
1154
c718cfb6 1155By now you should have figured that a Regex attribute is just what it
1156sounds like. This one takes a regular expression, and matches starting
1157from root. These differ from the rest as they can match multiple URLs.
cb93c9d7 1158
02bb2b5a 1159 sub my_handles : Regex('^handles') { .. }
cb93c9d7 1160
1161matches
1162
02bb2b5a 1163 http://localhost:3000/handles
cb93c9d7 1164
b1a08fe1 1165and
cb93c9d7 1166
02bb2b5a 1167 http://localhost:3000/handles_and_other_parts
cb93c9d7 1168
1169etc.
1170
6daaedc0 1171See also: L<Catalyst::DispatchType::Regex>
1172
cb93c9d7 1173=item LocalRegex
1174
1175A LocalRegex is similar to a Regex, except it only matches below the current
1176controller namespace.
1177
02bb2b5a 1178 sub my_handles : LocalRegex(^handles') { .. }
cb93c9d7 1179
1180matches
1181
02bb2b5a 1182 http://localhost:3000/buckets/handles
cb93c9d7 1183
1184and
1185
02bb2b5a 1186 http://localhost:3000/buckets/handles_and_other_parts
cb93c9d7 1187
1188etc.
1189
6daaedc0 1190=item Chained
1191
1192See L<Catalyst::DispatchType::Chained> for a description of how the chained
1193dispatch type works.
1194
cb93c9d7 1195=item Private
1196
c718cfb6 1197Last but not least, there is the Private attribute, which allows you
1198to create your own internal actions, which can be forwarded to, but
1199won't be matched as URLs.
cb93c9d7 1200
02bb2b5a 1201 sub my_handles : Private { .. }
cb93c9d7 1202
1203becomes nothing at all..
1204
c718cfb6 1205Catalyst also predefines some special Private actions, which you can
1206override, these are:
cb93c9d7 1207
1208=over 4
1209
1210=item default
1211
c718cfb6 1212The default action will be called, if no other matching action is
1213found. If you don't have one of these in your namespace, or any sub
1214part of your namespace, you'll get an error page instead. If you want
1215to find out where it was the user was trying to go, you can look in
1216the request object using C<< $c->req->path >>.
cb93c9d7 1217
02bb2b5a 1218 sub default :Path { .. }
cb93c9d7 1219
c718cfb6 1220works for all unknown URLs, in this controller namespace, or every one
1221if put directly into MyApp.pm.
cb93c9d7 1222
b1a08fe1 1223=item index
cb93c9d7 1224
c718cfb6 1225The index action is called when someone tries to visit the exact
1226namespace of your controller. If index, default and matching Path
1227actions are defined, then index will be used instead of default and
1228Path.
cb93c9d7 1229
02bb2b5a 1230 sub index :Path :Args(0) { .. }
cb93c9d7 1231
1232becomes
1233
02bb2b5a 1234 http://localhost:3000/buckets
cb93c9d7 1235
1236=item begin
1237
c718cfb6 1238The begin action is called at the beginning of every request involving
1239this namespace directly, before other matching actions are called. It
1240can be used to set up variables/data for this particular part of your
1241app. A single begin action is called, its always the one most relevant
1242to the current namespace.
cb93c9d7 1243
02bb2b5a 1244 sub begin : Private { .. }
cb93c9d7 1245
b1a08fe1 1246is called once when
cb93c9d7 1247
02bb2b5a 1248 http://localhost:3000/bucket/(anything)?
cb93c9d7 1249
1250is visited.
1251
1252=item end
1253
c718cfb6 1254Like begin, this action is always called for the namespace it is in,
1255after every other action has finished. It is commonly used to forward
1256processing to the View component. A single end action is called, its
1257always the one most relevant to the current namespace.
cb93c9d7 1258
1259
02bb2b5a 1260 sub end : Private { .. }
cb93c9d7 1261
1262is called once after any actions when
1263
02bb2b5a 1264 http://localhost:3000/bucket/(anything)?
cb93c9d7 1265
1266is visited.
1267
1268=item auto
1269
c718cfb6 1270Lastly, the auto action is magic in that B<every> auto action in the
1271chain of paths up to and including the ending namespace, will be
1272called. (In contrast, only one of the begin/end/default actions will
1273be called, the relevant one).
cb93c9d7 1274
02bb2b5a 1275 package MyApp::Controller::Root;
1276 sub auto : Private { .. }
cb93c9d7 1277
b1a08fe1 1278and
cb93c9d7 1279
1280 sub auto : Private { .. }
1281
b1a08fe1 1282will both be called when visiting
cb93c9d7 1283
02bb2b5a 1284 http://localhost:3000/bucket/(anything)?
cb93c9d7 1285
1286=back
1287
1288=back
1289
1290=head3 A word of warning
1291
e8200f38 1292You can put root actions in your main F<MyApp.pm> file, but this is deprecated,
b1a08fe1 1293please put your actions into your Root controller.
cb93c9d7 1294
7cfce6e1 1295=head3 Flowchart
cb93c9d7 1296
7cfce6e1 1297A graphical flowchart of how the dispatcher works can be found on the wiki at
08a0ac9e 1298L<https://web.archive.org/web/20190919010727/http://dev.catalystframework.org/attachment/wiki/WikiStart/catalyst-flow.png>.
cb93c9d7 1299
7cfce6e1 1300=head2 DRY Controllers with Chained actions
6daaedc0 1301
1302Imagine that you would like the following paths in your application:
1303
1304=over
1305
1b4425c5 1306=item B<< /cd/<ID>/track/<ID> >>
6daaedc0 1307
1308Displays info on a particular track.
b1a08fe1 1309
6daaedc0 1310In the case of a multi-volume CD, this is the track sequence.
1311
1b4425c5 1312=item B<< /cd/<ID>/volume/<ID>/track/<ID> >>
6daaedc0 1313
1314Displays info on a track on a specific volume.
1315
1316=back
1317
1318Here is some example code, showing how to do this with chained controllers:
1319
1320 package CD::Controller;
1321 use base qw/Catalyst::Controller/;
b1a08fe1 1322
6daaedc0 1323 sub root : Chained('/') PathPart('/cd') CaptureArgs(1) {
1324 my ($self, $c, $cd_id) = @_;
1325 $c->stash->{cd_id} = $cd_id;
1326 $c->stash->{cd} = $self->model('CD')->find_by_id($cd_id);
1327 }
b1a08fe1 1328
6daaedc0 1329 sub trackinfo : Chained('track') PathPart('') Args(0) RenderView {
1330 my ($self, $c) = @_;
1331 }
b1a08fe1 1332
6daaedc0 1333 package CD::Controller::ByTrackSeq;
1334 use base qw/CD::Controller/;
b1a08fe1 1335
6daaedc0 1336 sub track : Chained('root') PathPart('track') CaptureArgs(1) {
1337 my ($self, $c, $track_seq) = @_;
1338 $c->stash->{track} = $self->stash->{cd}->find_track_by_seq($track_seq);
1339 }
b1a08fe1 1340
6daaedc0 1341 package CD::Controller::ByTrackVolNo;
1342 use base qw/CD::Controller/;
b1a08fe1 1343
6daaedc0 1344 sub volume : Chained('root') PathPart('volume') CaptureArgs(1) {
1345 my ($self, $c, $volume) = @_;
1346 $c->stash->{volume} = $volume;
1347 }
b1a08fe1 1348
6daaedc0 1349 sub track : Chained('volume') PathPart('track') CaptureArgs(1) {
1350 my ($self, $c, $track_no) = @_;
1351 $c->stash->{track} = $self->stash->{cd}->find_track_by_vol_and_track_no(
1352 $c->stash->{volume}, $track_no
1353 );
1354 }
b1a08fe1 1355
1356Note that adding other actions (i.e. chain endpoints) which operate on a track
6daaedc0 1357is simply a matter of adding a new sub to CD::Controller - no code is duplicated,
1358even though there are two different methods of looking up a track.
1359
1360This technique can be expanded as needed to fulfil your requirements - for example,
1361if you inherit the first action of a chain from a base class, then mixing in a
433f1ad4 1362different base class can be used to duplicate an entire URL hierarchy at a different
6daaedc0 1363point within your application.
1364
cb93c9d7 1365=head2 Component-based Subrequests
1366
1367See L<Catalyst::Plugin::SubRequest>.
1368
1369=head2 File uploads
1370
1371=head3 Single file upload with Catalyst
1372
1373To implement uploads in Catalyst, you need to have a HTML form similar to
1374this:
1375
1376 <form action="/upload" method="post" enctype="multipart/form-data">
02bb2b5a 1377 <input type="hidden" name="form_submit" value="yes">
1378 <input type="file" name="my_file">
1379 <input type="submit" value="Send">
cb93c9d7 1380 </form>
1381
1382It's very important not to forget C<enctype="multipart/form-data"> in
1383the form.
1384
1385Catalyst Controller module 'upload' action:
1386
1387 sub upload : Global {
1388 my ($self, $c) = @_;
1389
1390 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1391
1392 if ( my $upload = $c->request->upload('my_file') ) {
1393
1394 my $filename = $upload->filename;
1395 my $target = "/tmp/upload/$filename";
1396
1397 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1398 die( "Failed to copy '$filename' to '$target': $!" );
1399 }
1400 }
1401 }
1402
1403 $c->stash->{template} = 'file_upload.html';
1404 }
1405
1406=head3 Multiple file upload with Catalyst
1407
1408Code for uploading multiple files from one form needs a few changes:
1409
1410The form should have this basic structure:
1411
1412 <form action="/upload" method="post" enctype="multipart/form-data">
02bb2b5a 1413 <input type="hidden" name="form_submit" value="yes">
1414 <input type="file" name="file1" size="50"><br>
1415 <input type="file" name="file2" size="50"><br>
1416 <input type="file" name="file3" size="50"><br>
1417 <input type="submit" value="Send">
cb93c9d7 1418 </form>
1419
1420And in the controller:
1421
1422 sub upload : Local {
1423 my ($self, $c) = @_;
1424
1425 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1426
1427 for my $field ( $c->req->upload ) {
1428
1429 my $upload = $c->req->upload($field);
1430 my $filename = $upload->filename;
1431 my $target = "/tmp/upload/$filename";
1432
1433 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1434 die( "Failed to copy '$filename' to '$target': $!" );
1435 }
1436 }
1437 }
1438
1439 $c->stash->{template} = 'file_upload.html';
1440 }
1441
34626ece 1442C<< for my $field ($c->req->upload) >> loops automatically over all file
cb93c9d7 1443input fields and gets input names. After that is basic file saving code,
1444just like in single file upload.
1445
1446Notice: C<die>ing might not be what you want to do, when an error
1447occurs, but it works as an example. A better idea would be to store
7dae1813 1448error C<$!> in C<< $c->stash->{error} >> and show a custom error template
cb93c9d7 1449displaying this message.
1450
1451For more information about uploads and usable methods look at
1452L<Catalyst::Request::Upload> and L<Catalyst::Request>.
1453
1454=head2 Forwarding with arguments
1455
1456Sometimes you want to pass along arguments when forwarding to another
1457action. As of version 5.30, arguments can be passed in the call to
1458C<forward>; in earlier versions, you can manually set the arguments in
1459the Catalyst Request object:
1460
02bb2b5a 1461 # version 5.30 and later:
1462 $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
cb93c9d7 1463
02bb2b5a 1464 # pre-5.30
1465 $c->req->args([qw/arg1 arg2 arg3/]);
1466 $c->forward('/wherever');
cb93c9d7 1467
b1a08fe1 1468(See the L<Catalyst::Manual::Intro> Flow_Control section for more
cb93c9d7 1469information on passing arguments via C<forward>.)
1470
6daaedc0 1471=head2 Chained dispatch using base classes, and inner packages.
1472
02bb2b5a 1473 package MyApp::Controller::Base;
1474 use base qw/Catalyst::Controller/;
6daaedc0 1475
02bb2b5a 1476 sub key1 : Chained('/')
31e9c5ef 1477
e2728084 1478=head2 Extending RenderView (formerly DefaultEnd)
1479
1480The recommended approach for an C<end> action is to use
1481L<Catalyst::Action::RenderView> (taking the place of
1482L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
1483However there are times when you need to add a bit to it, but don't want
1484to write your own C<end> action.
1485
1486You can extend it like this:
1487
1488To add something to an C<end> action that is called before rendering
1489(this is likely to be what you want), simply place it in the C<end>
1490method:
1491
1492 sub end : ActionClass('RenderView') {
02bb2b5a 1493 my ( $self, $c ) = @_;
1494 # do stuff here; the RenderView action is called afterwards
e2728084 1495 }
1496
1497To add things to an C<end> action that are called I<after> rendering,
1498you can set it up like this:
1499
1500 sub render : ActionClass('RenderView') { }
1501
1502 sub end : Private {
02bb2b5a 1503 my ( $self, $c ) = @_;
1504 $c->forward('render');
1505 # do stuff here
e2728084 1506 }
1507
31e9c5ef 1508
cb93c9d7 1509=head2 Serving static content
1510
1511Serving static content in Catalyst used to be somewhat tricky; the use
1512of L<Catalyst::Plugin::Static::Simple> makes everything much easier.
1513This plugin will automatically serve your static content during development,
1514but allows you to easily switch to Apache (or other server) in a
1515production environment.
1516
1517=head3 Introduction to Static::Simple
1518
1519Static::Simple is a plugin that will help to serve static content for your
1520application. By default, it will serve most types of files, excluding some
1521standard Template Toolkit extensions, out of your B<root> file directory. All
f4e9de4a 1522files are served by path, so if F<images/me.jpg> is requested, then
1523F<root/images/me.jpg> is found and served.
cb93c9d7 1524
1525=head3 Usage
1526
1527Using the plugin is as simple as setting your use line in MyApp.pm to include:
1528
02bb2b5a 1529 use Catalyst qw/Static::Simple/;
cb93c9d7 1530
1531and already files will be served.
1532
1533=head3 Configuring
1534
1535Static content is best served from a single directory within your root
f4e9de4a 1536directory. Having many different directories such as F<root/css> and
1537F<root/images> requires more code to manage, because you must separately
1538identify each static directory--if you decide to add a F<root/js>
cb93c9d7 1539directory, you'll need to change your code to account for it. In
1540contrast, keeping all static directories as subdirectories of a main
f4e9de4a 1541F<root/static> directory makes things much easier to manage. Here's an
cb93c9d7 1542example of a typical root directory structure:
1543
1544 root/
1545 root/content.tt
1546 root/controller/stuff.tt
1547 root/header.tt
1548 root/static/
1549 root/static/css/main.css
1550 root/static/images/logo.jpg
1551 root/static/js/code.js
1552
1553
f4e9de4a 1554All static content lives under F<root/static>, with everything else being
cb93c9d7 1555Template Toolkit files.
1556
1557=over 4
1558
1559=item Include Path
1560
1561You may of course want to change the default locations, and make
1562Static::Simple look somewhere else, this is as easy as:
1563
02bb2b5a 1564 MyApp->config(
1565 static => {
1566 include_path => [
1567 MyApp->path_to('/'),
1568 '/path/to/my/files',
1569 ],
1570 },
1571 );
cb93c9d7 1572
1573When you override include_path, it will not automatically append the
1574normal root path, so you need to add it yourself if you still want
1575it. These will be searched in order given, and the first matching file
1576served.
1577
1578=item Static directories
1579
1580If you want to force some directories to be only static, you can set
1581them using paths relative to the root dir, or regular expressions:
1582
02bb2b5a 1583 MyApp->config(
1584 static => {
1585 dirs => [
1586 'static',
1587 qr/^(images|css)/,
1588 ],
1589 },
1590 );
cb93c9d7 1591
1592=item File extensions
1593
1594By default, the following extensions are not served (that is, they will
1595be processed by Catalyst): B<tmpl, tt, tt2, html, xhtml>. This list can
1596be replaced easily:
1597
02bb2b5a 1598 MyApp->config(
19a5b486 1599 static => {
1600 ignore_extensions => [
1601 qw/tmpl tt tt2 html xhtml/
1602 ],
1603 },
02bb2b5a 1604 );
cb93c9d7 1605
1606=item Ignoring directories
1607
1608Entire directories can be ignored. If used with include_path,
1609directories relative to the include_path dirs will also be ignored:
1610
02bb2b5a 1611 MyApp->config( static => {
19a5b486 1612 ignore_dirs => [ qw/tmpl css/ ],
02bb2b5a 1613 });
cb93c9d7 1614
1615=back
1616
1617=head3 More information
1618
6f660c96 1619L<Catalyst::Plugin::Static::Simple>
cb93c9d7 1620
1621=head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
1622
1623In some situations you might want to control things more directly,
1624using L<Catalyst::Plugin::Static>.
1625
1626In your main application class (MyApp.pm), load the plugin:
1627
b411df01 1628 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
cb93c9d7 1629
1630You will also need to make sure your end method does I<not> forward
1631static content to the view, perhaps like this:
1632
1633 sub end : Private {
1634 my ( $self, $c ) = @_;
1635
b1a08fe1 1636 $c->forward( 'MyApp::View::TT' )
02bb2b5a 1637 unless ( $c->res->body || !$c->stash->{template} );
cb93c9d7 1638 }
1639
1640This code will only forward to the view if a template has been
1641previously defined by a controller and if there is not already data in
429d1caf 1642C<< $c->res->body >>.
cb93c9d7 1643
1644Next, create a controller to handle requests for the /static path. Use
1645the Helper to save time. This command will create a stub controller as
f4e9de4a 1646F<lib/MyApp/Controller/Static.pm>.
cb93c9d7 1647
1648 $ script/myapp_create.pl controller Static
1649
1650Edit the file and add the following methods:
1651
1652 # serve all files under /static as static files
1653 sub default : Path('/static') {
1654 my ( $self, $c ) = @_;
1655
1656 # Optional, allow the browser to cache the content
1657 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
1658
1659 $c->serve_static; # from Catalyst::Plugin::Static
1660 }
1661
1662 # also handle requests for /favicon.ico
1663 sub favicon : Path('/favicon.ico') {
1664 my ( $self, $c ) = @_;
1665
1666 $c->serve_static;
1667 }
1668
1669You can also define a different icon for the browser to use instead of
1670favicon.ico by using this in your HTML header:
1671
1672 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
1673
1674=head3 Common problems with the Static plugin
1675
1676The Static plugin makes use of the C<shared-mime-info> package to
1677automatically determine MIME types. This package is notoriously
1678difficult to install, especially on win32 and OS X. For OS X the easiest
1679path might be to install Fink, then use C<apt-get install
1680shared-mime-info>. Restart the server, and everything should be fine.
1681
1682Make sure you are using the latest version (>= 0.16) for best
1683results. If you are having errors serving CSS files, or if they get
1684served as text/plain instead of text/css, you may have an outdated
1685shared-mime-info version. You may also wish to simply use the following
1686code in your Static controller:
1687
1688 if ($c->req->path =~ /css$/i) {
1689 $c->serve_static( "text/css" );
1690 } else {
1691 $c->serve_static;
1692 }
1693
1694=head3 Serving Static Files with Apache
1695
1696When using Apache, you can bypass Catalyst and any Static
1697plugins/controllers controller by intercepting requests for the
f4e9de4a 1698F<root/static> path at the server level. All that is required is to
cb93c9d7 1699define a DocumentRoot and add a separate Location block for your static
1700content. Here is a complete config for this application under mod_perl
17011.x:
1702
1703 <Perl>
1704 use lib qw(/var/www/MyApp/lib);
1705 </Perl>
1706 PerlModule MyApp
1707
1708 <VirtualHost *>
1709 ServerName myapp.example.com
1710 DocumentRoot /var/www/MyApp/root
1711 <Location />
1712 SetHandler perl-script
1713 PerlHandler MyApp
1714 </Location>
1715 <LocationMatch "/(static|favicon.ico)">
1716 SetHandler default-handler
1717 </LocationMatch>
1718 </VirtualHost>
1719
1720And here's a simpler example that'll get you started:
1721
1722 Alias /static/ "/my/static/files/"
1723 <Location "/static">
1724 SetHandler none
1725 </Location>
1726
1727=head2 Caching
1728
1729Catalyst makes it easy to employ several different types of caching to
1730speed up your applications.
1731
1732=head3 Cache Plugins
1733
1734There are three wrapper plugins around common CPAN cache modules:
1735Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be
1736used to cache the result of slow operations.
1737
ca7528df 1738The Catalyst Advent Calendar uses the FileCache plugin to cache the
cb93c9d7 1739rendered XHTML version of the source POD document. This is an ideal
ca7528df 1740application for a cache because the source document changes
1741infrequently but may be viewed many times.
cb93c9d7 1742
b411df01 1743 use Catalyst qw/Cache::FileCache/;
b1a08fe1 1744
cb93c9d7 1745 ...
b1a08fe1 1746
cb93c9d7 1747 use File::stat;
1748 sub render_pod : Local {
1749 my ( self, $c ) = @_;
b1a08fe1 1750
cb93c9d7 1751 # the cache is keyed on the filename and the modification time
1752 # to check for updates to the file.
1753 my $file = $c->path_to( 'root', '2005', '11.pod' );
1754 my $mtime = ( stat $file )->mtime;
b1a08fe1 1755
cb93c9d7 1756 my $cached_pod = $c->cache->get("$file $mtime");
1757 if ( !$cached_pod ) {
1758 $cached_pod = do_slow_pod_rendering();
1759 # cache the result for 12 hours
1760 $c->cache->set( "$file $mtime", $cached_pod, '12h' );
1761 }
1762 $c->stash->{pod} = $cached_pod;
1763 }
b1a08fe1 1764
cb93c9d7 1765We could actually cache the result forever, but using a value such as 12 hours
1766allows old entries to be automatically expired when they are no longer needed.
1767
1768=head3 Page Caching
1769
1770Another method of caching is to cache the entire HTML page. While this is
5abded07 1771traditionally handled by a frontend proxy server like Squid, the Catalyst
cb93c9d7 1772PageCache plugin makes it trivial to cache the entire output from
1773frequently-used or slow actions.
1774
1775Many sites have a busy content-filled front page that might look something
1776like this. It probably takes a while to process, and will do the exact same
1777thing for every single user who views the page.
1778
1779 sub front_page : Path('/') {
1780 my ( $self, $c ) = @_;
b1a08fe1 1781
cb93c9d7 1782 $c->forward( 'get_news_articles' );
1783 $c->forward( 'build_lots_of_boxes' );
1784 $c->forward( 'more_slow_stuff' );
b1a08fe1 1785
cb93c9d7 1786 $c->stash->{template} = 'index.tt';
1787 }
1788
1789We can add the PageCache plugin to speed things up.
1790
b411df01 1791 use Catalyst qw/Cache::FileCache PageCache/;
b1a08fe1 1792
cb93c9d7 1793 sub front_page : Path ('/') {
1794 my ( $self, $c ) = @_;
b1a08fe1 1795
cb93c9d7 1796 $c->cache_page( 300 );
b1a08fe1 1797
cb93c9d7 1798 # same processing as above
1799 }
b1a08fe1 1800
cb93c9d7 1801Now the entire output of the front page, from <html> to </html>, will be
1802cached for 5 minutes. After 5 minutes, the next request will rebuild the
1803page and it will be re-cached.
1804
1805Note that the page cache is keyed on the page URI plus all parameters, so
1806requests for / and /?foo=bar will result in different cache items. Also,
1807only GET requests will be cached by the plugin.
1808
5abded07 1809You can even get that frontend Squid proxy to help out by enabling HTTP
cb93c9d7 1810headers for the cached page.
1811
19a5b486 1812 MyApp->config(
1813 page_cache => {
1814 set_http_headers => 1,
1815 },
1816 );
b1a08fe1 1817
cb93c9d7 1818This would now set the following headers so proxies and browsers may cache
1819the content themselves.
1820
1821 Cache-Control: max-age=($expire_time - time)
1822 Expires: $expire_time
1823 Last-Modified: $cache_created_time
b1a08fe1 1824
cb93c9d7 1825=head3 Template Caching
1826
1827Template Toolkit provides support for caching compiled versions of your
1828templates. To enable this in Catalyst, use the following configuration.
1829TT will cache compiled templates keyed on the file mtime, so changes will
1830still be automatically detected.
1831
1832 package MyApp::View::TT;
b1a08fe1 1833
cb93c9d7 1834 use strict;
1835 use warnings;
1836 use base 'Catalyst::View::TT';
b1a08fe1 1837
cb93c9d7 1838 __PACKAGE__->config(
1839 COMPILE_DIR => '/tmp/template_cache',
1840 );
b1a08fe1 1841
cb93c9d7 1842 1;
b1a08fe1 1843
cb93c9d7 1844=head3 More Info
1845
1846See the documentation for each cache plugin for more details and other
1847available configuration options.
1848
1849L<Catalyst::Plugin::Cache::FastMmap>
1850L<Catalyst::Plugin::Cache::FileCache>
1851L<Catalyst::Plugin::Cache::Memcached>
1852L<Catalyst::Plugin::PageCache>
655be431 1853L<Template::Manual::Config/Caching and Compiling Options>
cb93c9d7 1854
1855=head1 Testing
1856
1857Testing is an integral part of the web application development
1858process. Tests make multi developer teams easier to coordinate, and
1859they help ensure that there are no nasty surprises after upgrades or
1860alterations.
1861
1862=head2 Testing
1863
b1a08fe1 1864Catalyst provides a convenient way of testing your application during
cb93c9d7 1865development and before deployment in a real environment.
1866
f4e9de4a 1867L<Catalyst::Test> makes it possible to run the same tests both locally
cb93c9d7 1868(without an external daemon) and against a remote server via HTTP.
1869
1870=head3 Tests
1871
f4e9de4a 1872Let's examine a skeleton application's F<t/> directory:
cb93c9d7 1873
1874 mundus:~/MyApp chansen$ ls -l t/
1875 total 24
1876 -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t
1877 -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t
1878 -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t
1879
1880=over 4
1881
f4e9de4a 1882=item F<01app.t>
cb93c9d7 1883
1884Verifies that the application loads, compiles, and returns a successful
1885response.
1886
f4e9de4a 1887=item F<02pod.t>
cb93c9d7 1888
b1a08fe1 1889Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
cb93c9d7 1890environment variable is true.
1891
f4e9de4a 1892=item F<03podcoverage.t>
cb93c9d7 1893
1894Verifies that all methods/functions have POD coverage. Only executed if the
1895C<TEST_POD> environment variable is true.
1896
1897=back
1898
1899=head3 Creating tests
1900
1901 mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )'
1902 1 use Test::More tests => 2;
e5415384 1903 2 BEGIN { use_ok( Catalyst::Test, 'MyApp' ) }
cb93c9d7 1904 3
1905 4 ok( request('/')->is_success );
1906
1907The first line declares how many tests we are going to run, in this case
1908two. The second line tests and loads our application in test mode. The
1909fourth line verifies that our application returns a successful response.
1910
cacb3819 1911L<Catalyst::Test> exports two functions, C<request> and C<get>. Each can
cb93c9d7 1912take three different arguments:
1913
1914=over 4
1915
1916=item A string which is a relative or absolute URI.
1917
1918 request('/my/path');
1919 request('http://www.host.com/my/path');
1920
cacb3819 1921=item An instance of L<URI>.
cb93c9d7 1922
1923 request( URI->new('http://www.host.com/my/path') );
1924
cacb3819 1925=item An instance of L<HTTP::Request>.
cb93c9d7 1926
1927 request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
1928
1929=back
1930
cacb3819 1931C<request> returns an instance of L<HTTP::Response> and C<get> returns the
cb93c9d7 1932content (body) of the response.
1933
1934=head3 Running tests locally
1935
1936 mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
b1a08fe1 1937 t/01app............ok
1938 t/02pod............ok
1939 t/03podcoverage....ok
cb93c9d7 1940 All tests successful.
1941 Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
b1a08fe1 1942
cb93c9d7 1943C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
1944will see debug logs between tests.
1945
1946C<TEST_POD=1> enables POD checking and coverage.
1947
1948C<prove> A command-line tool that makes it easy to run tests. You can
1949find out more about it from the links below.
1950
1951=head3 Running tests remotely
1952
1953 mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
b1a08fe1 1954 t/01app....ok
cb93c9d7 1955 All tests successful.
1956 Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
1957
b1a08fe1 1958C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
1959your application. In C<CGI> or C<FastCGI> it should be the host and path
cb93c9d7 1960to the script.
1961
cacb3819 1962=head3 L<Test::WWW::Mechanize> and Catalyst
cb93c9d7 1963
cacb3819 1964Be sure to check out L<Test::WWW::Mechanize::Catalyst>. It makes it easy to
cb93c9d7 1965test HTML, forms and links. A short example of usage:
1966
1967 use Test::More tests => 6;
e5415384 1968 BEGIN { use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' ) }
cb93c9d7 1969
1970 my $mech = Test::WWW::Mechanize::Catalyst->new;
1971 $mech->get_ok("http://localhost/", 'Got index page');
1972 $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
1973 ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
1974 ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
1975 ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
1976
1977=head3 Further Reading
1978
1979=over 4
1980
6f660c96 1981=item * L<Catalyst::Test>
cb93c9d7 1982
6f660c96 1983=item * L<Test::WWW::Mechanize::Catalyst>
cb93c9d7 1984
6f660c96 1985=item * L<Test::WWW::Mechanize>
cb93c9d7 1986
6f660c96 1987=item * L<WWW::Mechanize>
cb93c9d7 1988
6f660c96 1989=item * L<LWP::UserAgent>
cb93c9d7 1990
6f660c96 1991=item * L<HTML::Form>
cb93c9d7 1992
6f660c96 1993=item * L<HTTP::Message>
cb93c9d7 1994
6f660c96 1995=item * L<HTTP::Request>
cb93c9d7 1996
6f660c96 1997=item * L<HTTP::Request::Common>
cb93c9d7 1998
6f660c96 1999=item * L<HTTP::Response>
cb93c9d7 2000
6f660c96 2001=item * L<HTTP::Status>
cb93c9d7 2002
6f660c96 2003=item * L<URI>
cb93c9d7 2004
6f660c96 2005=item * L<Test::More>
cb93c9d7 2006
6f660c96 2007=item * L<Test::Pod>
cb93c9d7 2008
6f660c96 2009=item * L<Test::Pod::Coverage>
cb93c9d7 2010
6f660c96 2011=item * L<prove> (L<Test::Harness>)
cb93c9d7 2012
6f660c96 2013=back
cb93c9d7 2014
6f660c96 2015=head3 More Information
cb93c9d7 2016
6f660c96 2017=over 4
cb93c9d7 2018
6f660c96 2019=item * L<Catalyst::Plugin::Authorization::Roles>
cb93c9d7 2020
6f660c96 2021=item * L<Catalyst::Plugin::Authorization::ACL>
cb93c9d7 2022
2023=back
2024
cb93c9d7 2025=head1 AUTHORS
2026
bbddff00 2027Catalyst Contributors, see Catalyst.pm
cb93c9d7 2028
2029=head1 COPYRIGHT
2030
bbddff00 2031This library is free software. You can redistribute it and/or modify it under
2032the same terms as Perl itself.
cb93c9d7 2033
bbddff00 2034=cut