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