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

Skipping your VCS's directories

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

Users and Access Control

235       Most multiuser, and some single-user web applications require that
236       users identify themselves, and the application is often required to
237       define those roles.  The recipes below describe some ways of doing
238       this.
239
240   Authentication (logging in)
241       This is extensively covered in other documentation; see in particular
242       Catalyst::Plugin::Authentication and the Authentication chapter of the
243       Tutorial at Catalyst::Manual::Tutorial::06_Authorization.
244
245   Pass-through login (and other actions)
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   Authentication/Authorization
262       This is done in several steps:
263
264       Verification
265           Getting the user to identify themselves, by giving you some piece
266           of information known only to you and the user. Then you can assume
267           that the user is who they say they are. This is called credential
268           verification.
269
270       Authorization
271           Making sure the user only accesses functions you want them to
272           access. This is done by checking the verified user's data against
273           your internal list of groups, or allowed persons for the current
274           page.
275
276       Modules
277
278       The Catalyst Authentication system is made up of many interacting
279       modules, to give you the most flexibility possible.
280
281       Credential verifiers
282
283       A Credential module tables the user input, and passes it to a Store, or
284       some other system, for verification. Typically, a user object is
285       created by either this module or the Store and made accessible by a
286       "$c->user" call.
287
288       Examples:
289
290        Password - Simple username/password checking.
291        HTTPD    - Checks using basic HTTP auth.
292        TypeKey  - Check using the typekey system.
293
294       Storage backends
295
296       A Storage backend contains the actual data representing the users. It
297       is queried by the credential verifiers. Updating the store is not done
298       within this system; you will need to do it yourself.
299
300       Examples:
301
302        DBIC     - Storage using a database via DBIx::Class.
303        Minimal  - Storage using a simple hash (for testing).
304
305       User objects
306
307       A User object is created by either the storage backend or the
308       credential verifier, and is filled with the retrieved user information.
309
310       Examples:
311
312        Hash     - A simple hash of keys and values.
313
314       ACL authorization
315
316       ACL stands for Access Control List. The ACL plugin allows you to
317       regulate access on a path-by-path basis, by listing which users, or
318       roles, have access to which paths.
319
320       Roles authorization
321
322       Authorization by roles is for assigning users to groups, which can then
323       be assigned to ACLs, or just checked when needed.
324
325       Logging in
326
327       When you have chosen your modules, all you need to do is call the
328       "$c->authenticate" method. If called with no parameters, it will try to
329       find suitable parameters, such as username and password, or you can
330       pass it these values.
331
332       Checking roles
333
334       Role checking is done by using the "$c->check_user_roles" method.  This
335       will check using the currently logged-in user (via "$c->user"). You
336       pass it the name of a role to check, and it returns true if the user is
337       a member.
338
339       EXAMPLE
340
341         package MyApp;
342         use Moose;
343         use namespace::autoclean;
344         extends qw/Catalyst/;
345         use Catalyst qw/
346           Authentication
347           Authorization::Roles
348         /;
349
350         __PACKAGE__->config(
351            authentication => {
352                default_realm => 'test',
353                realms => {
354                    test => {
355                        credential => {
356                            class          => 'Password',
357                            password_field => 'password',
358                            password_type  => 'self_check',
359                        },
360                        store => {
361                            class => 'Htpasswd',
362                            file => 'htpasswd',
363                        },
364                    },
365                },
366            },
367         );
368
369         package MyApp::Controller::Root;
370         use Moose;
371         use namespace::autoclean;
372
373         BEGIN { extends 'Catalyst::Controller' }
374
375         __PACKAGE__->config(namespace => '');
376
377         sub login : Local {
378            my ($self, $c) = @_;
379
380            if (    my $user = $c->req->param("user")
381                and my $password = $c->req->param("password") )
382            {
383                if ( $c->authenticate( username => $user, password => $password ) ) {
384                     $c->res->body( "hello " . $c->user->name );
385                } else {
386                   # login incorrect
387                }
388            }
389            else {
390                # invalid form input
391            }
392         }
393
394         sub restricted : Local {
395            my ( $self, $c ) = @_;
396
397            $c->detach("unauthorized")
398              unless $c->check_user_roles( "admin" );
399
400            # do something restricted here
401         }
402
403       Using authentication in a testing environment
404
405       Ideally, to write tests for authentication/authorization code one would
406       first set up a test database with known data, then use
407       Test::WWW::Mechanize::Catalyst to simulate a user logging in.
408       Unfortunately this can be rather awkward, which is why it's a good
409       thing that the authentication framework is so flexible.
410
411       Instead of using a test database, one can simply change the
412       authentication store to something a bit easier to deal with in a
413       testing environment. Additionally, this has the advantage of not
414       modifying one's database, which can be problematic if one forgets to
415       use the testing instead of production database.
416
417       Alternatively, if you want to authenticate real users, but not have to
418       worry about their passwords, you can use
419       Catalyst::Authentication::Credential::Testing to force all users to
420       authenticate with a global password.
421
422       More information
423
424       Catalyst::Plugin::Authentication has a longer explanation.
425
426   Authorization
427       Introduction
428
429       Authorization is the step that comes after authentication.
430       Authentication establishes that the user agent is really representing
431       the user we think it's representing, and then authorization determines
432       what this user is allowed to do.
433
434       Role Based Access Control
435
436       Under role based access control each user is allowed to perform any
437       number of roles. For example, at a zoo no one but specially trained
438       personnel can enter the moose cage (Mynd you, mA~XA~Xse bites kan be
439       pretty nasti!). For example:
440
441           package Zoo::Controller::MooseCage;
442
443           sub feed_moose : Local {
444               my ( $self, $c ) = @_;
445
446               $c->model( "Moose" )->eat( $c->req->param("food") );
447           }
448
449       With this action, anyone can just come into the moose cage and feed the
450       moose, which is a very dangerous thing. We need to restrict this
451       action, so that only a qualified moose feeder can perform that action.
452
453       The Authorization::Roles plugin lets us perform role based access
454       control checks. Let's load it:
455
456           use parent qw/Catalyst/;
457           use Catalyst qw/
458                           Authentication
459                           Authorization::Roles
460                         /;
461
462       And now our action should look like this:
463
464           sub feed_moose : Local {
465               my ( $self, $c ) = @_;
466
467               if ( $c->check_roles( "moose_feeder" ) ) {
468                   $c->model( "Moose" )->eat( $c->req->param("food") );
469               } else {
470                   $c->stash->{error} = "unauthorized";
471               }
472           }
473
474       This checks "$c->user", and only if the user has all the roles in the
475       list, a true value is returned.
476
477       "check_roles" has a sister method, "assert_roles", which throws an
478       exception if any roles are missing.
479
480       Some roles that might actually make sense in, say, a forum application:
481
482       ·   administrator
483
484       ·   moderator
485
486       each with a distinct task (system administration versus content
487       administration).
488
489       Access Control Lists
490
491       Checking for roles all the time can be tedious and error prone.
492
493       The Authorization::ACL plugin lets us declare where we'd like checks to
494       be done automatically for us.
495
496       For example, we may want to completely block out anyone who isn't a
497       "moose_feeder" from the entire "MooseCage" controller:
498
499           Zoo->deny_access_unless( "/moose_cage", [qw/moose_feeder/] );
500
501       The role list behaves in the same way as "check_roles". However, the
502       ACL plugin isn't limited to just interacting with the Roles plugin. We
503       can use a code reference instead. For example, to allow either moose
504       trainers or moose feeders into the moose cage, we can create a more
505       complex check:
506
507           Zoo->deny_access_unless( "/moose_cage", sub {
508               my $c = shift;
509               $c->check_roles( "moose_trainer" ) || $c->check_roles( "moose_feeder" );
510           });
511
512       The more specific a role, the earlier it will be checked. Let's say
513       moose feeders are now restricted to only the "feed_moose" action, while
514       moose trainers get access everywhere:
515
516           Zoo->deny_access_unless( "/moose_cage", [qw/moose_trainer/] );
517           Zoo->allow_access_if( "/moose_cage/feed_moose", [qw/moose_feeder/]);
518
519       When the "feed_moose" action is accessed the second check will be made.
520       If the user is a "moose_feeder", then access will be immediately
521       granted. Otherwise, the next rule in line will be tested - the one
522       checking for a "moose_trainer".  If this rule is not satisfied, access
523       will be immediately denied.
524
525       Rules applied to the same path will be checked in the order they were
526       added.
527
528       Lastly, handling access denial events is done by creating an
529       "access_denied" private action:
530
531           sub access_denied : Private {
532               my ( $self, $c, $action ) = @_;
533           }
534
535       This action works much like auto, in that it is inherited across
536       namespaces (not like object oriented code). This means that the
537       "access_denied" action which is nearest to the action which was blocked
538       will be triggered.
539
540       If this action does not exist, an error will be thrown, which you can
541       clean up in your "end" private action instead.
542
543       Also, it's important to note that if you restrict access to "/" then
544       "end", "default", etc. will also be restricted.
545
546          MyApp->acl_allow_root_internals;
547
548       will create rules that permit access to "end", "begin", and "auto" in
549       the root of your app (but not in any other controller).
550

