1Catalyst::Manual::CookbUosoekr(3C)ontributed Perl DocumeCnattaatliyosnt::Manual::Cookbook(3)
2
3
4

NAME

6       Catalyst::Manual::Cookbook - Cooking with Catalyst
7

DESCRIPTION

9       Yummy code like your mum used to bake!
10

RECIPES

Basics

13       These recipes cover some basic stuff that is worth knowing for catalyst
14       developers.
15
16       Delivering a Custom Error Page
17
18       By default, Catalyst will display its own error page whenever it
19       encounters an error in your application. When running under "-Debug"
20       mode, the error page is a useful screen including the error message and
21       Data::Dump output of the relevant parts of the $c context object.  When
22       not in "-Debug", users see a simple "Please come back later" screen.
23
24       To use a custom error page, use a special "end" method to short-circuit
25       the error processing. The following is an example; you might want to
26       adjust it further depending on the needs of your application (for exam‐
27       ple, any calls to "fillform" will probably need to go into this "end"
28       method; see Catalyst::Plugin::FillInForm).
29
30           sub end : Private {
31               my ( $self, $c ) = @_;
32
33               if ( scalar @{ $c->error } ) {
34                   $c->stash->{errors}   = $c->error;
35                   $c->stash->{template} = 'errors.tt';
36                   $c->forward('MyApp::View::TT');
37                   $c->error(0);
38               }
39
40               return 1 if $c->response->status =~ /^3\d\d$/;
41               return 1 if $c->response->body;
42
43               unless ( $c->response->content_type ) {
44                   $c->response->content_type('text/html; charset=utf-8');
45               }
46
47               $c->forward('MyApp::View::TT');
48           }
49
50       You can manually set errors in your code to trigger this page by call‐
51       ing
52
53           $c->error( 'You broke me!' );
54
55       Disable statistics
56
57       Just add this line to your application class if you don't want those
58       nifty statistics in your debug messages.
59
60           sub Catalyst::Log::info { }
61
62       Enable debug status in the environment
63
64       Normally you enable the debugging info by adding the "-Debug" flag to
65       your "use Catalyst" statement. However, you can also enable it using
66       environment variable, so you can (for example) get debug info without
67       modifying your application scripts. Just set "CATALYST_DEBUG" or
68       "<MYAPP>_DEBUG" to a true value.
69
70       Sessions
71
72       When you have your users identified, you will want to somehow remember
73       that fact, to save them from having to identify themselves for every
74       single page. One way to do this is to send the username and password
75       parameters in every single page, but that's ugly, and won't work for
76       static pages.
77
78       Sessions are a method of saving data related to some transaction, and
79       giving the whole collection a single ID. This ID is then given to the
80       user to return to us on every page they visit while logged in. The
81       usual way to do this is using a browser cookie.
82
83       Catalyst uses two types of plugins to represent sessions:
84
85       State
86
87       A State module is used to keep track of the state of the session
88       between the users browser, and your application.
89
90       A common example is the Cookie state module, which sends the browser a
91       cookie containing the session ID. It will use default value for the
92       cookie name and domain, so will "just work" when used.
93
94       Store
95
96       A Store module is used to hold all the data relating to your session,
97       for example the users ID, or the items for their shopping cart. You can
98       store data in memory (FastMmap), in a file (File) or in a database
99       (DBI).
100
101       Authentication magic
102
103       If you have included the session modules in your application, the
104       Authentication modules will automagically use your session to save and
105       retrieve the user data for you.
106
107       Using a session
108
109       Once the session modules are loaded, the session is available as
110       "$c->session", and can be writen to and read from as a simple hash ref‐
111       erence.
112
113       EXAMPLE
114
115         use Catalyst qw/
116                        Session
117                        Session::Store::FastMmap
118                        Session::State::Cookie
119                        /;
120
121         ## Write data into the session
122
123         sub add_item : Local {
124            my ( $self, $c ) = @_;
125
126            my $item_id = $c->req->param("item");
127
128            push @{ $c->session->{items} }, $item_id;
129
130         }
131
132         ## A page later we retrieve the data from the session:
133
134         sub get_items : Local {
135            my ( $self, $c ) = @_;
136
137            $c->stash->{items_to_display} = $c->session->{items};
138
139         }
140
141       More information
142
143       <http://search.cpan.org/dist/Catalyst-Plugin-Session>
144
145       <http://search.cpan.org/dist/Catalyst-Plugin-Session-State-Cookie>
146
147       <http://search.cpan.org/dist/Catalyst-Plugin-Session-State-URI>
148
149       <http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-FastMmap>
150
151       <http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-File>
152
153       <http://search.cpan.org/dist/Catalyst-Plugin-Session-Store-DBI>
154
155       Configure your application
156
157       You configure your application with the "config" method in your appli‐
158       cation class. This can be hard-coded, or brought in from a separate
159       configuration file.
160
161       Using YAML
162
163       YAML is a method for creating flexible and readable configuration
164       files. It's a great way to keep your Catalyst application configuration
165       in one easy-to-understand location.
166
167       In your application class (e.g. "lib/MyApp.pm"):
168
169         use YAML;
170         # application setup
171         __PACKAGE__->config( YAML::LoadFile(__PACKAGE__->config->{'home'} . '/myapp.yml') );
172         __PACKAGE__->setup;
173
174       Now create "myapp.yml" in your application home:
175
176         --- #YAML:1.0
177         # DO NOT USE TABS FOR INDENTATION OR label/value SEPARATION!!!
178         name:     MyApp
179
180         # session; perldoc Catalyst::Plugin::Session::FastMmap
181         session:
182           expires:        '3600'
183           rewrite:        '0'
184           storage:        '/tmp/myapp.session'
185
186         # emails; perldoc Catalyst::Plugin::Email
187         # this passes options as an array :(
188         email:
189           - SMTP
190           - localhost
191
192       This is equivalent to:
193
194         # configure base package
195         __PACKAGE__->config( name => MyApp );
196         # configure authentication
197         __PACKAGE__->config->{authentication} = {
198           user_class => 'MyApp::Model::MyDB::Customer',
199           ...
200         };
201         # configure sessions
202         __PACKAGE__->config->{session} = {
203           expires => 3600,
204           ...
205         };
206         # configure email sending
207         __PACKAGE__->config->{email} = [qw/SMTP localhost/];
208
209       See also YAML.
210

Skipping your VCS's directories

212       Catalyst uses Module::Pluggable to load Models, Views and Controllers.
213       Module::Pluggable will scan through all directories and load modules it
214       finds.  Sometimes you might want to skip some of these directories, for
215       example when your version control system makes a subdirectory with
216       meta-information in every version-controlled directory.  While Catalyst
217       skips subversion and CVS directories already, there are other source
218       control systems.  Here is the configuration you need to add their
219       directories to the list to skip.
220
221       You can make catalyst skip these directories using the Catalyst config:
222
223         # Configure the application
224         __PACKAGE__->config(
225             name => 'MyApp',
226             setup_components => { except => qr/SCCS/ },
227         );
228
229       See the Module::Pluggable manual page for more information on except
230       and other options.
231

Users and Access Control

