5 Catalyst::Manual::Cookbook - Cooking with Catalyst
9 Yummy code like your mum used to bake!
15 These recipes cover some basic stuff that is worth knowing for
18 =head2 Delivering a Custom Error Page
20 By default, Catalyst will display its own error page whenever it
21 encounters an error in your application. When running under C<-Debug>
22 mode, the error page is a useful screen including the error message
23 and L<Data::Dump> output of the relevant parts of the C<$c> context
24 object. When not in C<-Debug>, users see a simple "Please come back
27 To use a custom error page, use a special C<end> method to
28 short-circuit the error processing. The following is an example; you
29 might want to adjust it further depending on the needs of your
30 application (for example, any calls to C<fillform> will probably need
31 to go into this C<end> method; see L<Catalyst::Plugin::FillInForm>).
34 my ( $self, $c ) = @_;
36 if ( scalar @{ $c->error } ) {
37 $c->stash->{errors} = $c->error;
38 for my $error ( @{ $c->error } ) {
39 $c->log->error($error);
41 $c->stash->{template} = 'errors.tt';
42 $c->forward('MyApp::View::TT');
46 return 1 if $c->response->status =~ /^3\d\d$/;
47 return 1 if $c->response->body;
49 unless ( $c->response->content_type ) {
50 $c->response->content_type('text/html; charset=utf-8');
53 $c->forward('MyApp::View::TT');
56 You can manually set errors in your code to trigger this page by calling
58 $c->error( 'You broke me!' );
60 =head2 Disable statistics
62 Just add this line to your application class if you don't want those
63 nifty statistics in your debug messages.
65 sub Catalyst::Log::info { }
67 =head2 Enable debug status in the environment
69 Normally you enable the debugging info by adding the C<-Debug> flag to
70 your C<use Catalyst> statement . However, you can also enable it using
71 environment variable, so you can (for example) get debug info without
72 modifying your application scripts. Just set C<CATALYST_DEBUG> or
73 C<< <MYAPP>_DEBUG >> to a true value.
77 When you have your users identified, you will want to somehow remember
78 that fact, to save them from having to identify themselves for every
79 single page. One way to do this is to send the username and password
80 parameters in every single page, but that's ugly, and won't work for
83 Sessions are a method of saving data related to some transaction, and
84 giving the whole collection a single ID. This ID is then given to the
85 user to return to us on every page they visit while logged in. The
86 usual way to do this is using a browser cookie.
88 Catalyst uses two types of plugins to represent sessions:
92 A State module is used to keep track of the state of the session
93 between the users browser, and your application.
95 A common example is the Cookie state module, which sends the browser a
96 cookie containing the session ID. It will use default value for the
97 cookie name and domain, so will "just work" when used.
101 A Store module is used to hold all the data relating to your session,
102 for example the users ID, or the items for their shopping cart. You
103 can store data in memory (FastMmap), in a file (File) or in a database
106 =head3 Authentication magic
108 If you have included the session modules in your application, the
109 Authentication modules will automagically use your session to save and
110 retrieve the user data for you.
112 =head3 Using a session
114 Once the session modules are loaded, the session is available as C<<
115 $c->session >>, and can be written to and read from as a simple hash
122 use namespace::autoclean;
126 Session::Store::FastMmap
127 Session::State::Cookie
132 package MyApp::Controller::Foo;
134 use namespace::autoclean;
135 BEGIN { extends 'Catalyst::Controller' };
136 ## Write data into the session
138 sub add_item : Local {
139 my ( $self, $c ) = @_;
141 my $item_id = $c->req->params->{item};
143 push @{ $c->session->{items} }, $item_id;
147 ## A page later we retrieve the data from the session:
149 sub get_items : Local {
150 my ( $self, $c ) = @_;
152 $c->stash->{items_to_display} = $c->session->{items};
157 =head3 More information
159 L<Catalyst::Plugin::Session>
161 L<Catalyst::Plugin::Session::State::Cookie>
163 L<Catalyst::Plugin::Session::State::URI>
165 L<Catalyst::Plugin::Session::Store::FastMmap>
167 L<Catalyst::Plugin::Session::Store::File>
169 L<Catalyst::Plugin::Session::Store::DBI>
171 =head2 Configure your application
173 You configure your application with the C<config> method in your
174 application class. This can be hard-coded, or brought in from a
175 separate configuration file.
177 =head3 Using Config::General
179 L<Config::General|Config::General> is a method for creating flexible
180 and readable configuration files. It's a great way to keep your
181 Catalyst application configuration in one easy-to-understand location.
183 Now create F<myapp.conf> in your application home:
187 # session; perldoc Catalyst::Plugin::Session::FastMmap
191 storage /tmp/myapp.session
194 # emails; perldoc Catalyst::Plugin::Email
195 # this passes options as an array :(
199 This is equivalent to:
201 # configure base package
202 __PACKAGE__->config( name => MyApp );
203 # configure authentication
205 'Plugin::Authentication' => {
206 user_class => 'MyApp::Model::MyDB::Customer',
217 # configure email sending
218 __PACKAGE__->config( email => [qw/SMTP localhost/] );
220 L<Catalyst> explains precedence of multiple sources for configuration
221 values, how to access the values in your components, and many 'base'
222 config variables used internally.
224 See also L<Config::General|Config::General>.
226 =head1 Skipping your VCS's directories
228 Catalyst uses Module::Pluggable to load Models, Views, and Controllers.
229 Module::Pluggable will scan through all directories and load modules
230 it finds. Sometimes you might want to skip some of these directories,
231 for example when your version control system makes a subdirectory with
232 meta-information in every version-controlled directory. While
233 Catalyst skips subversion and CVS directories already, there are other
234 source control systems. Here is the configuration you need to add
235 their directories to the list to skip.
237 You can make Catalyst skip these directories using the Catalyst config:
239 # Configure the application
242 setup_components => { except => qr/SCCS/ },
245 See the Module::Pluggable manual page for more information on B<except>
248 =head1 Users and Access Control
250 Most multiuser, and some single-user web applications require that
251 users identify themselves, and the application is often required to
252 define those roles. The recipes below describe some ways of doing
255 =head2 Authentication (logging in)
257 This is extensively covered in other documentation; see in particular
258 L<Catalyst::Plugin::Authentication> and the Authentication chapter
259 of the Tutorial at L<Catalyst::Manual::Tutorial::06_Authorization>.
261 =head2 Pass-through login (and other actions)
263 An easy way of having assorted actions that occur during the processing
264 of a request that are orthogonal to its actual purpose - logins, silent
265 commands etc. Provide actions for these, but when they're required for
266 something else fill e.g. a form variable __login and have a sub begin
269 sub begin : Private {
271 foreach my $action (qw/login docommand foo bar whatever/) {
272 if ($c->req->params->{"__${action}"}) {
273 $c->forward($action);
278 =head2 Authentication/Authorization
280 This is done in several steps:
286 Getting the user to identify themselves, by giving you some piece of
287 information known only to you and the user. Then you can assume that
288 the user is who they say they are. This is called B<credential
293 Making sure the user only accesses functions you want them to
294 access. This is done by checking the verified user's data against your
295 internal list of groups, or allowed persons for the current page.
301 The Catalyst Authentication system is made up of many interacting
302 modules, to give you the most flexibility possible.
304 =head4 Credential verifiers
306 A Credential module tables the user input, and passes it to a Store,
307 or some other system, for verification. Typically, a user object is
308 created by either this module or the Store and made accessible by a
309 C<< $c->user >> call.
313 Password - Simple username/password checking.
314 HTTPD - Checks using basic HTTP auth.
315 TypeKey - Check using the typekey system.
317 =head3 Storage backends
319 A Storage backend contains the actual data representing the users. It
320 is queried by the credential verifiers. Updating the store is not done
321 within this system; you will need to do it yourself.
325 DBIC - Storage using a database via DBIx::Class.
326 Minimal - Storage using a simple hash (for testing).
330 A User object is created by either the storage backend or the
331 credential verifier, and is filled with the retrieved user information.
335 Hash - A simple hash of keys and values.
337 =head3 ACL authorization
339 ACL stands for Access Control List. The ACL plugin allows you to
340 regulate access on a path-by-path basis, by listing which users, or
341 roles, have access to which paths.
343 =head3 Roles authorization
345 Authorization by roles is for assigning users to groups, which can
346 then be assigned to ACLs, or just checked when needed.
350 When you have chosen your modules, all you need to do is call the C<<
351 $c->authenticate >> method. If called with no parameters, it will try to find
352 suitable parameters, such as B<username> and B<password>, or you can
353 pass it these values.
355 =head3 Checking roles
357 Role checking is done by using the C<< $c->check_user_roles >> method.
358 This will check using the currently logged-in user (via C<< $c->user
359 >>). You pass it the name of a role to check, and it returns true if
360 the user is a member.
366 use namespace::autoclean;
367 extends qw/Catalyst/;
375 default_realm => 'test',
380 password_field => 'password',
381 password_type => 'self_check',
392 package MyApp::Controller::Root;
394 use namespace::autoclean;
396 BEGIN { extends 'Catalyst::Controller' }
398 __PACKAGE__->config(namespace => '');
403 if ( my $user = $c->req->params->{user}
404 and my $password = $c->req->param->{password} )
406 if ( $c->authenticate( username => $user, password => $password ) ) {
407 $c->res->body( "hello " . $c->user->name );
417 sub restricted : Local {
418 my ( $self, $c ) = @_;
420 $c->detach("unauthorized")
421 unless $c->check_user_roles( "admin" );
423 # do something restricted here
426 =head3 Using authentication in a testing environment
428 Ideally, to write tests for authentication/authorization code one would
429 first set up a test database with known data, then use
430 L<Test::WWW::Mechanize::Catalyst> to simulate a user logging
431 in. Unfortunately this can be rather awkward, which is why it's a good
432 thing that the authentication framework is so flexible.
434 Instead of using a test database, one can simply change the
435 authentication store to something a bit easier to deal with in a
436 testing environment. Additionally, this has the advantage of not
437 modifying one's database, which can be problematic if one forgets to
438 use the testing instead of production database.
440 Alternatively, if you want to authenticate real users, but not have to
441 worry about their passwords, you can use
442 L<Catalyst::Authentication::Credential::Testing> to force all users to
443 authenticate with a global password.
445 =head3 More information
447 L<Catalyst::Plugin::Authentication> has a longer explanation.
453 Authorization is the step that comes after
454 authentication. Authentication establishes that the user agent is really
455 representing the user we think it's representing, and then authorization
456 determines what this user is allowed to do.
458 =head3 Role Based Access Control
460 Under role based access control each user is allowed to perform any
461 number of roles. For example, at a zoo no one but specially trained
462 personnel can enter the moose cage (Mynd you, møøse bites kan be
463 pretty nasti!). For example:
465 package Zoo::Controller::MooseCage;
467 sub feed_moose : Local {
468 my ( $self, $c ) = @_;
470 $c->model( "Moose" )->eat( $c->req->params->{food} );
473 With this action, anyone can just come into the moose cage and feed
474 the moose, which is a very dangerous thing. We need to restrict this
475 action, so that only a qualified moose feeder can perform that action.
477 The Authorization::Roles plugin lets us perform role based access
478 control checks. Let's load it:
480 use parent qw/Catalyst/;
486 And now our action should look like this:
488 sub feed_moose : Local {
489 my ( $self, $c ) = @_;
491 if ( $c->check_roles( "moose_feeder" ) ) {
492 $c->model( "Moose" )->eat( $c->req->params->{food} );
494 $c->stash->{error} = "unauthorized";
498 This checks C<< $c->user >>, and only if the user has B<all> the roles
499 in the list, a true value is returned.
501 C<check_roles> has a sister method, C<assert_roles>, which throws an
502 exception if any roles are missing.
504 Some roles that might actually make sense in, say, a forum application:
518 each with a distinct task (system administration versus content
521 =head3 Access Control Lists
523 Checking for roles all the time can be tedious and error prone.
525 The Authorization::ACL plugin lets us declare where we'd like checks
526 to be done automatically for us.
528 For example, we may want to completely block out anyone who isn't a
529 C<moose_feeder> from the entire C<MooseCage> controller:
531 Zoo->deny_access_unless( "/moose_cage", [qw/moose_feeder/] );
533 The role list behaves in the same way as C<check_roles>. However, the
534 ACL plugin isn't limited to just interacting with the Roles plugin. We
535 can use a code reference instead. For example, to allow either moose
536 trainers or moose feeders into the moose cage, we can create a more
539 Zoo->deny_access_unless( "/moose_cage", sub {
541 $c->check_roles( "moose_trainer" ) || $c->check_roles( "moose_feeder" );
544 The more specific a role, the earlier it will be checked. Let's say
545 moose feeders are now restricted to only the C<feed_moose> action,
546 while moose trainers get access everywhere:
548 Zoo->deny_access_unless( "/moose_cage", [qw/moose_trainer/] );
549 Zoo->allow_access_if( "/moose_cage/feed_moose", [qw/moose_feeder/]);
551 When the C<feed_moose> action is accessed the second check will be
552 made. If the user is a C<moose_feeder>, then access will be
553 immediately granted. Otherwise, the next rule in line will be tested -
554 the one checking for a C<moose_trainer>. If this rule is not
555 satisfied, access will be immediately denied.
557 Rules applied to the same path will be checked in the order they were
560 Lastly, handling access denial events is done by creating an
561 C<access_denied> private action:
563 sub access_denied : Private {
564 my ( $self, $c, $action ) = @_;
567 This action works much like auto, in that it is inherited across
568 namespaces (not like object oriented code). This means that the
569 C<access_denied> action which is B<nearest> to the action which was
570 blocked will be triggered.
572 If this action does not exist, an error will be thrown, which you can
573 clean up in your C<end> private action instead.
575 Also, it's important to note that if you restrict access to "/" then
576 C<end>, C<default>, etc. will also be restricted.
578 MyApp->acl_allow_root_internals;
580 will create rules that permit access to C<end>, C<begin>, and C<auto> in the
581 root of your app (but not in any other controller).
585 Models are where application data belongs. Catalyst is extremely
586 flexible with the kind of models that it can use. The recipes here
589 =head2 Using existing DBIC (etc.) classes with Catalyst
591 Many people have existing Model classes that they would like to use
592 with Catalyst (or, conversely, they want to write Catalyst models that
593 can be used outside of Catalyst, e.g. in a cron job). It's trivial to
594 write a simple component in Catalyst that slurps in an outside Model:
596 package MyApp::Model::DB;
598 use base qw/Catalyst::Model::DBIC::Schema/;
601 schema_class => 'Some::DBIC::Schema',
602 connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}],
607 and that's it! Now C<Some::DBIC::Schema> is part of your
608 Cat app as C<MyApp::Model::DB>.
610 =head2 DBIx::Class as a Catalyst Model
612 See L<Catalyst::Model::DBIC::Schema>.
614 =head2 Create accessors to preload static data once per server instance
616 When you have data that you want to load just once from the model at
617 startup, instead of for each request, use mk_group_accessors to
618 create accessors and tie them to resultsets in your package that
619 inherits from DBIx::Class::Schema:
622 use base qw/DBIx::Class::Schema/;
623 __PACKAGE__->register_class('RESULTSOURCEMONIKER',
624 'My::Schema::RESULTSOURCE');
625 __PACKAGE__->mk_group_accessors('simple' =>
626 qw(ACCESSORNAME1 ACCESSORNAME2 ACCESSORNAMEn));
629 my ($self, @rest) = @_;
630 $self->next::method(@rest);
631 # $self is now a live My::Schema object, complete with DB connection
633 $self->ACCESSORNAME1([ $self->resultset('RESULTSOURCEMONIKER')->all ]);
634 $self->ACCESSORNAME2([ $self->resultset('RESULTSOURCEMONIKER')->search({ COLUMN => { '<' => '30' } })->all ]);
635 $self->ACCESSORNAMEn([ $self->resultset('RESULTSOURCEMONIKER')->find(1) ]);
640 and now in the controller, you can now access any of these without a
643 $c->stash->{something} = $c->model('My::Schema')->schema->ACCESSORNAME;
648 Unlike SOAP, XMLRPC is a very simple (and elegant) web-services
649 protocol, exchanging small XML messages like these:
654 TE: deflate,gzip;q=0.3
655 Connection: TE, close
659 User-Agent: SOAP::Lite/Perl/0.60
661 Content-Type: text/xml
663 <?xml version="1.0" encoding="UTF-8"?>
665 <methodName>add</methodName>
667 <param><value><int>1</int></value></param>
668 <param><value><int>2</int></value></param>
675 Date: Tue, 20 Dec 2005 07:45:55 GMT
677 Content-Type: text/xml
681 <?xml version="1.0" encoding="us-ascii"?>
684 <param><value><int>3</int></value></param>
688 Now follow these few steps to implement the application:
690 1. Install Catalyst (5.61 or later), Catalyst::Plugin::XMLRPC (0.06 or
691 later) and SOAP::Lite (for XMLRPCsh.pl).
693 2. Create an application framework:
699 3. Add the XMLRPC plugin to MyApp.pm
701 use Catalyst qw/-Debug Static::Simple XMLRPC/;
703 4. Add an API controller
705 % ./script/myapp_create.pl controller API
707 5. Add a XMLRPC redispatch method and an add method with Remote
708 attribute to lib/MyApp/Controller/API.pm
711 my ( $self, $c ) = @_;
716 my ( $self, $c, $a, $b ) = @_;
720 The default action is the entry point for each XMLRPC request. It will
721 redispatch every request to methods with Remote attribute in the same
724 The C<add> method is not a traditional action; it has no private or
725 public path. Only the XMLRPC dispatcher knows it exists.
727 6. That's it! You have built your first web service. Let's test it with
728 XMLRPCsh.pl (part of SOAP::Lite):
730 % ./script/myapp_server.pl
732 % XMLRPCsh.pl http://127.0.0.1:3000/api
733 Usage: method[(parameters)]
735 --- XMLRPC RESULT ---
740 Your return data type is usually auto-detected, but you can easily
741 enforce a specific one.
744 my ( $self, $c, $a, $b ) = @_;
745 return RPC::XML::int->new( $a + $b );
750 Views pertain to the display of your application. As with models,
751 Catalyst is uncommonly flexible. The recipes below are just a start.
753 =head2 Catalyst::View::TT
755 One of the first things you probably want to do when starting a new
756 Catalyst application is set up your View. Catalyst doesn't care how you
757 display your data; you can choose to generate HTML, PDF files, or plain
760 Most Catalyst applications use a template system to generate their HTML,
761 and though there are several template systems available,
762 L<Template Toolkit|Template> is probably the most popular.
764 Once again, the Catalyst developers have done all the hard work, and
765 made things easy for the rest of us. Catalyst::View::TT provides the
766 interface to Template Toolkit, and provides Helpers which let us set it
767 up that much more easily.
769 =head3 Creating your View
771 Catalyst::View::TT provides two different helpers for us to use: TT and
776 Create a basic Template Toolkit View using the provided helper script:
778 script/myapp_create.pl view TT TT
780 This will create lib/MyApp/View/MyView.pm, which is going to be pretty
781 empty to start. However, it sets everything up that you need to get
782 started. You can now define which template you want and forward to your
786 my ( $self, $c ) = @_;
788 $c->stash->{template} = 'hello.tt';
790 $c->forward( $c->view('TT') );
793 In practice you wouldn't do the forwarding manually, but would
794 use L<Catalyst::Action::RenderView>.
798 Although the TT helper does create a functional, working view, you may
799 find yourself having to create the same template files and changing the
800 same options every time you create a new application. The TTSite helper
801 saves us even more time by creating the basic templates and setting some
802 common options for us.
804 Once again, you can use the helper script:
806 script/myapp_create.pl view TT TTSite
808 This time, the helper sets several options for us in the generated View.
810 __PACKAGE__->config({
811 CATALYST_VAR => 'Catalyst',
813 MyApp->path_to( 'root', 'src' ),
814 MyApp->path_to( 'root', 'lib' )
816 PRE_PROCESS => 'config/main',
817 WRAPPER => 'site/wrapper',
818 ERROR => 'error.tt2',
826 INCLUDE_PATH defines the directories that Template Toolkit should search
827 for the template files.
831 PRE_PROCESS is used to process configuration options which are common to
836 WRAPPER is a file which is processed with each template, usually used to
837 easily provide a common header and footer for every page.
841 In addition to setting these options, the TTSite helper also created the
842 template and config files for us! In the 'root' directory, you'll notice
843 two new directories: src and lib.
845 Several configuration files in root/lib/config are called by PRE_PROCESS.
847 The files in root/lib/site are the site-wide templates, called by
848 WRAPPER, and display the html framework, control the layout, and provide
849 the templates for the header and footer of your page. Using the template
850 organization provided makes it much easier to standardize pages and make
851 changes when they are (inevitably) needed.
853 The template files that you will create for your application will go
854 into root/src, and you don't need to worry about putting the <html>
855 or <head> sections; just put in the content. The WRAPPER will the rest
856 of the page around your template for you.
859 =head3 C<< $c->stash >>
861 Of course, having the template system include the header and footer for
862 you isn't all that we want our templates to do. We need to be able to
863 put data into our templates, and have it appear where and how we want
864 it, right? That's where the stash comes in.
866 In our controllers, we can add data to the stash, and then access it
867 from the template. For instance:
870 my ( $self, $c ) = @_;
872 $c->stash->{name} = 'Adam';
874 $c->stash->{template} = 'hello.tt';
876 $c->forward( $c->view('TT') );
881 <strong>Hello, [% name %]!</strong>
883 When you view this page, it will display "Hello, Adam!"
885 All of the information in your stash is available, by its name/key, in
886 your templates. And your data don't have to be plain, old, boring
887 scalars. You can pass array references and hash references, too.
892 my ( $self, $c ) = @_;
894 $c->stash->{names} = [ 'Adam', 'Dave', 'John' ];
896 $c->stash->{template} = 'hello.tt';
898 $c->forward( $c->view('TT') );
903 [% FOREACH name IN names %]
904 <strong>Hello, [% name %]!</strong><br />
907 This allowed us to loop through each item in the arrayref, and display a
908 line for each name that we have.
910 This is the most basic usage, but Template Toolkit is quite powerful,
911 and allows you to truly keep your presentation logic separate from the
912 rest of your application.
914 =head3 C<< $c->uri_for() >>
916 One of my favorite things about Catalyst is the ability to move an
917 application around without having to worry that everything is going to
918 break. One of the areas that used to be a problem was with the http
919 links in your template files. For example, suppose you have an
920 application installed at http://www.domain.com/Calendar. The links point
921 to "/Calendar", "/Calendar/2005", "/Calendar/2005/10", etc. If you move
922 the application to be at http://www.mydomain.com/Tools/Calendar, then
923 all of those links will suddenly break.
925 That's where C<< $c->uri_for() >> comes in. This function will merge its
926 parameters with either the base location for the app, or its current
927 namespace. Let's take a look at a couple of examples.
929 In your template, you can use the following:
931 <a href="[% c.uri_for('/login') %]">Login Here</a>
933 Although the parameter starts with a forward slash, this is relative
934 to the application root, not the webserver root. This is important to
935 remember. So, if your application is installed at
936 http://www.domain.com/Calendar, then the link would be
937 http://www.mydomain.com/Calendar/Login. If you move your application
938 to a different domain or path, then that link will still be correct.
942 <a href="[% c.uri_for('2005','10', '24') %]">October, 24 2005</a>
944 The first parameter does NOT have a forward slash, and so it will be
945 relative to the current namespace. If the application is installed at
946 http://www.domain.com/Calendar. and if the template is called from
947 C<MyApp::Controller::Display>, then the link would become
948 http://www.domain.com/Calendar/Display/2005/10/24.
950 If you want to link to a parent uri of your current namespace you can
951 prefix the arguments with multiple '../':
953 <a href="[% c.uri_for('../../view', stashed_object.id) %]">User view</a>
955 Once again, this allows you to move your application around without
956 having to worry about broken links. But there's something else, as
957 well. Since the links are generated by uri_for, you can use the same
958 template file by several different controllers, and each controller
959 will get the links that its supposed to. Since we believe in Don't
960 Repeat Yourself, this is particularly helpful if you have common
961 elements in your site that you want to keep in one file.
967 L<Catalyst::View::TT>
971 =head2 Adding RSS feeds
973 Adding RSS feeds to your Catalyst applications is simple. We'll see two
974 different approaches here, but the basic premise is that you forward to
975 the normal view action first to get the objects, then handle the output
978 =head3 Using XML::Feed
980 Assuming we have a C<view> action that populates
981 'entries' with some DBIx::Class iterator, the code would look something
986 $c->forward('view'); # get the entries
988 my $feed = XML::Feed->new('RSS');
989 $feed->title( $c->config->{name} . ' RSS Feed' );
990 $feed->link( $c->req->base ); # link to the site.
991 $feed->description('Catalyst advent calendar'); Some description
993 # Process the entries
994 while( my $entry = $c->stash->{entries}->next ) {
995 my $feed_entry = XML::Feed::Entry->new('RSS');
996 $feed_entry->title($entry->title);
997 $feed_entry->link( $c->uri_for($entry->link) );
998 $feed_entry->issued( DateTime->from_epoch(epoch => $entry->created) );
999 $feed->add_entry($feed_entry);
1001 $c->res->body( $feed->as_xml );
1004 With this approach you're
1005 pretty sure to get something that validates.
1007 Note that for both of the above approaches, you'll need to set the
1008 content type like this:
1010 $c->res->content_type('application/rss+xml');
1014 You could generalize the second variant easily by replacing 'RSS' with a
1015 variable, so you can generate Atom feeds with the same code.
1017 Now, go ahead and make RSS feeds for all your stuff. The world *needs*
1018 updates on your goldfish!
1020 =head2 Forcing the browser to download content
1022 Sometimes you need your application to send content for download. For
1023 example, you can generate a comma-separated values (CSV) file for your
1024 users to download and import into their spreadsheet program.
1026 Let's say you have an C<Orders> controller which generates a CSV file
1027 in the C<export> action (i.e., C<http://localhost:3000/orders/export>):
1029 sub export : Local Args(0) {
1030 my ( $self, $c ) = @_;
1032 # In a real application, you'd generate this from the database
1033 my $csv = "1,5.99\n2,29.99\n3,3.99\n";
1035 $c->res->content_type('text/comma-separated-values');
1036 $c->res->body($csv);
1039 Normally the browser uses the last part of the URI to generate a
1040 filename for data it cannot display. In this case your browser would
1041 likely ask you to save a file named C<export>.
1043 Luckily you can have the browser download the content with a specific
1044 filename by setting the C<Content-Disposition> header:
1046 my $filename = 'Important Orders.csv';
1047 $c->res->header('Content-Disposition', qq[attachment; filename="$filename"]);
1049 Note the use of quotes around the filename; this ensures that any
1050 spaces in the filename are handled by the browser.
1052 Put this right before calling C<< $c->res->body >> and your browser
1053 will download a file named F<Important Orders.csv> instead of
1056 You can also use this to have the browser download content which it
1057 normally displays, such as JPEG images or even HTML. Just be sure to
1058 set the appropriate content type and disposition.
1063 Controllers are the main point of communication between the web server
1064 and your application. Here we explore some aspects of how they work.
1070 A Catalyst application is driven by one or more Controller
1071 modules. There are a number of ways that Catalyst can decide which of
1072 the methods in your controller modules it should call. Controller
1073 methods are also called actions, because they determine how your
1074 catalyst application should (re-)act to any given URL. When the
1075 application is started up, catalyst looks at all your actions, and
1076 decides which URLs they map to.
1078 =head3 Type attributes
1080 Each action is a normal method in your controller, except that it has an
1081 L<attribute|attributes>
1082 attached. These can be one of several types.
1084 Assume our Controller module starts with the following package declaration:
1086 package MyApp::Controller::Buckets;
1088 and we are running our application on localhost, port 3000 (the test
1095 A Path attribute also takes an argument, this can be either a relative
1096 or an absolute path. A relative path will be relative to the
1097 controller namespace, an absolute path will represent an exact
1100 sub my_handles : Path('handles') { .. }
1104 http://localhost:3000/buckets/handles
1108 sub my_handles : Path('/handles') { .. }
1112 http://localhost:3000/handles
1114 See also: L<Catalyst::DispatchType::Path>
1118 When using a Local attribute, no parameters are needed, instead, the
1119 name of the action is matched in the URL. The namespaces created by
1120 the name of the controller package is always part of the URL.
1122 sub my_handles : Local { .. }
1126 http://localhost:3000/buckets/my_handles
1130 A Global attribute is similar to a Local attribute, except that the
1131 namespace of the controller is ignored, and matching starts at root.
1133 sub my_handles : Global { .. }
1137 http://localhost:3000/my_handles
1141 By now you should have figured that a Regex attribute is just what it
1142 sounds like. This one takes a regular expression, and matches starting
1143 from root. These differ from the rest as they can match multiple URLs.
1145 sub my_handles : Regex('^handles') { .. }
1149 http://localhost:3000/handles
1153 http://localhost:3000/handles_and_other_parts
1157 See also: L<Catalyst::DispatchType::Regex>
1161 A LocalRegex is similar to a Regex, except it only matches below the current
1162 controller namespace.
1164 sub my_handles : LocalRegex(^handles') { .. }
1168 http://localhost:3000/buckets/handles
1172 http://localhost:3000/buckets/handles_and_other_parts
1178 See L<Catalyst::DispatchType::Chained> for a description of how the chained
1179 dispatch type works.
1183 Last but not least, there is the Private attribute, which allows you
1184 to create your own internal actions, which can be forwarded to, but
1185 won't be matched as URLs.
1187 sub my_handles : Private { .. }
1189 becomes nothing at all..
1191 Catalyst also predefines some special Private actions, which you can
1192 override, these are:
1198 The default action will be called, if no other matching action is
1199 found. If you don't have one of these in your namespace, or any sub
1200 part of your namespace, you'll get an error page instead. If you want
1201 to find out where it was the user was trying to go, you can look in
1202 the request object using C<< $c->req->path >>.
1204 sub default :Path { .. }
1206 works for all unknown URLs, in this controller namespace, or every one
1207 if put directly into MyApp.pm.
1211 The index action is called when someone tries to visit the exact
1212 namespace of your controller. If index, default and matching Path
1213 actions are defined, then index will be used instead of default and
1216 sub index :Path :Args(0) { .. }
1220 http://localhost:3000/buckets
1224 The begin action is called at the beginning of every request involving
1225 this namespace directly, before other matching actions are called. It
1226 can be used to set up variables/data for this particular part of your
1227 app. A single begin action is called, its always the one most relevant
1228 to the current namespace.
1230 sub begin : Private { .. }
1234 http://localhost:3000/bucket/(anything)?
1240 Like begin, this action is always called for the namespace it is in,
1241 after every other action has finished. It is commonly used to forward
1242 processing to the View component. A single end action is called, its
1243 always the one most relevant to the current namespace.
1246 sub end : Private { .. }
1248 is called once after any actions when
1250 http://localhost:3000/bucket/(anything)?
1256 Lastly, the auto action is magic in that B<every> auto action in the
1257 chain of paths up to and including the ending namespace, will be
1258 called. (In contrast, only one of the begin/end/default actions will
1259 be called, the relevant one).
1261 package MyApp::Controller::Root;
1262 sub auto : Private { .. }
1266 sub auto : Private { .. }
1268 will both be called when visiting
1270 http://localhost:3000/bucket/(anything)?
1276 =head3 A word of warning
1278 You can put root actions in your main MyApp.pm file, but this is deprecated,
1279 please put your actions into your Root controller.
1283 A graphical flowchart of how the dispatcher works can be found on the wiki at
1284 L<http://dev.catalyst.perl.org/attachment/wiki/WikiStart/catalyst-flow.png>.
1286 =head2 DRY Controllers with Chained actions
1288 Imagine that you would like the following paths in your application:
1292 =item B<< /cd/<ID>/track/<ID> >>
1294 Displays info on a particular track.
1296 In the case of a multi-volume CD, this is the track sequence.
1298 =item B<< /cd/<ID>/volume/<ID>/track/<ID> >>
1300 Displays info on a track on a specific volume.
1304 Here is some example code, showing how to do this with chained controllers:
1306 package CD::Controller;
1307 use base qw/Catalyst::Controller/;
1309 sub root : Chained('/') PathPart('/cd') CaptureArgs(1) {
1310 my ($self, $c, $cd_id) = @_;
1311 $c->stash->{cd_id} = $cd_id;
1312 $c->stash->{cd} = $self->model('CD')->find_by_id($cd_id);
1315 sub trackinfo : Chained('track') PathPart('') Args(0) RenderView {
1316 my ($self, $c) = @_;
1319 package CD::Controller::ByTrackSeq;
1320 use base qw/CD::Controller/;
1322 sub track : Chained('root') PathPart('track') CaptureArgs(1) {
1323 my ($self, $c, $track_seq) = @_;
1324 $c->stash->{track} = $self->stash->{cd}->find_track_by_seq($track_seq);
1327 package CD::Controller::ByTrackVolNo;
1328 use base qw/CD::Controller/;
1330 sub volume : Chained('root') PathPart('volume') CaptureArgs(1) {
1331 my ($self, $c, $volume) = @_;
1332 $c->stash->{volume} = $volume;
1335 sub track : Chained('volume') PathPart('track') CaptureArgs(1) {
1336 my ($self, $c, $track_no) = @_;
1337 $c->stash->{track} = $self->stash->{cd}->find_track_by_vol_and_track_no(
1338 $c->stash->{volume}, $track_no
1342 Note that adding other actions (i.e. chain endpoints) which operate on a track
1343 is simply a matter of adding a new sub to CD::Controller - no code is duplicated,
1344 even though there are two different methods of looking up a track.
1346 This technique can be expanded as needed to fulfil your requirements - for example,
1347 if you inherit the first action of a chain from a base class, then mixing in a
1348 different base class can be used to duplicate an entire URL hierarchy at a different
1349 point within your application.
1351 =head2 Component-based Subrequests
1353 See L<Catalyst::Plugin::SubRequest>.
1357 =head3 Single file upload with Catalyst
1359 To implement uploads in Catalyst, you need to have a HTML form similar to
1362 <form action="/upload" method="post" enctype="multipart/form-data">
1363 <input type="hidden" name="form_submit" value="yes">
1364 <input type="file" name="my_file">
1365 <input type="submit" value="Send">
1368 It's very important not to forget C<enctype="multipart/form-data"> in
1371 Catalyst Controller module 'upload' action:
1373 sub upload : Global {
1374 my ($self, $c) = @_;
1376 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1378 if ( my $upload = $c->request->upload('my_file') ) {
1380 my $filename = $upload->filename;
1381 my $target = "/tmp/upload/$filename";
1383 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1384 die( "Failed to copy '$filename' to '$target': $!" );
1389 $c->stash->{template} = 'file_upload.html';
1392 =head3 Multiple file upload with Catalyst
1394 Code for uploading multiple files from one form needs a few changes:
1396 The form should have this basic structure:
1398 <form action="/upload" method="post" enctype="multipart/form-data">
1399 <input type="hidden" name="form_submit" value="yes">
1400 <input type="file" name="file1" size="50"><br>
1401 <input type="file" name="file2" size="50"><br>
1402 <input type="file" name="file3" size="50"><br>
1403 <input type="submit" value="Send">
1406 And in the controller:
1408 sub upload : Local {
1409 my ($self, $c) = @_;
1411 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
1413 for my $field ( $c->req->upload ) {
1415 my $upload = $c->req->upload($field);
1416 my $filename = $upload->filename;
1417 my $target = "/tmp/upload/$filename";
1419 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
1420 die( "Failed to copy '$filename' to '$target': $!" );
1425 $c->stash->{template} = 'file_upload.html';
1428 C<< for my $field ($c->req->upload) >> loops automatically over all file
1429 input fields and gets input names. After that is basic file saving code,
1430 just like in single file upload.
1432 Notice: C<die>ing might not be what you want to do, when an error
1433 occurs, but it works as an example. A better idea would be to store
1434 error C<$!> in C<< $c->stash->{error} >> and show a custom error template
1435 displaying this message.
1437 For more information about uploads and usable methods look at
1438 L<Catalyst::Request::Upload> and L<Catalyst::Request>.
1440 =head2 Forwarding with arguments
1442 Sometimes you want to pass along arguments when forwarding to another
1443 action. As of version 5.30, arguments can be passed in the call to
1444 C<forward>; in earlier versions, you can manually set the arguments in
1445 the Catalyst Request object:
1447 # version 5.30 and later:
1448 $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
1451 $c->req->args([qw/arg1 arg2 arg3/]);
1452 $c->forward('/wherever');
1454 (See the L<Catalyst::Manual::Intro> Flow_Control section for more
1455 information on passing arguments via C<forward>.)
1457 =head2 Chained dispatch using base classes, and inner packages.
1459 package MyApp::Controller::Base;
1460 use base qw/Catalyst::Controller/;
1462 sub key1 : Chained('/')
1464 =head2 Extending RenderView (formerly DefaultEnd)
1466 The recommended approach for an C<end> action is to use
1467 L<Catalyst::Action::RenderView> (taking the place of
1468 L<Catalyst::Plugin::DefaultEnd>), which does what you usually need.
1469 However there are times when you need to add a bit to it, but don't want
1470 to write your own C<end> action.
1472 You can extend it like this:
1474 To add something to an C<end> action that is called before rendering
1475 (this is likely to be what you want), simply place it in the C<end>
1478 sub end : ActionClass('RenderView') {
1479 my ( $self, $c ) = @_;
1480 # do stuff here; the RenderView action is called afterwards
1483 To add things to an C<end> action that are called I<after> rendering,
1484 you can set it up like this:
1486 sub render : ActionClass('RenderView') { }
1489 my ( $self, $c ) = @_;
1490 $c->forward('render');
1495 =head2 Serving static content
1497 Serving static content in Catalyst used to be somewhat tricky; the use
1498 of L<Catalyst::Plugin::Static::Simple> makes everything much easier.
1499 This plugin will automatically serve your static content during development,
1500 but allows you to easily switch to Apache (or other server) in a
1501 production environment.
1503 =head3 Introduction to Static::Simple
1505 Static::Simple is a plugin that will help to serve static content for your
1506 application. By default, it will serve most types of files, excluding some
1507 standard Template Toolkit extensions, out of your B<root> file directory. All
1508 files are served by path, so if F<images/me.jpg> is requested, then
1509 F<root/images/me.jpg> is found and served.
1513 Using the plugin is as simple as setting your use line in MyApp.pm to include:
1515 use Catalyst qw/Static::Simple/;
1517 and already files will be served.
1521 Static content is best served from a single directory within your root
1522 directory. Having many different directories such as F<root/css> and
1523 F<root/images> requires more code to manage, because you must separately
1524 identify each static directory--if you decide to add a F<root/js>
1525 directory, you'll need to change your code to account for it. In
1526 contrast, keeping all static directories as subdirectories of a main
1527 F<root/static> directory makes things much easier to manage. Here's an
1528 example of a typical root directory structure:
1532 root/controller/stuff.tt
1535 root/static/css/main.css
1536 root/static/images/logo.jpg
1537 root/static/js/code.js
1540 All static content lives under F<root/static>, with everything else being
1541 Template Toolkit files.
1547 You may of course want to change the default locations, and make
1548 Static::Simple look somewhere else, this is as easy as:
1553 MyApp->path_to('/'),
1554 '/path/to/my/files',
1559 When you override include_path, it will not automatically append the
1560 normal root path, so you need to add it yourself if you still want
1561 it. These will be searched in order given, and the first matching file
1564 =item Static directories
1566 If you want to force some directories to be only static, you can set
1567 them using paths relative to the root dir, or regular expressions:
1578 =item File extensions
1580 By default, the following extensions are not served (that is, they will
1581 be processed by Catalyst): B<tmpl, tt, tt2, html, xhtml>. This list can
1586 ignore_extensions => [
1587 qw/tmpl tt tt2 html xhtml/
1592 =item Ignoring directories
1594 Entire directories can be ignored. If used with include_path,
1595 directories relative to the include_path dirs will also be ignored:
1597 MyApp->config( static => {
1598 ignore_dirs => [ qw/tmpl css/ ],
1603 =head3 More information
1605 L<Catalyst::Plugin::Static::Simple>
1607 =head3 Serving manually with the Static plugin with HTTP::Daemon (myapp_server.pl)
1609 In some situations you might want to control things more directly,
1610 using L<Catalyst::Plugin::Static>.
1612 In your main application class (MyApp.pm), load the plugin:
1614 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
1616 You will also need to make sure your end method does I<not> forward
1617 static content to the view, perhaps like this:
1620 my ( $self, $c ) = @_;
1622 $c->forward( 'MyApp::View::TT' )
1623 unless ( $c->res->body || !$c->stash->{template} );
1626 This code will only forward to the view if a template has been
1627 previously defined by a controller and if there is not already data in
1628 C<< $c->res->body >>.
1630 Next, create a controller to handle requests for the /static path. Use
1631 the Helper to save time. This command will create a stub controller as
1632 F<lib/MyApp/Controller/Static.pm>.
1634 $ script/myapp_create.pl controller Static
1636 Edit the file and add the following methods:
1638 # serve all files under /static as static files
1639 sub default : Path('/static') {
1640 my ( $self, $c ) = @_;
1642 # Optional, allow the browser to cache the content
1643 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
1645 $c->serve_static; # from Catalyst::Plugin::Static
1648 # also handle requests for /favicon.ico
1649 sub favicon : Path('/favicon.ico') {
1650 my ( $self, $c ) = @_;
1655 You can also define a different icon for the browser to use instead of
1656 favicon.ico by using this in your HTML header:
1658 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
1660 =head3 Common problems with the Static plugin
1662 The Static plugin makes use of the C<shared-mime-info> package to
1663 automatically determine MIME types. This package is notoriously
1664 difficult to install, especially on win32 and OS X. For OS X the easiest
1665 path might be to install Fink, then use C<apt-get install
1666 shared-mime-info>. Restart the server, and everything should be fine.
1668 Make sure you are using the latest version (>= 0.16) for best
1669 results. If you are having errors serving CSS files, or if they get
1670 served as text/plain instead of text/css, you may have an outdated
1671 shared-mime-info version. You may also wish to simply use the following
1672 code in your Static controller:
1674 if ($c->req->path =~ /css$/i) {
1675 $c->serve_static( "text/css" );
1680 =head3 Serving Static Files with Apache
1682 When using Apache, you can bypass Catalyst and any Static
1683 plugins/controllers controller by intercepting requests for the
1684 F<root/static> path at the server level. All that is required is to
1685 define a DocumentRoot and add a separate Location block for your static
1686 content. Here is a complete config for this application under mod_perl
1690 use lib qw(/var/www/MyApp/lib);
1695 ServerName myapp.example.com
1696 DocumentRoot /var/www/MyApp/root
1698 SetHandler perl-script
1701 <LocationMatch "/(static|favicon.ico)">
1702 SetHandler default-handler
1706 And here's a simpler example that'll get you started:
1708 Alias /static/ "/my/static/files/"
1709 <Location "/static">
1715 Catalyst makes it easy to employ several different types of caching to
1716 speed up your applications.
1718 =head3 Cache Plugins
1720 There are three wrapper plugins around common CPAN cache modules:
1721 Cache::FastMmap, Cache::FileCache, and Cache::Memcached. These can be
1722 used to cache the result of slow operations.
1724 The Catalyst Advent Calendar uses the FileCache plugin to cache the
1725 rendered XHTML version of the source POD document. This is an ideal
1726 application for a cache because the source document changes
1727 infrequently but may be viewed many times.
1729 use Catalyst qw/Cache::FileCache/;
1734 sub render_pod : Local {
1735 my ( self, $c ) = @_;
1737 # the cache is keyed on the filename and the modification time
1738 # to check for updates to the file.
1739 my $file = $c->path_to( 'root', '2005', '11.pod' );
1740 my $mtime = ( stat $file )->mtime;
1742 my $cached_pod = $c->cache->get("$file $mtime");
1743 if ( !$cached_pod ) {
1744 $cached_pod = do_slow_pod_rendering();
1745 # cache the result for 12 hours
1746 $c->cache->set( "$file $mtime", $cached_pod, '12h' );
1748 $c->stash->{pod} = $cached_pod;
1751 We could actually cache the result forever, but using a value such as 12 hours
1752 allows old entries to be automatically expired when they are no longer needed.
1756 Another method of caching is to cache the entire HTML page. While this is
1757 traditionally handled by a frontend proxy server like Squid, the Catalyst
1758 PageCache plugin makes it trivial to cache the entire output from
1759 frequently-used or slow actions.
1761 Many sites have a busy content-filled front page that might look something
1762 like this. It probably takes a while to process, and will do the exact same
1763 thing for every single user who views the page.
1765 sub front_page : Path('/') {
1766 my ( $self, $c ) = @_;
1768 $c->forward( 'get_news_articles' );
1769 $c->forward( 'build_lots_of_boxes' );
1770 $c->forward( 'more_slow_stuff' );
1772 $c->stash->{template} = 'index.tt';
1775 We can add the PageCache plugin to speed things up.
1777 use Catalyst qw/Cache::FileCache PageCache/;
1779 sub front_page : Path ('/') {
1780 my ( $self, $c ) = @_;
1782 $c->cache_page( 300 );
1784 # same processing as above
1787 Now the entire output of the front page, from <html> to </html>, will be
1788 cached for 5 minutes. After 5 minutes, the next request will rebuild the
1789 page and it will be re-cached.
1791 Note that the page cache is keyed on the page URI plus all parameters, so
1792 requests for / and /?foo=bar will result in different cache items. Also,
1793 only GET requests will be cached by the plugin.
1795 You can even get that frontend Squid proxy to help out by enabling HTTP
1796 headers for the cached page.
1800 set_http_headers => 1,
1804 This would now set the following headers so proxies and browsers may cache
1805 the content themselves.
1807 Cache-Control: max-age=($expire_time - time)
1808 Expires: $expire_time
1809 Last-Modified: $cache_created_time
1811 =head3 Template Caching
1813 Template Toolkit provides support for caching compiled versions of your
1814 templates. To enable this in Catalyst, use the following configuration.
1815 TT will cache compiled templates keyed on the file mtime, so changes will
1816 still be automatically detected.
1818 package MyApp::View::TT;
1822 use base 'Catalyst::View::TT';
1824 __PACKAGE__->config(
1825 COMPILE_DIR => '/tmp/template_cache',
1832 See the documentation for each cache plugin for more details and other
1833 available configuration options.
1835 L<Catalyst::Plugin::Cache::FastMmap>
1836 L<Catalyst::Plugin::Cache::FileCache>
1837 L<Catalyst::Plugin::Cache::Memcached>
1838 L<Catalyst::Plugin::PageCache>
1839 L<http://search.cpan.org/dist/Template-Toolkit/lib/Template/Manual/Config.pod#Caching_and_Compiling_Options>
1843 Testing is an integral part of the web application development
1844 process. Tests make multi developer teams easier to coordinate, and
1845 they help ensure that there are no nasty surprises after upgrades or
1850 Catalyst provides a convenient way of testing your application during
1851 development and before deployment in a real environment.
1853 L<Catalyst::Test> makes it possible to run the same tests both locally
1854 (without an external daemon) and against a remote server via HTTP.
1858 Let's examine a skeleton application's F<t/> directory:
1860 mundus:~/MyApp chansen$ ls -l t/
1862 -rw-r--r-- 1 chansen chansen 95 18 Dec 20:50 01app.t
1863 -rw-r--r-- 1 chansen chansen 190 18 Dec 20:50 02pod.t
1864 -rw-r--r-- 1 chansen chansen 213 18 Dec 20:50 03podcoverage.t
1870 Verifies that the application loads, compiles, and returns a successful
1875 Verifies that all POD is free from errors. Only executed if the C<TEST_POD>
1876 environment variable is true.
1878 =item F<03podcoverage.t>
1880 Verifies that all methods/functions have POD coverage. Only executed if the
1881 C<TEST_POD> environment variable is true.
1885 =head3 Creating tests
1887 mundus:~/MyApp chansen$ cat t/01app.t | perl -ne 'printf( "%2d %s", $., $_ )'
1888 1 use Test::More tests => 2;
1889 2 BEGIN { use_ok( Catalyst::Test, 'MyApp' ) }
1891 4 ok( request('/')->is_success );
1893 The first line declares how many tests we are going to run, in this case
1894 two. The second line tests and loads our application in test mode. The
1895 fourth line verifies that our application returns a successful response.
1897 L<Catalyst::Test> exports two functions, C<request> and C<get>. Each can
1898 take three different arguments:
1902 =item A string which is a relative or absolute URI.
1904 request('/my/path');
1905 request('http://www.host.com/my/path');
1907 =item An instance of L<URI>.
1909 request( URI->new('http://www.host.com/my/path') );
1911 =item An instance of L<HTTP::Request>.
1913 request( HTTP::Request->new( GET => 'http://www.host.com/my/path') );
1917 C<request> returns an instance of L<HTTP::Response> and C<get> returns the
1918 content (body) of the response.
1920 =head3 Running tests locally
1922 mundus:~/MyApp chansen$ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib/ t/
1923 t/01app............ok
1924 t/02pod............ok
1925 t/03podcoverage....ok
1926 All tests successful.
1927 Files=3, Tests=4, 2 wallclock secs ( 1.60 cusr + 0.36 csys = 1.96 CPU)
1929 C<CATALYST_DEBUG=0> ensures that debugging is off; if it's enabled you
1930 will see debug logs between tests.
1932 C<TEST_POD=1> enables POD checking and coverage.
1934 C<prove> A command-line tool that makes it easy to run tests. You can
1935 find out more about it from the links below.
1937 =head3 Running tests remotely
1939 mundus:~/MyApp chansen$ CATALYST_SERVER=http://localhost:3000/ prove --lib lib/ t/01app.t
1941 All tests successful.
1942 Files=1, Tests=2, 0 wallclock secs ( 0.40 cusr + 0.01 csys = 0.41 CPU)
1944 C<CATALYST_SERVER=http://localhost:3000/> is the absolute deployment URI of
1945 your application. In C<CGI> or C<FastCGI> it should be the host and path
1948 =head3 L<Test::WWW::Mechanize> and Catalyst
1950 Be sure to check out L<Test::WWW::Mechanize::Catalyst>. It makes it easy to
1951 test HTML, forms and links. A short example of usage:
1953 use Test::More tests => 6;
1954 BEGIN { use_ok( Test::WWW::Mechanize::Catalyst, 'MyApp' ) }
1956 my $mech = Test::WWW::Mechanize::Catalyst->new;
1957 $mech->get_ok("http://localhost/", 'Got index page');
1958 $mech->title_like( qr/^MyApp on Catalyst/, 'Got right index title' );
1959 ok( $mech->find_link( text_regex => qr/^Wiki/i ), 'Found link to Wiki' );
1960 ok( $mech->find_link( text_regex => qr/^Mailing-List/i ), 'Found link to Mailing-List' );
1961 ok( $mech->find_link( text_regex => qr/^IRC channel/i ), 'Found link to IRC channel' );
1963 =head3 Further Reading
1967 =item * L<Catalyst::Test>
1969 =item * L<Test::WWW::Mechanize::Catalyst>
1971 =item * L<Test::WWW::Mechanize>
1973 =item * L<WWW::Mechanize>
1975 =item * L<LWP::UserAgent>
1977 =item * L<HTML::Form>
1979 =item * L<HTTP::Message>
1981 =item * L<HTTP::Request>
1983 =item * L<HTTP::Request::Common>
1985 =item * L<HTTP::Response>
1987 =item * L<HTTP::Status>
1991 =item * L<Test::More>
1993 =item * L<Test::Pod>
1995 =item * L<Test::Pod::Coverage>
1997 =item * L<prove> (L<Test::Harness>)
2001 =head3 More Information
2005 =item * L<Catalyst::Plugin::Authorization::Roles>
2007 =item * L<Catalyst::Plugin::Authorization::ACL>
2013 Catalyst Contributors, see Catalyst.pm
2017 This library is free software. You can redistribute it and/or modify it under
2018 the same terms as Perl itself.