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