233       Most multiuser, and some single user web applications require that
234       users identify themselves, and the application is often required to
235       define those roles.  The recipes below describe some ways of doing
236       this.
237
238       Authentication (logging in)
239
240       This is extensively covered in other documentation; see in particular
241       Catalyst::Plugin::Authentication and the Authentication chapter of the
242       Tutorial at Catalyst::Manual::Tutorial::Authorization.
243
244       Pass-through login (and other actions)
245
246       An easy way of having assorted actions that occur during the processing
247       of a request that are orthogonal to its actual purpose - logins, silent
248       commands etc. Provide actions for these, but when they're required for
249       something else fill e.g. a form variable __login and have a sub begin
250       like so:
251
252           sub begin : Private {
253             my ($self, $c) = @_;
254             foreach my $action (qw/login docommand foo bar whatever/) {
255               if ($c->req->params->{"__${action}"}) {
256                 $c->forward($action);
257               }
258             }
259           }
260
261       Role-based Authorization
262
263       For more advanced access control, you may want to consider using role-
264       based authorization. This means you can assign different roles to each
265       user, e.g.  "user", "admin", etc.
266
267       The "login" and "logout" methods and view template are exactly the same
268       as in the previous example.
269
270       The Catalyst::Plugin::Authorization::Roles plugin is required when
271       implementing roles:
272
273        use Catalyst qw/
274           Authentication
275           Authentication::Credential::Password
276           Authentication::Store::Htpasswd
277           Authorization::Roles
278         /;
279
280       Roles are implemented automatically when using Catalyst::Authentica‐
281       tion::Store::Htpasswd:
282
283         # no additional role configuration required
284         __PACKAGE__->config->{authentication}{htpasswd} = "passwdfile";
285
286       Or can be set up manually when using Catalyst::Authentica‐
287       tion::Store::DBIC:
288
289         # Authorization using a many-to-many role relationship
290         __PACKAGE__->config->{authorization}{dbic} = {
291           'role_class'           => 'My::Model::DBIC::Role',
292           'role_field'           => 'name',
293           'user_role_user_field' => 'user',
294
295           # DBIx::Class only (omit if using Class::DBI)
296           'role_rel'             => 'user_role',
297
298           # Class::DBI only, (omit if using DBIx::Class)
299           'user_role_class'      => 'My::Model::CDBI::UserRole'
300           'user_role_role_field' => 'role',
301         };
302
303       To restrict access to any action, you can use the "check_user_roles"
304       method:
305
306         sub restricted : Local {
307            my ( $self, $c ) = @_;
308
309            $c->detach("unauthorized")
310              unless $c->check_user_roles( "admin" );
311
312            # do something restricted here
313         }
314
315       You can also use the "assert_user_roles" method. This just gives an
316       error if the current user does not have one of the required roles:
317
318         sub also_restricted : Global {
319           my ( $self, $c ) = @_;
320           $c->assert_user_roles( qw/ user admin / );
321         }
322
323       Authentication/Authorization
324
325       This is done in several steps:
326
327       Verification
328           Getting the user to identify themselves, by giving you some piece
329           of information known only to you and the user. Then you can assume
330           that the user is who they say they are. This is called credential
331           verification.
332
333       Authorization
334           Making sure the user only accesses functions you want them to
335           access. This is done by checking the verified users data against
336           your internal list of groups, or allowed persons for the current
337           page.
338
339       Modules
340
341       The Catalyst Authentication system is made up of many interacting mod‐
342       ules, to give you the most flexibility possible.
343
344       Credential verifiers
345
346       A Credential module tables the user input, and passes it to a Store, or
347       some other system, for verification. Typically, a user object is cre‐
348       ated by either this module or the Store and made accessible by a
349       "$c->user" call.
350
351       Examples:
352
353        Password - Simple username/password checking.
354        HTTPD    - Checks using basic HTTP auth.
355        TypeKey  - Check using the typekey system.
356
357       Storage backends
358
359       A Storage backend contains the actual data representing the users. It
360       is queried by the credential verifiers. Updating the store is not done
361       within this system, you will need to do it yourself.
362
363       Examples:
364
365        DBIC     - Storage using a database.
366        Minimal  - Storage using a simple hash (for testing).
367
368       User objects
369
370       A User object is created by either the storage backend or the creden‐
371       tial verifier, and filled with the retrieved user information.
372
373       Examples:
374
375        Hash     - A simple hash of keys and values.
376
377       ACL authorization
378
379       ACL stands for Access Control List. The ACL plugin allows you to regu‐
380       late access on a path by path basis, by listing which users, or roles,
381       have access to which paths.
382
383       Roles authorization
384
385       Authorization by roles is for assigning users to groups, which can then
386       be assigned to ACLs, or just checked when needed.
387
388       Logging in
389
390       When you have chosen your modules, all you need to do is call the
391       "$c->login" method. If called with no parameters, it will try to find
392       suitable parameters, such as username and password, or you can pass it
393       these values.
394
395       Checking roles
396
397       Role checking is done by using the "$c->check_user_roles" method, this
398       will check using the currently logged in user (via "$c->user"). You
399       pass it the name of a role to check, and it returns true if the user is
400       a member.
401
402       EXAMPLE
403
404        use Catalyst qw/Authentication
405                        Authentication::Credential::Password
406                        Authentication::Store::Htpasswd
407                        Authorization::Roles/;
408
409        __PACKAGE__->config->{authentication}{htpasswd} = "passwdfile";
410
411         sub login : Local {
412            my ($self, $c) = @_;
413
414            if (    my $user = $c->req->param("user")
415                and my $password = $c->req->param("password") )
416            {
417                if ( $c->login( $user, $password ) ) {
418                     $c->res->body( "hello " . $c->user->name );
419                } else {
420                   # login incorrect
421                }
422            }
423            else {
424                # invalid form input
425            }
426         }
427
428         sub restricted : Local {
429            my ( $self, $c ) = @_;
430
431            $c->detach("unauthorized")
432              unless $c->check_user_roles( "admin" );
433
434            # do something restricted here
435         }
436
437       Using authentication in a testing environment
438
439       Ideally, to write tests for authentication/authorization code one would
440       first set up a test database with known data, then use Test::WWW::Mech‐
441       anize::Catalyst to simulate a user logging in. Unfortunately the former
442       can be rather awkward, which is why it's a good thing that the authen‐
443       tication framework is so flexible.
444
445       Instead of using a test database, one can simply change the authentica‐
446       tion store to something a bit easier to deal with in a testing environ‐
447       ment. Additionally, this has the advantage of not modifying one's data‐
448       base, which can be problematic if one forgets to use the testing
449       instead of production database.
450
451       e.g.,
452
453         use Catalyst::Plugin::Authentication::Store::Minimal::Backend;
454
455         # Sets up the user `test_user' with password `test_pass'
456         MyApp->default_auth_store(
457           Catalyst::Plugin::Authentication::Store::Minimal::Backend->new({
458             test_user => { password => 'test_pass' },
459           })
460         );
461
462       Now, your test code can call "$c-"login('test_user', 'test_pass')> and
463       successfully login, without messing with the database at all.
464
465       More information
466
467       <http://search.cpan.org/perldoc?Catalyst::Plugin::Authentication> has a
468       longer explanation.
469
470       Authorization
471
472       Introduction
473
474       Authorization is the step that comes after authentication. Authentica‐
475       tion establishes that the user agent is really representing the user we
476       think it's representing, and then authorization determines what this
477       user is allowed to do.
478
479       Role Based Access Control
480
481       Under role based access control each user is allowed to perform any
482       number of roles. For example, at a zoo no one but specially trained
483       personnel can enter the moose cage (Mynd you, møøse bites kan be pretty
484       nasti!). For example:
485
486           package Zoo::Controller::MooseCage;
487
488           sub feed_moose : Local {
489               my ( $self, $c ) = @_;
490
491               $c->model( "Moose" )->eat( $c->req->param("food") );
492           }
493
494       With this action, anyone can just come into the moose cage and feed the
495       moose, which is a very dangerous thing. We need to restrict this
496       action, so that only a qualified moose feeder can perform that action.
497
498       The Authorization::Roles plugin let's us perform role based access con‐
499       trol checks. Let's load it:
500
501           use Catalyst qw/
502               Authentication # yadda yadda
503               Authorization::Roles
504           /;
505
506       And now our action should look like this:
507
508           sub feed_moose : Local {
509               my ( $self, $c ) = @_;
510
511               if ( $c->check_roles( "moose_feeder" ) ) {
512                   $c->model( "Moose" )->eat( $c->req->param("food") );
513               } else {
514                   $c->stash->{error} = "unauthorized";
515               }
516           }
517
518       This checks "$c->user", and only if the user has all the roles in the
519       list, a true value is returned.
520
521       "check_roles" has a sister method, "assert_roles", which throws an
522       exception if any roles are missing.
523
524       Some roles that might actually make sense in, say, a forum application:
525
526       ·   administrator
527
528       ·   moderator
529
530       each with a distinct task (system administration versus content admin‐
531       istration).
532
533       Access Control Lists
534
535       Checking for roles all the time can be tedious and error prone.
536
537       The Authorization::ACL plugin let's us declare where we'd like checks
538       to be done automatically for us.
539
540       For example, we may want to completely block out anyone who isn't a
541       "moose_feeder" from the entire "MooseCage" controller:
542
543           Zoo->deny_access_unless( "/moose_cage", [qw/moose_feeder/] );
544
545       The role list behaves in the same way as "check_roles". However, the
546       ACL plugin isn't limited to just interacting with the Roles plugin. We
547       can use a code reference instead. For example, to allow either moose
548       trainers or moose feeders into the moose cage, we can create a more
549       complex check:
550
551           Zoo->deny_access_unless( "/moose_cage", sub {
552               my $c = shift;
553               $c->check_roles( "moose_trainer" ) ⎪⎪ $c->check_roles( "moose_feeder" );
554           });
555
556       The more specific a role, the earlier it will be checked. Let's say
557       moose feeders are now restricted to only the "feed_moose" action, while
558       moose trainers get access everywhere:
559
560           Zoo->deny_access_unless( "/moose_cage", [qw/moose_trainer/] );
561           Zoo->allow_access_if( "/moose_cage/feed_moose", [qw/moose_feeder/]);
562
563       When the "feed_moose" action is accessed the second check will be made.
564       If the user is a "moose_feeder", then access will be immediately
565       granted. Otherwise, the next rule in line will be tested - the one
566       checking for a "moose_trainer".  If this rule is not satisfied, access
567       will be immediately denied.
568
569       Rules applied to the same path will be checked in the order they were
570       added.
571
572       Lastly, handling access denial events is done by creating an
573       "access_denied" private action:
574
575           sub access_denied : Private {
576               my ( $self, $c, $action ) = @_;
577
578           }
579
580       This action works much like auto, in that it is inherited across names‐
581       paces (not like object oriented code). This means that the
582       "access_denied" action which is nearest to the action which was blocked
583       will be triggered.
584
585       If this action does not exist, an error will be thrown, which you can
586       clean up in your "end" private action instead.
587
588       Also, it's important to note that if you restrict access to "/" then
589       "end", "default", etc will also be restricted.
590
591          MyApp->acl_allow_root_internals;
592
593       will create rules that permit access to "end", "begin", and "auto" in
594       the root of your app (but not in any other controller).
595

Models