Models

552       Models are where application data belongs.  Catalyst is exteremely
553       flexible with the kind of models that it can use.  The recipes here are
554       just the start.
555
556   Using existing DBIC (etc.) classes with Catalyst
557       Many people have existing Model classes that they would like to use
558       with Catalyst (or, conversely, they want to write Catalyst models that
559       can be used outside of Catalyst, e.g.  in a cron job). It's trivial to
560       write a simple component in Catalyst that slurps in an outside Model:
561
562           package MyApp::Model::DB;
563
564           use base qw/Catalyst::Model::DBIC::Schema/;
565
566           __PACKAGE__->config(
567               schema_class => 'Some::DBIC::Schema',
568               connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}];
569           );
570
571           1;
572
573       and that's it! Now "Some::DBIC::Schema" is part of your Cat app as
574       "MyApp::Model::DB".
575
576   DBIx::Class as a Catalyst Model
577       See Catalyst::Model::DBIC::Schema.
578
579   Create accessors to preload static data once per server instance
580       When you have data that you want to load just once from the model at
581       startup, instead of for each request, use mk_group_accessors to create
582       accessors and tie them to resultsets in your package that inherits from
583       DBIx::Class::Schema:
584
585           package My::Schema;
586           use base qw/DBIx::Class::Schema/;
587           __PACKAGE__->register_class('RESULTSOURCEMONIKER',
588                                       'My::Schema::RESULTSOURCE');
589           __PACKAGE__->mk_group_accessors('simple' =>
590                                       qw(ACCESSORNAME1 ACCESSORNAME2 ACCESSORNAMEn));
591
592           sub connection {
593               my ($self, @rest) = @_;
594               $self->next::method(@rest);
595               # $self is now a live My::Schema object, complete with DB connection
596
597               $self->ACCESSORNAME1([ $self->resultset('RESULTSOURCEMONIKER')->all ]);
598               $self->ACCESSORNAME2([ $self->resultset('RESULTSOURCEMONIKER')->search({ COLUMN => { '<' => '30' } })->all ]);
599               $self->ACCESSORNAMEn([ $self->resultset('RESULTSOURCEMONIKER')->find(1) ]);
600           }
601
602           1;
603
604       and now in the controller, you can now access any of these without a
605       per-request fetch:
606
607           $c->stash->{something} = $c->model('My::Schema')->schema->ACCESSORNAME;
608
609   XMLRPC
610       Unlike SOAP, XMLRPC is a very simple (and elegant) web-services
611       protocol, exchanging small XML messages like these:
612
613       Request:
614
615           POST /api HTTP/1.1
616           TE: deflate,gzip;q=0.3
617           Connection: TE, close
618           Accept: text/xml
619           Accept: multipart/*
620           Host: 127.0.0.1:3000
621           User-Agent: SOAP::Lite/Perl/0.60
622           Content-Length: 192
623           Content-Type: text/xml
624
625           <?xml version="1.0" encoding="UTF-8"?>
626           <methodCall>
627               <methodName>add</methodName>
628               <params>
629                   <param><value><int>1</int></value></param>
630                   <param><value><int>2</int></value></param>
631               </params>
632           </methodCall>
633
634       Response:
635
636           Connection: close
637           Date: Tue, 20 Dec 2005 07:45:55 GMT
638           Content-Length: 133
639           Content-Type: text/xml
640           Status: 200
641           X-Catalyst: 5.70
642
643           <?xml version="1.0" encoding="us-ascii"?>
644           <methodResponse>
645               <params>
646                   <param><value><int>3</int></value></param>
647               </params>
648           </methodResponse>
649
650       Now follow these few steps to implement the application:
651
652       1. Install Catalyst (5.61 or later), Catalyst::Plugin::XMLRPC (0.06 or
653       later) and SOAP::Lite (for XMLRPCsh.pl).
654
655       2. Create an application framework:
656
657           % catalyst.pl MyApp
658           ...
659           % cd MyApp
660
661       3. Add the XMLRPC plugin to MyApp.pm
662
663           use Catalyst qw/-Debug Static::Simple XMLRPC/;
664
665       4. Add an API controller
666
667           % ./script/myapp_create.pl controller API
668
669       5. Add a XMLRPC redispatch method and an add method with Remote
670       attribute to lib/MyApp/Controller/API.pm
671
672           sub default :Path {
673               my ( $self, $c ) = @_;
674               $c->xmlrpc;
675           }
676
677           sub add : Remote {
678               my ( $self, $c, $a, $b ) = @_;
679               return $a + $b;
680           }
681
682       The default action is the entry point for each XMLRPC request. It will
683       redispatch every request to methods with Remote attribute in the same
684       class.
685
686       The "add" method is not a traditional action; it has no private or
687       public path. Only the XMLRPC dispatcher knows it exists.
688
689       6. That's it! You have built your first web service. Let's test it with
690       XMLRPCsh.pl (part of SOAP::Lite):
691
692           % ./script/myapp_server.pl
693           ...
694           % XMLRPCsh.pl http://127.0.0.1:3000/api
695           Usage: method[(parameters)]
696           > add( 1, 2 )
697           --- XMLRPC RESULT ---
698           '3'
699
700       Tip
701
702       Your return data type is usually auto-detected, but you can easily
703       enforce a specific one.
704
705           sub add : Remote {
706               my ( $self, $c, $a, $b ) = @_;
707               return RPC::XML::int->new( $a + $b );
708           }
709

Views

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

Controllers

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

Deployment

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

Testing

2227       Testing is an integral part of the web application development process.
2228       Tests make multi developer teams easier to coordinate, and they help
2229       ensure that there are no nasty surprises after upgrades or alterations.
2230
2231   Testing
2232       Catalyst provides a convenient way of testing your application during
2233       development and before deployment in a real environment.
2234
2235       "Catalyst::Test" makes it possible to run the same tests both locally
2236       (without an external daemon) and against a remote server via HTTP.
2237
2238       Tests
2239
2240       Let's examine a skeleton application's "t/" directory:
2241
2242           mundus:~/MyApp chansen$ ls -l t/
2243           total 24
2244           -rw-r--r--  1 chansen  chansen   95 18 Dec 20:50 01app.t
2245           -rw-r--r--  1 chansen  chansen  190 18 Dec 20:50 02pod.t
2246           -rw-r--r--  1 chansen  chansen  213 18 Dec 20:50 03podcoverage.t
2247
2248       "01app.t"
2249           Verifies that the application loads, compiles, and returns a
2250           successful response.
2251
2252       "02pod.t"
2253           Verifies that all POD is free from errors. Only executed if the
2254           "TEST_POD" environment variable is true.
2255
2256       "03podcoverage.t"
2257           Verifies that all methods/functions have POD coverage. Only
2258           executed if the "TEST_POD" environment variable is true.
2259
2260       Creating tests
2261
2262           mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d  %s", $., $_ )'
2263           1  use Test::More tests => 2;
2264           2  use_ok( Catalyst::Test, 'MyApp' );
2265           3
2266           4  ok( request('/')->is_success );
2267
2268       The first line declares how many tests we are going to run, in this
2269       case two. The second line tests and loads our application in test mode.
2270       The fourth line verifies that our application returns a successful
2271       response.
2272
2273       "Catalyst::Test" exports two functions, "request" and "get". Each can
2274       take three different arguments:
2275
2276       A string which is a relative or absolute URI.
2277               request('/my/path');
2278               request('http://www.host.com/my/path');
2279
2280       An instance of "URI".
2281               request( URI->new('http://www.host.com/my/path') );
2282
2283       An instance of "HTTP::Request".
2284               request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
2285
2286       "request" returns an instance of "HTTP::Response" and "get" returns the
2287       content (body) of the response.
2288
2289       Running tests locally
2290
2291           mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
2292           t/01app............ok
2293           t/02pod............ok
2294           t/03podcoverage....ok
2295           All tests successful.
2296           Files=3, Tests=4,  2 wallclock secs ( 1.60 cusr +  0.36 csys =  1.96 CPU)
2297
2298       "CATALYST_DEBUG=0" ensures that debugging is off; if it's enabled you
2299       will see debug logs between tests.
2300
2301       "TEST_POD=1" enables POD checking and coverage.
2302
2303       "prove" A command-line tool that makes it easy to run tests. You can
2304       find out more about it from the links below.
2305
2306       Running tests remotely
2307
2308           mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
2309           t/01app....ok
2310           All tests successful.
2311           Files=1, Tests=2,  0 wallclock secs ( 0.40 cusr +  0.01 csys =  0.41 CPU)
2312
2313       "CATALYST_SERVER=http://localhost:3000/" is the absolute deployment URI
2314       of your application. In "CGI" or "FastCGI" it should be the host and
2315       path to the script.
2316
2317       "Test::WWW::Mechanize" and Catalyst
2318
2319       Be sure to check out "Test::WWW::Mechanize::Catalyst". It makes it easy
2320       to test HTML, forms and links. A short example of usage:
2321
2322           use Test::More tests => 6;
2323           use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' );
2324
2325           my $mech = Test::WWW::Mechanize::Catalyst->new;
2326           $mech->get_ok("http://localhost/", 'Got index page');
2327           $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
2328           ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
2329           ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
2330           ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
2331
2332       Further Reading
2333
2334       Catalyst::Test
2335           <http://search.cpan.org/dist/Catalyst/lib/Catalyst/Test.pm>
2336
2337       Test::WWW::Mechanize::Catalyst
2338           http://search.cpan.org/dist/Test-WWW-Mechanize-Catalyst/lib/Test/WWW/Mechanize/Catalyst.pm
2339           <http://search.cpan.org/dist/Test-WWW-Mechanize-
2340           Catalyst/lib/Test/WWW/Mechanize/Catalyst.pm>
2341
2342       Test::WWW::Mechanize
2343           http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm
2344           <http://search.cpan.org/dist/Test-WWW-Mechanize/Mechanize.pm>
2345
2346       WWW::Mechanize
2347           http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm
2348           <http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize.pm>
2349
2350       LWP::UserAgent
2351           http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm
2352           <http://search.cpan.org/dist/libwww-perl/lib/LWP/UserAgent.pm>
2353
2354       HTML::Form
2355           http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm
2356           <http://search.cpan.org/dist/libwww-perl/lib/HTML/Form.pm>
2357
2358       HTTP::Message
2359           http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm
2360           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Message.pm>
2361
2362       HTTP::Request
2363           http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm
2364           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request.pm>
2365
2366       HTTP::Request::Common
2367           http://search.cpan.org/dist/libwww-perl/lib/HTTP/Request/Common.pm
2368           <http://search.cpan.org/dist/libwww-
2369           perl/lib/HTTP/Request/Common.pm>
2370
2371       HTTP::Response
2372           http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm
2373           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Response.pm>
2374
2375       HTTP::Status
2376           http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm
2377           <http://search.cpan.org/dist/libwww-perl/lib/HTTP/Status.pm>
2378
2379       URI <http://search.cpan.org/dist/URI/URI.pm>
2380
2381       Test::More
2382           http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm
2383           <http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm>
2384
2385       Test::Pod
2386           http://search.cpan.org/dist/Test-Pod/Pod.pm
2387           <http://search.cpan.org/dist/Test-Pod/Pod.pm>
2388
2389       Test::Pod::Coverage
2390           http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm
2391           <http://search.cpan.org/dist/Test-Pod-Coverage/Coverage.pm>
2392
2393       prove (Test::Harness)
2394           http://search.cpan.org/dist/Test-Harness/bin/prove
2395           <http://search.cpan.org/dist/Test-Harness/bin/prove>
2396
2397       More Information
2398
2399       <http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::Roles>
2400       <http://search.cpan.org/perldoc?Catalyst::Plugin::Authorization::ACL>
2401

AUTHORS

2403       Catalyst Contributors, see Catalyst.pm
2404
2406       This library is free software. You can redistribute it and/or modify it
2407       under the same terms as Perl itself.
2408
2409
2410
2411perl v5.12.0                      2010-02-17     Catalyst::Manual::Cookbook(3)
Impressum