597       Models are where application data belongs.  Catalyst is exteremely
598       flexible with the kind of models that it can use.  The recipes here are
599       just the start.
600
601       Using existing DBIC (etc.) classes with Catalyst
602
603       Many people have existing Model classes that they would like to use
604       with Catalyst (or, conversely, they want to write Catalyst models that
605       can be used outside of Catalyst, e.g.  in a cron job). It's trivial to
606       write a simple component in Catalyst that slurps in an outside Model:
607
608           package MyApp::Model::DB;
609           use base qw/Catalyst::Model::DBIC::Schema/;
610           __PACKAGE__->config(
611               schema_class => 'Some::DBIC::Schema',
612               connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}];
613           );
614           1;
615
616       and that's it! Now "Some::DBIC::Schema" is part of your Cat app as
617       "MyApp::Model::DB".
618
619       DBIx::Class as a Catalyst Model
620
621       See Catalyst::Model::DBIC::Schema.
622
623       XMLRPC
624
625       Unlike SOAP, XMLRPC is a very simple (and imo elegant) web-services
626       protocol, exchanging small XML messages like these:
627
628       Request:
629
630           POST /api HTTP/1.1
631           TE: deflate,gzip;q=0.3
632           Connection: TE, close
633           Accept: text/xml
634           Accept: multipart/*
635           Host: 127.0.0.1:3000
636           User-Agent: SOAP::Lite/Perl/0.60
637           Content-Length: 192
638           Content-Type: text/xml
639
640           <?xml version="1.0" encoding="UTF-8"?>
641           <methodCall>
642               <methodName>add</methodName>
643               <params>
644                   <param><value><int>1</int></value></param>
645                   <param><value><int>2</int></value></param>
646               </params>
647           </methodCall>
648
649       Response:
650
651           Connection: close
652           Date: Tue, 20 Dec 2005 07:45:55 GMT
653           Content-Length: 133
654           Content-Type: text/xml
655           Status: 200
656           X-Catalyst: 5.70
657
658           <?xml version="1.0" encoding="us-ascii"?>
659           <methodResponse>
660               <params>
661                   <param><value><int>3</int></value></param>
662               </params>
663           </methodResponse>
664
665       Now follow these few steps to implement the application:
666
667       1. Install Catalyst (5.61 or later), Catalyst::Plugin::XMLRPC (0.06 or
668       later) and SOAP::Lite (for XMLRPCsh.pl).
669
670       2. Create an application framework:
671
672           % catalyst.pl MyApp
673           ...
674           % cd MyApp
675
676       3. Add the XMLRPC plugin to MyApp.pm
677
678           use Catalyst qw/-Debug Static::Simple XMLRPC/;
679
680       4. Add an API controller
681
682           % ./script/myapp_create.pl controller API
683
684       5. Add a XMLRPC redispatch method and an add method with Remote
685       attribute to lib/MyApp/Controller/API.pm
686
687           sub default : Private {
688               my ( $self, $c ) = @_;
689               $c->xmlrpc;
690           }
691
692           sub add : Remote {
693               my ( $self, $c, $a, $b ) = @_;
694               return $a + $b;
695           }
696
697       The default action is the entry point for each XMLRPC request. It will
698       redispatch every request to methods with Remote attribute in the same
699       class.
700
701       The "add" method is not a traditional action; it has no private or pub‐
702       lic path. Only the XMLRPC dispatcher knows it exists.
703
704       6. That's it! You have built your first web service. Let's test it with
705       XMLRPCsh.pl (part of SOAP::Lite):
706
707           % ./script/myapp_server.pl
708           ...
709           % XMLRPCsh.pl http://127.0.0.1:3000/api
710           Usage: method[(parameters)]
711           > add( 1, 2 )
712           --- XMLRPC RESULT ---
713           '3'
714
715       Tip
716
717       Your return data type is usually auto-detected, but you can easily
718       enforce a specific one.
719
720           sub add : Remote {
721               my ( $self, $c, $a, $b ) = @_;
722               return RPC::XML::int->new( $a + $b );
723           }
724

Views

726       Views pertain to the display of your application.  As with models, cat‐
727       alyst is uncommonly flexible.  The recipes below are just a start.
728
729       Catalyst::View::TT
730
731       One of the first things you probably want to do when starting a new
732       Catalyst application is set up your View. Catalyst doesn't care how you
733       display your data; you can choose to generate HTML, PDF files, or plain
734       text if you wanted.
735
736       Most Catalyst applications use a template system to generate their
737       HTML, and though there are several template systems available, Template
738       Toolkit is probably the most popular.
739
740       Once again, the Catalyst developers have done all the hard work, and
741       made things easy for the rest of us. Catalyst::View::TT provides the
742       interface to Template Toolkit, and provides Helpers which let us set it
743       up that much more easily.
744
745       Creating your View
746
747       Catalyst::View::TT provides two different helpers for us to use: TT and
748       TTSite.
749
750       TT
751
752       Create a basic Template Toolkit View using the provided helper script:
753
754           script/myapp_create.pl view TT TT
755
756       This will create lib/MyApp/View/MyView.pm, which is going to be pretty
757       empty to start. However, it sets everything up that you need to get
758       started. You can now define which template you want and forward to your
759       view. For instance:
760
761           sub hello : Local {
762               my ( $self, $c ) = @_;
763
764               $c->stash->{template} = 'hello.tt';
765
766               $c->forward( $c->view('TT') );
767           }
768
769       In practice you wouldn't do the forwarding manually, but would use Cat‐
770       alyst::Action::RenderView.
771
772       TTSite
773
774       Although the TT helper does create a functional, working view, you may
775       find yourself having to create the same template files and changing the
776       same options every time you create a new application. The TTSite helper
777       saves us even more time by creating the basic templates and setting
778       some common options for us.
779
780       Once again, you can use the helper script:
781
782           script/myapp_create.pl view TT TTSite
783
784       This time, the helper sets several options for us in the generated
785       View.
786
787           __PACKAGE__->config({
788               CATALYST_VAR => 'Catalyst',
789               INCLUDE_PATH => [
790                   MyApp->path_to( 'root', 'src' ),
791                   MyApp->path_to( 'root', 'lib' )
792               ],
793               PRE_PROCESS  => 'config/main',
794               WRAPPER      => 'site/wrapper',
795               ERROR        => 'error.tt2',
796               TIMER        => 0
797           });
798
799       ·   INCLUDE_PATH defines the directories that Template Toolkit should
800           search for the template files.
801
802       ·   PRE_PROCESS is used to process configuration options which are com‐
803           mon to every template file.
804
805       ·   WRAPPER is a file which is processed with each template, usually
806           used to easily provide a common header and footer for every page.
807
808       In addition to setting these options, the TTSite helper also created
809       the template and config files for us! In the 'root' directory, you'll
810       notice two new directories: src and lib.
811
812       Several configuration files in root/lib/config are called by
813       PRE_PROCESS.
814
815       The files in root/lib/site are the site-wide templates, called by WRAP‐
816       PER, and display the html framework, control the layout, and provide
817       the templates for the header and footer of your page. Using the tem‐
818       plate organization provided makes it much easier to standardize pages
819       and make changes when they are (inevitably) needed.
820
821       The template files that you will create for your application will go
822       into root/src, and you don't need to worry about putting the the <html>
823       or <head> sections; just put in the content. The WRAPPER will the rest
824       of the page around your template for you.
825
826       $c->stash
827
828       Of course, having the template system include the header and footer for
829       you isn't all that we want our templates to do. We need to be able to
830       put data into our templates, and have it appear where and how we want
831       it, right? That's where the stash comes in.
832
833       In our controllers, we can add data to the stash, and then access it
834       from the template. For instance:
835
836           sub hello : Local {
837               my ( $self, $c ) = @_;
838
839               $c->stash->{name} = 'Adam';
840
841               $c->stash->{template} = 'hello.tt';
842
843               $c->forward( $c->view('TT') );
844           }
845
846       Then, in hello.tt:
847
848           <strong>Hello, [% name %]!</strong>
849
850       When you view this page, it will display "Hello, Adam!"
851
852       All of the information in your stash is available, by its name/key, in
853       your templates. And your data don't have to be plain, old, boring
854       scalars. You can pass array references and hash references, too.
855
856       In your controller:
857
858           sub hello : Local {
859               my ( $self, $c ) = @_;
860
861               $c->stash->{names} = [ 'Adam', 'Dave', 'John' ];
862
863               $c->stash->{template} = 'hello.tt';
864
865               $c->forward( $c->view('TT') );
866           }
867
868       In hello.tt:
869
870           [% FOREACH name IN names %]
871               <strong>Hello, [% name %]!</strong><br />
872           [% END %]
873
874       This allowed us to loop through each item in the arrayref, and display
875       a line for each name that we have.
876
877       This is the most basic usage, but Template Toolkit is quite powerful,
878       and allows you to truly keep your presentation logic separate from the
879       rest of your application.
880
881       $c->uri_for()
882
883       One of my favorite things about Catalyst is the ability to move an
884       application around without having to worry that everything is going to
885       break. One of the areas that used to be a problem was with the http
886       links in your template files. For example, suppose you have an applica‐
887       tion installed at http://www.domain.com/Calendar. The links point to
888       "/Calendar", "/Calendar/2005", "/Calendar/2005/10", etc.  If you move
889       the application to be at http://www.mydomain.com/Tools/Calendar, then
890       all of those links will suddenly break.
891
892       That's where $c->uri_for() comes in. This function will merge its
893       parameters with either the base location for the app, or its current
894       namespace. Let's take a look at a couple of examples.
895
896       In your template, you can use the following:
897
898           <a href="[% c.uri_for('/login') %]">Login Here</a>
899
900       Although the parameter starts with a forward slash, this is relative to
901       the application root, not the webserver root. This is important to
902       remember. So, if your application is installed at
903       http://www.domain.com/Calendar, then the link would be http://www.mydo
904       main.com/Calendar/Login. If you move your application to a different
905       domain or path, then that link will still be correct.
906
907       Likewise,
908
909           <a href="[% c.uri_for('2005','10', '24') %]">October, 24 2005</a>
910
911       The first parameter does NOT have a forward slash, and so it will be
912       relative to the current namespace. If the application is installed at
913       http://www.domain.com/Calendar. and if the template is called from
914       MyApp::Controller::Display, then the link would become
915       http://www.domain.com/Calendar/Display/2005/10/24.
916
917       Once again, this allows you to move your application around without
918       having to worry about broken links. But there's something else, as
919       well. Since the links are generated by uri_for, you can use the same
920       template file by several different controllers, and each controller
921       will get the links that its supposed to. Since we believe in Don't
922       Repeat Yourself, this is particularly helpful if you have common ele‐
923       ments in your site that you want to keep in one file.
924
925       Further Reading:
926
927       <http://search.cpan.org/perldoc?Catalyst>
928
929       <http://search.cpan.org/perldoc?Catalyst%3A%3AView%3A%3ATT>
930
931       <http://search.cpan.org/perldoc?Template>
932
933       Adding RSS feeds
934
935       Adding RSS feeds to your Catalyst applications is simple. We'll see two
936       different aproaches here, but the basic premise is that you forward to
937       the normal view action first to get the objects, then handle the output
938       differently.
939
940       Using TT templates
941
942       This is the aproach used in Agave (<http://dev.rawmode.org/>).
943
944           sub rss : Local {
945               my ($self,$c) = @_;
946               $c->forward('view');
947               $c->stash->{template}='rss.tt';
948           }
949
950       Then you need a template. Here's the one from Agave:
951
952           <?xml version="1.0" encoding="UTF-8"?>
953           <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
954             <channel>
955               <title>[ [% blog.name ⎪⎪ c.config.name ⎪⎪ "Agave" %] ] RSS Feed</title>
956               <link>[% base %]</link>
957               <description>Recent posts</description>
958               <language>en-us</language>
959               <ttl>40</ttl>
960            [% WHILE (post = posts.next) %]
961             <item>
962               <title>[% post.title %]</title>
963               <description>[% post.formatted_teaser⎪html%]</description>
964               <pubDate>[% post.pub_date %]</pubDate>
965               <guid>[% post.full_uri %]</guid>
966               <link>[% post.full_uri %]</link>
967               <dc:creator>[% post.author.screenname %]</dc:creator>
968             </item>
969           [% END %]
970             </channel>
971           </rss>
972
973       Using XML::Feed
974
975       A more robust solution is to use XML::Feed, as was done in the Catalyst
976       Advent Calendar. Assuming we have a "view" action that populates
977       'entries' with some DBIx::Class iterator, the code would look something
978       like this:
979
980           sub rss : Local {
981               my ($self,$c) = @_;
982               $c->forward('view'); # get the entries
983
984               my $feed = XML::Feed->new('RSS');
985               $feed->title( $c->config->{name} . ' RSS Feed' );
986               $feed->link( $c->req->base ); # link to the site.
987               $feed->description('Catalyst advent calendar'); Some description
988
989               # Process the entries
990               while( my $entry = $c->stash->{entries}->next ) {
991                   my $feed_entry = XML::Feed::Entry->new('RSS');
992                   $feed_entry->title($entry->title);
993                   $feed_entry->link( $c->uri_for($entry->link) );
994                   $feed_entry->issued( DateTime->from_epoch(epoch => $entry->created) );
995                   $feed->add_entry($feed_entry);
996               }
997               $c->res->body( $feed->as_xml );
998          }
999
1000       A little more code in the controller, but with this approach you're
1001       pretty sure to get something that validates.
1002
1003       Note that for both of the above aproaches, you'll need to set the con‐
1004       tent type like this:
1005
1006           $c->res->content_type('application/rss+xml');
1007
1008       Final words
1009
1010       You could generalize the second variant easily by replacing 'RSS' with
1011       a variable, so you can generate Atom feeds with the same code.
1012
1013       Now, go ahead and make RSS feeds for all your stuff. The world *needs*
1014       updates on your goldfish!
1015
1016       Forcing the browser to download content
1017
1018       Sometimes you need your application to send content for download. For
1019       example, you can generate a comma-separated values (CSV) file for your
1020       users to download and import into their spreadsheet program.
1021
1022       Let's say you have an "Orders" controller which generates a CSV file in
1023       the "export" action (i.e., "http://localhost:3000/orders/export"):
1024
1025           sub export : Local Args(0) {
1026               my ( $self, $c ) = @_;
1027
1028               # In a real application, you'd generate this from the database
1029               my $csv = "1,5.99\n2,29.99\n3,3.99\n";
1030
1031               $c->res->content_type('text/comma-separated-values');
1032               $c->res->body($csv);
1033           }
1034
1035       Normally the browser uses the last part of the URI to generate a file‐
1036       name for data it cannot display. In this case your browser would likely
1037       ask you to save a file named "export".
1038
1039       Luckily you can have the browser download the content with a specific
1040       filename by setting the "Content-Disposition" header:
1041
1042           my $filename = 'Important Orders.csv';
1043           $c->res->header('Content-Disposition', qq[attachment; filename="$filename"]);
1044
1045       Note the use of quotes around the filename; this ensures that any spa‐
1046       ces in the filename are handled by the browser.
1047
1048       Put this right before calling "$c->res->body" and your browser will
1049       download a file named "Important Orders.csv" instead of "export".
1050
1051       You can also use this to have the browser download content which it
1052       normally displays, such as JPEG images or even HTML. Just be sure to
1053       set the appropriate content type and disposition.
1054

Controllers

1056       Controllers are the main point of communication between the web server
1057       and your application.  Here we explore some aspects of how they work.
1058
1059       Extending RenderView (formerly DefaultEnd)
1060
1061       The recommended approach for an "end" action is to use Cata‐
1062       lyst::Action::RenderView (taking the place of Catalyst::Plugin::Defaul‐
1063       tEnd), which does what you usually need.  However there are times when
1064       you need to add a bit to it, but don't want to write your own "end"
1065       action.
1066
1067       You can extend it like this:
1068
1069       To add something to an "end" action that is called before rendering
1070       (this is likely to be what you want), simply place it in the "end"
1071       method:
1072
1073           sub end : ActionClass('RenderView') {
1074             my ( $self, $c ) = @_;
1075             # do stuff here; the RenderView action is called afterwards
1076           }
1077
1078       To add things to an "end" action that are called after rendering, you
1079       can set it up like this:
1080
1081           sub render : ActionClass('RenderView') { }
1082
1083           sub end : Private {
1084             my ( $self, $c ) = @_;
1085             $c->forward('render');
1086             # do stuff here
1087           }
1088
1089       Action Types
1090
1091       Introduction
1092
1093       A Catalyst application is driven by one or more Controller modules.
1094       There are a number of ways that Catalyst can decide which of the meth‐
1095       ods in your controller modules it should call. Controller methods are
1096       also called actions, because they determine how your catalyst applica‐
1097       tion should (re-)act to any given URL. When the application is started
1098       up, catalyst looks at all your actions, and decides which URLs they map
1099       to.
1100
1101       Type attributes
1102
1103       Each action is a normal method in your controller, except that it has
1104       an attribute attached. These can be one of several types.
1105
1106       Assume our Controller module starts with the following package declara‐
1107       tion:
1108
1109        package MyApp::Controller::Buckets;
1110
1111       and we are running our application on localhost, port 3000 (the test
1112       server default).
1113
1114       Path
1115           A Path attribute also takes an argument, this can be either a rela‐
1116           tive or an absolute path. A relative path will be relative to the
1117           controller namespace, an absolute path will represent an exact
1118           matching URL.
1119
1120            sub my_handles : Path('handles') { .. }
1121
1122           becomes
1123
1124            http://localhost:3000/buckets/handles
1125
1126           and
1127
1128            sub my_handles : Path('/handles') { .. }
1129
1130           becomes
1131
1132            http://localhost:3000/handles
1133
1134       Local
1135           When using a Local attribute, no parameters are needed, instead,
1136           the name of the action is matched in the URL. The namespaces cre‐
1137           ated by the name of the controller package is always part of the
1138           URL.
1139
1140            sub my_handles : Local { .. }
1141
1142           becomes
1143
1144            http://localhost:3000/buckets/my_handles
1145
1146       Global
1147           A Global attribute is similar to a Local attribute, except that the
1148           namespace of the controller is ignored, and matching starts at
1149           root.
1150
1151            sub my_handles : Global { .. }
1152
1153           becomes
1154
1155            http://localhost:3000/my_handles
1156
1157       Regex
1158           By now you should have figured that a Regex attribute is just what
1159           it sounds like. This one takes a regular expression, and matches
1160           starting from root. These differ from the rest as they can match
1161           multiple URLs.
1162
1163            sub my_handles : Regex('^handles') { .. }
1164
1165           matches
1166
1167            http://localhost:3000/handles
1168
1169           and
1170
1171            http://localhost:3000/handles_and_other_parts
1172
1173           etc.
1174
1175       LocalRegex
1176           A LocalRegex is similar to a Regex, except it only matches below
1177           the current controller namespace.
1178
1179            sub my_handles : LocalRegex(^handles') { .. }
1180
1181           matches
1182
1183            http://localhost:3000/buckets/handles
1184
1185           and
1186
1187            http://localhost:3000/buckets/handles_and_other_parts
1188
1189           etc.
1190
1191       Private
1192           Last but not least, there is the Private attribute, which allows
1193           you to create your own internal actions, which can be forwarded to,
1194           but won't be matched as URLs.
1195
1196            sub my_handles : Private { .. }
1197
1198           becomes nothing at all..
1199
1200           Catalyst also predefines some special Private actions, which you
1201           can override, these are:
1202
1203           default
1204               The default action will be called, if no other matching action
1205               is found. If you don't have one of these in your namespace, or
1206               any sub part of your namespace, you'll get an error page
1207               instead. If you want to find out where it was the user was try‐
1208               ing to go, you can look in the request object using
1209               "$c->req->path".
1210
1211                sub default : Private { .. }
1212
1213               works for all unknown URLs, in this controller namespace, or
1214               every one if put directly into MyApp.pm.
1215
1216           index
1217               The index action is called when someone tries to visit the
1218               exact namespace of your controller. If index, default and
1219               matching Path actions are defined, then index will be used
1220               instead of default and Path.
1221
1222                sub index : Private { .. }
1223
1224               becomes
1225
1226                http://localhost:3000/buckets
1227
1228           begin
1229               The begin action is called at the beginning of every request
1230               involving this namespace directly, before other matching
1231               actions are called. It can be used to set up variables/data for
1232               this particular part of your app. A single begin action is
1233               called, its always the one most relevant to the current names‐
1234               pace.
1235
1236                sub begin : Private { .. }
1237
1238               is called once when
1239
1240                http://localhost:3000/bucket/(anything)?
1241
1242               is visited.
1243
1244           end Like begin, this action is always called for the namespace it
1245               is in, after every other action has finished. It is commonly
1246               used to forward processing to the View component. A single end
1247               action is called, its always the one most relevant to the cur‐
1248               rent namespace.
1249
1250                sub end : Private { .. }
1251
1252               is called once after any actions when
1253
1254                http://localhost:3000/bucket/(anything)?
1255
1256               is visited.
1257
1258           auto
1259               Lastly, the auto action is magic in that every auto action in
1260               the chain of paths up to and including the ending namespace,
1261               will be called. (In contrast, only one of the begin/end/default
1262               actions will be called, the relevant one).
1263
1264                package MyApp.pm;
1265                sub auto : Private { .. }
1266
1267               and
1268
1269                sub auto : Private { .. }
1270
1271               will both be called when visiting
1272
1273                http://localhost:3000/bucket/(anything)?
1274
1275       A word of warning
1276
1277       Due to possible namespace conflicts with Plugins, it is advised to only
1278       put the pre-defined Private actions in your main MyApp.pm file, all
1279       others should go in a Controller module.
1280
1281       More Information
1282
1283       <http://search.cpan.org/author/SRI/Catalyst-5.61/lib/Catalyst/Man
1284       ual/Intro.pod>
1285
1286       <http://dev.catalyst.perl.org/wiki/FlowChart>
1287
1288       Component-based Subrequests
1289
1290       See Catalyst::Plugin::SubRequest.
1291
1292       File uploads
1293
1294       Single file upload with Catalyst
1295
1296       To implement uploads in Catalyst, you need to have a HTML form similar
1297       to this:
1298
1299           <form action="/upload" method="post" enctype="multipart/form-data">
1300             <input type="hidden" name="form_submit" value="yes">
1301             <input type="file" name="my_file">
1302             <input type="submit" value="Send">
1303           </form>
1304
1305       It's very important not to forget "enctype="multipart/form-data"" in
1306       the form.
1307
1308       Catalyst Controller module 'upload' action:
1309
1310           sub upload : Global {
1311               my ($self, $c) = @_;
1312
1313               if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1314
1315                   if ( my $upload = $c->request->upload('my_file') ) {
1316
1317                       my $filename = $upload->filename;
1318                       my $target   = "/tmp/upload/$filename";
1319
1320                       unless ( $upload->link_to($target) ⎪⎪ $upload->copy_to($target) ) {
1321                           die( "Failed to copy '$filename' to '$target': $!" );
1322                       }
1323                   }
1324               }
1325
1326               $c->stash->{template} = 'file_upload.html';
1327           }
1328
1329       Multiple file upload with Catalyst
1330
1331       Code for uploading multiple files from one form needs a few changes:
1332
1333       The form should have this basic structure:
1334
1335           <form action="/upload" method="post" enctype="multipart/form-data">
1336             <input type="hidden" name="form_submit" value="yes">
1337             <input type="file" name="file1" size="50"><br>
1338             <input type="file" name="file2" size="50"><br>
1339             <input type="file" name="file3" size="50"><br>
1340             <input type="submit" value="Send">
1341           </form>
1342
1343       And in the controller:
1344
1345           sub upload : Local {
1346               my ($self, $c) = @_;
1347
1348               if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1349
1350                   for my $field ( $c->req->upload ) {
1351
1352                       my $upload   = $c->req->upload($field);
1353                       my $filename = $upload->filename;
1354                       my $target   = "/tmp/upload/$filename";
1355
1356                       unless ( $upload->link_to($target) ⎪⎪ $upload->copy_to($target) ) {
1357                           die( "Failed to copy '$filename' to '$target': $!" );
1358                       }
1359                   }
1360               }
1361
1362               $c->stash->{template} = 'file_upload.html';
1363           }
1364
1365       "for my $field ($c->req-"upload)> loops automatically over all file
1366       input fields and gets input names. After that is basic file saving
1367       code, just like in single file upload.
1368
1369       Notice: "die"ing might not be what you want to do, when an error
1370       occurs, but it works as an example. A better idea would be to store
1371       error $! in $c->stash->{error} and show a custom error template dis‐
1372       playing this message.
1373
1374       For more information about uploads and usable methods look at Cata‐
1375       lyst::Request::Upload and Catalyst::Request.
1376
1377       Forwarding with arguments
1378
1379       Sometimes you want to pass along arguments when forwarding to another
1380       action. As of version 5.30, arguments can be passed in the call to
1381       "forward"; in earlier versions, you can manually set the arguments in
1382       the Catalyst Request object:
1383
1384         # version 5.30 and later:
1385         $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
1386
1387         # pre-5.30
1388         $c->req->args([qw/arg1 arg2 arg3/]);
1389         $c->forward('/wherever');
1390
1391       (See the Catalyst::Manual::Intro Flow_Control section for more informa‐
1392       tion on passing arguments via "forward".)
1393

Deployment

1395       The recipes below describe aspects of the deployment process, including
1396       web server engines and tips to improve application efficiency.
1397
1398       mod_perl Deployment
1399
1400       mod_perl is the best solution for many applications, but we'll list
1401       some pros and cons so you can decide for yourself.  The other produc‐
1402       tion deployment option is FastCGI, for which see below.
1403
1404       Pros
1405
1406       Speed
1407
1408       mod_perl is very fast and your app will benefit from being loaded in
1409       memory within each Apache process.
1410
1411       Shared memory for multiple apps
1412
1413       If you need to run several Catalyst apps on the same server, mod_perl
1414       will share the memory for common modules.
1415
1416       Cons
1417
1418       Memory usage
1419
1420       Since your application is fully loaded in memory, every Apache process
1421       will be rather large.  This means a large Apache process will be tied
1422       up while serving static files, large files, or dealing with slow
1423       clients.  For this reason, it is best to run a two-tiered web architec‐
1424       ture with a lightweight frontend server passing dynamic requests to a
1425       large backend mod_perl server.
1426
1427       Reloading
1428
1429       Any changes made to the core code of your app require a full Apache
1430       restart.  Catalyst does not support Apache::Reload or StatINC.  This is
1431       another good reason to run a frontend web server where you can set up
1432       an "ErrorDocument 502" page to report that your app is down for mainte‐
1433       nance.
1434
1435       Cannot run multiple versions of the same app
1436
1437       It is not possible to run two different versions of the same applica‐
1438       tion in the same Apache instance because the namespaces will collide.
1439
1440       Setup
1441
1442       Now that we have that out of the way, let's talk about setting up
1443       mod_perl to run a Catalyst app.
1444
1445       1. Install Catalyst::Engine::Apache
1446
1447       You should install the latest versions of both Catalyst and Cata‐
1448       lyst::Engine::Apache.  The Apache engines were separated from the Cata‐
1449       lyst core in version 5.50 to allow for updates to the engine without
1450       requiring a new Catalyst release.
1451
1452       2. Install Apache with mod_perl
1453
1454       Both Apache 1.3 and Apache 2 are supported, although Apache 2 is highly
1455       recommended.  With Apache 2, make sure you are using the prefork MPM
1456       and not the worker MPM.  The reason for this is that many Perl modules
1457       are not thread-safe and may have problems running within the threaded
1458       worker environment.  Catalyst is thread-safe however, so if you know
1459       what you're doing, you may be able to run using worker.
1460
1461       In Debian, the following commands should get you going.
1462
1463           apt-get install apache2-mpm-prefork
1464           apt-get install libapache2-mod-perl2
1465
1466       3. Configure your application
1467
1468       Every Catalyst application will automagically become a mod_perl handler
1469       when run within mod_perl.  This makes the configuration extremely easy.
1470       Here is a basic Apache 2 configuration.
1471
1472           PerlSwitches -I/var/www/MyApp/lib
1473           PerlModule MyApp
1474
1475           <Location />
1476               SetHandler          modperl
1477               PerlResponseHandler MyApp
1478           </Location>
1479
1480       The most important line here is "PerlModule MyApp".  This causes
1481       mod_perl to preload your entire application into shared memory, includ‐
1482       ing all of your controller, model, and view classes and configuration.
1483       If you have -Debug mode enabled, you will see the startup output scroll
1484       by when you first start Apache.
1485
1486       For an example Apache 1.3 configuration, please see the documentation
1487       for Catalyst::Engine::Apache::MP13.
1488
1489       Test It
1490
1491       That's it, your app is now a full-fledged mod_perl application!  Try it
1492       out by going to http://your.server.com/.
1493
1494       Other Options
1495
1496       Non-root location
1497
1498       You may not always want to run your app at the root of your server or
1499       virtual host.  In this case, it's a simple change to run at any non-
1500       root location of your choice.
1501
1502           <Location /myapp>
1503               SetHandler          modperl
1504               PerlResponseHandler MyApp
1505           </Location>
1506
1507       When running this way, it is best to make use of the "uri_for" method
1508       in Catalyst for constructing correct links.
1509
1510       Static file handling
1511
1512       Static files can be served directly by Apache for a performance boost.
1513
1514           DocumentRoot /var/www/MyApp/root
1515           <Location /static>
1516               SetHandler default-handler
1517           </Location>
1518
1519       This will let all files within root/static be handled directly by
1520       Apache.  In a two-tiered setup, the frontend server should handle
1521       static files.  The configuration to do this on the frontend will vary.
1522
1523       Catalyst on shared hosting
1524
1525       So, you want to put your Catalyst app out there for the whole world to
1526       see, but you don't want to break the bank. There is an answer - if you
1527       can get shared hosting with FastCGI and a shell, you can install your
1528       Catalyst app in a local directory on your shared host. First, run
1529
1530           perl -MCPAN -e shell
1531
1532       and go through the standard CPAN configuration process. Then exit out
1533       without installing anything. Next, open your .bashrc and add
1534
1535           export PATH=$HOME/local/bin:$HOME/local/script:$PATH
1536           perlversion=`perl -v ⎪ grep 'built for' ⎪ awk '{print $4}' ⎪ sed -e 's/v//;'`
1537           export PERL5LIB=$HOME/local/share/perl/$perlversion:$HOME/local/lib/perl/$perlversion:$HOME/local/lib:$PERL5LIB
1538
1539       and log out, then back in again (or run ". .bashrc" if you prefer).
1540       Finally, edit ".cpan/CPAN/MyConfig.pm" and add
1541
1542           'make_install_arg' => qq[SITEPREFIX=$ENV{HOME}/local],
1543           'makepl_arg' => qq[INSTALLDIRS=site install_base=$ENV{HOME}/local],
1544
1545       Now you can install the modules you need using CPAN as normal; they
1546       will be installed into your local directory, and perl will pick them
1547       up. Finally, change directory into the root of your virtual host and
1548       symlink your application's script directory in:
1549
1550           cd path/to/mydomain.com
1551           ln -s ~/lib/MyApp/script script
1552
1553       And add the following lines to your .htaccess file (assuming the server
1554       is setup to handle .pl as fcgi - you may need to rename the script to
1555       myapp_fastcgi.fcgi and/or use a SetHandler directive):
1556
1557         RewriteEngine On
1558         RewriteCond %{REQUEST_URI} !^/?script/myapp_fastcgi.pl
1559         RewriteRule ^(.*)$ script/myapp_fastcgi.pl/$1 [PT,L]
1560
1561       Now "http://mydomain.com/" should now Just Work. Congratulations, now
1562       you can tell your friends about your new website (or in our case, tell
1563       the client it's time to pay the invoice :) )
1564
1565       FastCGI Deployment
1566
1567       FastCGI is a high-performance extension to CGI. It is suitable for pro‐
1568       duction environments.
1569
1570       Pros
1571
1572       Speed
1573
1574       FastCGI performs equally as well as mod_perl.  Don't let the 'CGI' fool
1575       you; your app runs as multiple persistent processes ready to receive
1576       connections from the web server.
1577
1578       App Server
1579
1580       When using external FastCGI servers, your application runs as a stand‐
1581       alone application server.  It may be restarted independently from the
1582       web server.  This allows for a more robust environment and faster
1583       reload times when pushing new app changes.  The frontend server can
1584       even be configured to display a friendly "down for maintenance" page
1585       while the application is restarting.
1586
1587       Load-balancing
1588
1589       You can launch your application on multiple backend servers and allow
1590       the frontend web server to load-balance between all of them.  And of
1591       course, if one goes down, your app continues to run fine.
1592
1593       Multiple versions of the same app
1594
1595       Each FastCGI application is a separate process, so you can run differ‐
1596       ent versions of the same app on a single server.
1597
1598       Can run with threaded Apache
1599
1600       Since your app is not running inside of Apache, the faster mpm_worker
1601       module can be used without worrying about the thread safety of your
1602       application.
1603
1604       Cons
1605
1606       More complex environment
1607
1608       With FastCGI, there are more things to monitor and more processes run‐
1609       ning than when using mod_perl.
1610
1611       Setup
1612
1613       1. Install Apache with mod_fastcgi
1614
1615       mod_fastcgi for Apache is a third party module, and can be found at
1616       <http://www.fastcgi.com/>.  It is also packaged in many distributions,
1617       for example, libapache2-mod-fastcgi in Debian.
1618
1619       2. Configure your application
1620
1621           # Serve static content directly
1622           DocumentRoot  /var/www/MyApp/root
1623           Alias /static /var/www/MyApp/root/static
1624
1625           FastCgiServer /var/www/MyApp/script/myapp_fastcgi.pl -processes 3
1626           Alias /myapp/ /var/www/MyApp/script/myapp_fastcgi.pl/
1627
1628           # Or, run at the root
1629           Alias / /var/www/MyApp/script/myapp_fastcgi.pl/
1630
1631       The above commands will launch 3 app processes and make the app avail‐
1632       able at /myapp/
1633
1634       Standalone server mode
1635
1636       While not as easy as the previous method, running your app as an exter‐
1637       nal server gives you much more flexibility.
1638
1639       First, launch your app as a standalone server listening on a socket.
1640
1641           script/myapp_fastcgi.pl -l /tmp/myapp.socket -n 5 -p /tmp/myapp.pid -d
1642
1643       You can also listen on a TCP port if your web server is not on the same
1644       machine.
1645
1646           script/myapp_fastcgi.pl -l :8080 -n 5 -p /tmp/myapp.pid -d
1647
1648       You will probably want to write an init script to handle starting/stop‐
1649       ping of the app using the pid file.
1650
1651       Now, we simply configure Apache to connect to the running server.
1652
1653           # 502 is a Bad Gateway error, and will occur if the backend server is down
1654           # This allows us to display a friendly static page that says "down for
1655           # maintenance"
1656           Alias /_errors /var/www/MyApp/root/error-pages
1657           ErrorDocument 502 /_errors/502.html
1658
1659           FastCgiExternalServer /tmp/myapp.fcgi -socket /tmp/myapp.socket
1660           Alias /myapp/ /tmp/myapp.fcgi/
1661
1662           # Or, run at the root
1663           Alias / /tmp/myapp.fcgi/
1664
1665       More Info
1666
1667       Catalyst::Engine::FastCGI.
1668
1669       Development server deployment
1670
1671       The development server is a mini web server written in perl.  If you
1672       expect a low number of hits or you don't need mod_perl/FastCGI speed,
1673       you could use the development server as the application server with a
1674       lightweight proxy web server at the front.  However, be aware that
1675       there are known issues, especially with Internet Explorer.  Many of
1676       these issues can be dealt with by running the server with the -k
1677       (keepalive) option but be aware for more complex applications this may
1678       not be suitable.  Consider using Catalyst::Engine::HTTP::POE.  This
1679       recipe is easily adapted for POE as well.
1680
1681       Pros
1682
1683       As this is an application server setup, the pros are the same as
1684       FastCGI (with the exception of speed).  It is also:
1685
1686       Simple
1687
1688       The development server is what you create your code on, so if it works
1689       here, it should work in production!
1690
1691       Cons
1692
1693       Speed
1694
1695       Not as fast as mod_perl or FastCGI. Needs to fork for each request that
1696       comes in - make sure static files are served by the web server to save
1697       forking.
1698
1699       Setup
1700
1701       Start up the development server
1702
1703          script/myapp_server.pl -p 8080 -k  -f -pidfile=/tmp/myapp.pid -daemon
1704
1705       You will probably want to write an init script to handle stop/starting
1706       the app using the pid file.
1707
1708       Configuring Apache
1709
1710       Make sure mod_proxy is enabled and add:
1711
1712           # Serve static content directly
1713           DocumentRoot /var/www/MyApp/root
1714           Alias /static /var/www/MyApp/root/static
1715
1716           ProxyRequests Off
1717           <Proxy *>
1718               Order deny,allow
1719               Allow from all
1720           </Proxy>
1721           ProxyPass / http://localhost:8080/
1722           ProxyPassReverse / http://localhost:8080/
1723
1724       You can wrap the above within a VirtualHost container if you want dif‐
1725       ferent apps served on the same host.
1726
1727       Quick deployment: Building PAR Packages
1728
1729       You have an application running on your development box, but then you
1730       have to quickly move it to another one for demonstration/deploy‐
1731       ment/testing...
1732
1733       PAR packages can save you from a lot of trouble here. They are usual
1734       Zip files that contain a blib tree; you can even include all prereqs
1735       and a perl interpreter by setting a few flags!
1736
1737       Follow these few points to try it out!
1738
1739       1. Install Catalyst and PAR 0.89 (or later)
1740
1741           % perl -MCPAN -e 'install Catalyst'
1742           ...
1743           % perl -MCPAN -e 'install PAR'
1744           ...
1745
1746       2. Create a application
1747
1748           % catalyst.pl MyApp
1749           ...
1750           % cd MyApp
1751
1752       Recent versions of Catalyst (5.62 and up) include Module::Install::Cat‐
1753       alyst, which simplifies the process greatly.  From the shell in your
1754       application directory:
1755
1756           % perl Makefile.PL
1757           % make catalyst_par
1758
1759       Congratulations! Your package "myapp.par" is ready, the following steps
1760       are just optional.
1761
1762       3. Test your PAR package with "parl" (no typo)
1763
1764           % parl myapp.par
1765           Usage:
1766               [parl] myapp[.par] [script] [arguments]
1767
1768             Examples:
1769               parl myapp.par myapp_server.pl -r
1770               myapp myapp_cgi.pl
1771
1772             Available scripts:
1773               myapp_cgi.pl
1774               myapp_create.pl
1775               myapp_fastcgi.pl
1776               myapp_server.pl
1777               myapp_test.pl
1778
1779           % parl myapp.par myapp_server.pl
1780           You can connect to your server at http://localhost:3000
1781
1782       Yes, this nifty little starter application gets automatically included.
1783       You can also use "catalyst_par_script('myapp_server.pl')" to set a
1784       default script to execute.
1785
1786       6. Want to create a binary that includes the Perl interpreter?
1787
1788           % pp -o myapp myapp.par
1789           % ./myapp myapp_server.pl
1790           You can connect to your server at http://localhost:3000
1791
1792       Serving static content
1793
1794       Serving static content in Catalyst used to be somewhat tricky; the use
1795       of Catalyst::Plugin::Static::Simple makes everything much easier.  This
1796       plugin will automatically serve your static content during development,
1797       but allows you to easily switch to Apache (or other server) in a pro‐
1798       duction environment.
1799
1800       Introduction to Static::Simple
1801
1802       Static::Simple is a plugin that will help to serve static content for
1803       your application. By default, it will serve most types of files,
1804       excluding some standard Template Toolkit extensions, out of your root
1805       file directory. All files are served by path, so if images/me.jpg is
1806       requested, then root/images/me.jpg is found and served.
1807
1808       Usage
1809
1810       Using the plugin is as simple as setting your use line in MyApp.pm to
1811       include:
1812
1813        use Catalyst qw/Static::Simple/;
1814
1815       and already files will be served.
1816
1817       Configuring
1818
1819       Static content is best served from a single directory within your root
1820       directory. Having many different directories such as "root/css" and
1821       "root/images" requires more code to manage, because you must separately
1822       identify each static directory--if you decide to add a "root/js" direc‐
1823       tory, you'll need to change your code to account for it. In contrast,
1824       keeping all static directories as subdirectories of a main
1825       "root/static" directory makes things much easier to manage. Here's an
1826       example of a typical root directory structure:
1827
1828           root/
1829           root/content.tt
1830           root/controller/stuff.tt
1831           root/header.tt
1832           root/static/
1833           root/static/css/main.css
1834           root/static/images/logo.jpg
1835           root/static/js/code.js
1836
1837       All static content lives under "root/static", with everything else
1838       being Template Toolkit files.
1839
1840       Include Path
1841           You may of course want to change the default locations, and make
1842           Static::Simple look somewhere else, this is as easy as:
1843
1844            MyApp->config->{static}->{include_path} = [
1845             MyApp->config->{root},
1846             '/path/to/my/files'
1847            ];
1848
1849           When you override include_path, it will not automatically append
1850           the normal root path, so you need to add it yourself if you still
1851           want it. These will be searched in order given, and the first
1852           matching file served.
1853
1854       Static directories
1855           If you want to force some directories to be only static, you can
1856           set them using paths relative to the root dir, or regular expres‐
1857           sions:
1858
1859            MyApp->config->{static}->{dirs} = [
1860              'static',
1861              qr/^(images⎪css)/,
1862            ];
1863
1864       File extensions
1865           By default, the following extensions are not served (that is, they
1866           will be processed by Catalyst): tmpl, tt, tt2, html, xhtml. This
1867           list can be replaced easily:
1868
1869            MyApp->config->{static}->{ignore_extensions} = [
1870               qw/tmpl tt tt2 html xhtml/
1871            ];
1872
1873       Ignoring directories
1874           Entire directories can be ignored. If used with include_path,
1875           directories relative to the include_path dirs will also be ignored:
1876
1877            MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
1878
1879       More information
1880
1881       <http://search.cpan.org/dist/Catalyst-Plugin-Static-Simple/>
1882
1883       Serving manually with the Static plugin with HTTP::Daemon
1884       (myapp_server.pl)
1885
1886       In some situations you might want to control things more directly,
1887       using Catalyst::Plugin::Static.
1888
1889       In your main application class (MyApp.pm), load the plugin:
1890
1891           use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
1892
1893       You will also need to make sure your end method does not forward static
1894       content to the view, perhaps like this:
1895
1896           sub end : Private {
1897               my ( $self, $c ) = @_;
1898
1899               $c->forward( 'MyApp::View::TT' )
1900                 unless ( $c->res->body ⎪⎪ !$c->stash->{template} );
1901           }
1902
1903       This code will only forward to the view if a template has been previ‐
1904       ously defined by a controller and if there is not already data in
1905       "$c->res->body".
1906
1907       Next, create a controller to handle requests for the /static path. Use
1908       the Helper to save time. This command will create a stub controller as
1909       "lib/MyApp/Controller/Static.pm".
1910
1911           $ script/myapp_create.pl controller Static
1912
1913       Edit the file and add the following methods:
1914
1915           # serve all files under /static as static files
1916           sub default : Path('/static') {
1917               my ( $self, $c ) = @_;
1918
1919               # Optional, allow the browser to cache the content
1920               $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
1921
1922               $c->serve_static; # from Catalyst::Plugin::Static
1923           }
1924
1925           # also handle requests for /favicon.ico
1926           sub favicon : Path('/favicon.ico') {
1927               my ( $self, $c ) = @_;
1928
1929               $c->serve_static;
1930           }
1931
1932       You can also define a different icon for the browser to use instead of
1933       favicon.ico by using this in your HTML header:
1934
1935           <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
1936
1937       Common problems with the Static plugin
1938
1939       The Static plugin makes use of the "shared-mime-info" package to auto‐
1940       matically determine MIME types. This package is notoriously difficult
1941       to install, especially on win32 and OS X. For OS X the easiest path
1942       might be to install Fink, then use "apt-get install shared-mime-info".
1943       Restart the server, and everything should be fine.
1944
1945       Make sure you are using the latest version (>= 0.16) for best results.
1946       If you are having errors serving CSS files, or if they get served as
1947       text/plain instead of text/css, you may have an outdated shared-mime-
1948       info version. You may also wish to simply use the following code in
1949       your Static controller:
1950
1951           if ($c->req->path =~ /css$/i) {
1952               $c->serve_static( "text/css" );
1953           } else {
1954               $c->serve_static;
1955           }
1956
1957       Serving Static Files with Apache
1958
1959       When using Apache, you can bypass Catalyst and any Static plugins/con‐
1960       trollers controller by intercepting requests for the "root/static" path
1961       at the server level. All that is required is to define a DocumentRoot
1962       and add a separate Location block for your static content. Here is a
1963       complete config for this application under mod_perl 1.x:
1964
1965           <Perl>
1966               use lib qw(/var/www/MyApp/lib);
1967           </Perl>
1968           PerlModule MyApp
1969
1970           <VirtualHost *>
1971               ServerName myapp.example.com
1972               DocumentRoot /var/www/MyApp/root
1973               <Location />
1974                   SetHandler perl-script
1975                   PerlHandler MyApp
1976               </Location>
1977               <LocationMatch "/(static⎪favicon.ico)">
1978                   SetHandler default-handler
1979               </LocationMatch>
1980           </VirtualHost>
1981
1982       And here's a simpler example that'll get you started:
1983
1984           Alias /static/ "/my/static/files/"
1985           <Location "/static">
1986               SetHandler none
1987           </Location>
1988
1989       Caching
1990
1991       Catalyst makes it easy to employ several different types of caching to
1992       speed up your applications.
1993
1994       Cache Plugins
1995
1996       There are three wrapper plugins around common CPAN cache modules:
1997       Cache::FastMmap, Cache::FileCache, and Cache::Memcached.  These can be
1998       used to cache the result of slow operations.
1999
2000       This very page you're viewing makes use of the FileCache plugin to
2001       cache the rendered XHTML version of the source POD document.  This is
2002       an ideal application for a cache because the source document changes
2003       infrequently but may be viewed many times.
2004
2005           use Catalyst qw/Cache::FileCache/;
2006
2007           ...
2008
2009           use File::stat;
2010           sub render_pod : Local {
2011               my ( self, $c ) = @_;
2012
2013               # the cache is keyed on the filename and the modification time
2014               # to check for updates to the file.
2015               my $file  = $c->path_to( 'root', '2005', '11.pod' );
2016               my $mtime = ( stat $file )->mtime;
2017
2018               my $cached_pod = $c->cache->get("$file $mtime");
2019               if ( !$cached_pod ) {
2020                   $cached_pod = do_slow_pod_rendering();
2021                   # cache the result for 12 hours
2022                   $c->cache->set( "$file $mtime", $cached_pod, '12h' );
2023               }
2024               $c->stash->{pod} = $cached_pod;
2025           }
2026
2027       We could actually cache the result forever, but using a value such as
2028       12 hours allows old entries to be automatically expired when they are
2029       no longer needed.
2030
2031       Page Caching
2032
2033       Another method of caching is to cache the entire HTML page.  While this
2034       is traditionally handled by a front-end proxy server like Squid, the
2035       Catalyst PageCache plugin makes it trivial to cache the entire output
2036       from frequently-used or slow actions.
2037
2038       Many sites have a busy content-filled front page that might look some‐
2039       thing like this.  It probably takes a while to process, and will do the
2040       exact same thing for every single user who views the page.
2041
2042           sub front_page : Path('/') {
2043               my ( $self, $c ) = @_;
2044
2045               $c->forward( 'get_news_articles' );
2046               $c->forward( 'build_lots_of_boxes' );
2047               $c->forward( 'more_slow_stuff' );
2048
2049               $c->stash->{template} = 'index.tt';
2050           }
2051
2052       We can add the PageCache plugin to speed things up.
2053
2054           use Catalyst qw/Cache::FileCache PageCache/;
2055
2056           sub front_page : Path ('/') {
2057               my ( $self, $c ) = @_;
2058
2059               $c->cache_page( 300 );
2060
2061               # same processing as above
2062           }
2063
2064       Now the entire output of the front page, from <html> to </html>, will
2065       be cached for 5 minutes.  After 5 minutes, the next request will
2066       rebuild the page and it will be re-cached.
2067
2068       Note that the page cache is keyed on the page URI plus all parameters,
2069       so requests for / and /?foo=bar will result in different cache items.
2070       Also, only GET requests will be cached by the plugin.
2071
2072       You can even get that front-end Squid proxy to help out by enabling
2073       HTTP headers for the cached page.
2074
2075           MyApp->config->{page_cache}->{set_http_headers} = 1;
2076
2077       This would now set the following headers so proxies and browsers may
2078       cache the content themselves.
2079
2080           Cache-Control: max-age=($expire_time - time)
2081           Expires: $expire_time
2082           Last-Modified: $cache_created_time
2083
2084       Template Caching
2085
2086       Template Toolkit provides support for caching compiled versions of your
2087       templates.  To enable this in Catalyst, use the following configura‐
2088       tion.  TT will cache compiled templates keyed on the file mtime, so
2089       changes will still be automatically detected.
2090
2091           package MyApp::View::TT;
2092
2093           use strict;
2094           use warnings;
2095           use base 'Catalyst::View::TT';
2096
2097           __PACKAGE__->config(
2098               COMPILE_DIR => '/tmp/template_cache',
2099           );
2100
2101           1;
2102
2103       More Info
2104
2105       See the documentation for each cache plugin for more details and other
2106       available configuration options.
2107
2108       Catalyst::Plugin::Cache::FastMmap Catalyst::Plugin::Cache::FileCache
2109       Catalyst::Plugin::Cache::Memcached Catalyst::Plugin::PageCache
2110       <http://search.cpan.org/dist/Template-Toolkit/lib/Template/Manual/Con
2111       fig.pod#Caching_and_Compiling_Options>
2112

Testing

2114       Testing is an integral part of the web application development process.
2115       Tests make multi developer teams easier to coordinate, and they help
2116       ensure that there are no nasty surprises after upgrades or alterations.
2117
2118       Testing
2119
2120       Catalyst provides a convenient way of testing your application during
2121       development and before deployment in a real environment.
2122
2123       "Catalyst::Test" makes it possible to run the same tests both locally
2124       (without an external daemon) and against a remote server via HTTP.
2125
2126       Tests
2127
2128       Let's examine a skeleton application's "t/" directory:
2129
2130           mundus:~/MyApp chansen$ ls -l t/
2131           total 24
2132           -rw-r--r--  1 chansen  chansen   95 18 Dec 20:50 01app.t
2133           -rw-r--r--  1 chansen  chansen  190 18 Dec 20:50 02pod.t
2134           -rw-r--r--  1 chansen  chansen  213 18 Dec 20:50 03podcoverage.t
2135
2136       "01app.t"
2137           Verifies that the application loads, compiles, and returns a suc‐
2138           cessful response.
2139
2140       "02pod.t"
2141           Verifies that all POD is free from errors. Only executed if the
2142           "TEST_POD" environment variable is true.
2143
2144       "03podcoverage.t"
2145           Verifies that all methods/functions have POD coverage. Only exe‐
2146           cuted if the "TEST_POD" environment variable is true.
2147
2148       Creating tests
2149
2150           mundus:~/MyApp chansen$ cat t/01app.t ⎪ perl -ne 'printf( "%2d  %s", $., $_ )'
2151           1  use Test::More tests => 2;
2152           2  use_ok( Catalyst::Test, 'MyApp' );
2153           3
2154           4  ok( request('/')->is_success );
2155
2156       The first line declares how many tests we are going to run, in this
2157       case two. The second line tests and loads our application in test mode.
2158       The fourth line verifies that our application returns a successful
2159       response.
2160
2161       "Catalyst::Test" exports two functions, "request" and "get". Each can
2162       take three different arguments:
2163
2164       A string which is a relative or absolute URI.
2165               request('/my/path');
2166               request('http://www.host.com/my/path');
2167
2168       An instance of "URI".
2169               request( URI->new('http://www.host.com/my/path') );
2170
2171       An instance of "HTTP::Request".
2172               request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
2173
2174       "request" returns an instance of "HTTP::Response" and "get" returns the
2175       content (body) of the response.
2176
2177       Running tests locally
2178
2179           mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
2180           t/01app............ok
2181           t/02pod............ok
2182           t/03podcoverage....ok
2183           All tests successful.
2184           Files=3, Tests=4,  2 wallclock secs ( 1.60 cusr +  0.36 csys =  1.96 CPU)
2185
2186       "CATALYST_DEBUG=0" ensures that debugging is off; if it's enabled you
2187       will see debug logs between tests.
2188
2189       "TEST_POD=1" enables POD checking and coverage.
2190
2191       "prove" A command-line tool that makes it easy to run tests. You can
2192       find out more about it from the links below.
2193
2194       Running tests remotely
2195
2196           mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
2197           t/01app....ok
2198           All tests successful.
2199           Files=1, Tests=2,  0 wallclock secs ( 0.40 cusr +  0.01 csys =  0.41 CPU)
2200
2201       "CATALYST_SERVER=http://localhost:3000/" is the absolute deployment URI
2202       of your application. In "CGI" or "FastCGI" it should be the host and
2203       path to the script.
2204
2205       "Test::WWW::Mechanize" and Catalyst
2206
2207       Be sure to check out "Test::WWW::Mechanize::Catalyst". It makes it easy
2208       to test HTML, forms and links. A short example of usage:
2209
2210           use Test::More tests => 6;
2211           use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' );
2212
2213           my $mech = Test::WWW::Mechanize::Catalyst->new;
2214           $mech->get_ok("http://localhost/", 'Got index page');
2215           $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
2216           ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
2217           ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
2218           ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
2219
2220       Further Reading
2221
2222       Catalyst::Test
2223           <http://search.cpan.org/dist/Catalyst/lib/Catalyst/Test.pm>
2224
2225       Test::WWW::Mechanize::Catalyst
2226           <http://search.cpan.org/dist/Test-WWW-Mechanize-Cata
2227           lyst/lib/Test/WWW/Mechanize/Catalyst.pm>
2228
2229       Test::WWW::Mechanize
2230           <http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm>
2231
2232       WWW::Mechanize
2233           <http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm>
2234
2235       LWP::UserAgent
2236           <http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm>
2237
2238       HTML::Form
2239           <http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm>
2240
2241       HTTP::Message
2242           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm>
2243
2244       HTTP::Request
2245           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm>
2246
2247       HTTP::Request::Common
2248           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request/Com
2249           mon.pm>
2250
2251       HTTP::Response
2252           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm>
2253
2254       HTTP::Status
2255           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm>
2256
2257       URI <http://search.cpan.org/dist/URI/URI.pm>
2258
2259       Test::More
2260           <http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm>
2261
2262       Test::Pod
2263           <http://search.cpan.org/dist/Test-Pod/Pod.pm>
2264
2265       Test::Pod::Coverage
2266           <http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm>
2267
2268       prove (Test::Harness)
2269           <http://search.cpan.org/dist/Test-Harness/bin/prove>
2270
2271       More Information
2272
2273       <http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::Roles>
2274       <http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::ACL>
2275

AUTHORS

2277       Sebastian Riedel "sri@oook.de"
2278
2279       Danijel Milicevic "me@danijel.de"
2280
2281       Viljo Marrandi "vilts@yahoo.com"
2282
2283       Marcus Ramberg "mramberg@cpan.org"
2284
2285       Jesse Sheidlower "jester@panix.com"
2286
2287       Andy Grundman "andy@hybridized.org"
2288
2289       Chisel Wright "pause@herlpacker.co.uk"
2290
2291       Will Hawes "info@whawes.co.uk"
2292
2293       Gavin Henry "ghenry@perl.me.uk"
2294
2295       Kieren Diment "kd@totaldatasolution.com"
2296
2298       This document is free, you can redistribute it and/or modify it under
2299       the same terms as Perl itself.
2300
2301
2302
2303perl v5.8.8                       2007-02-28     Catalyst::Manual::Cookbook(3)
Impressum