fixed borked Cookbook merge
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Manual / Cookbook.pod
1 =head1 NAME
2
3 Catalyst::Manual::Cookbook - Cooking with Catalyst
4
5 =head1 DESCRIPTION
6
7 Yummy code like your mum used to bake!
8
9 =head1 RECIPES
10
11 =head2 Force debug screen
12
13 You can force Catalyst to display the debug screen at the end of the request by
14 placing a C<die()> call in the C<end> action.
15
16      sub end : Private {
17          my ( $self, $c ) = @_;
18          die "forced debug";
19      }
20
21 If you're tired of removing and adding this all the time, you can add a
22 condition in the C<end> action. For example:
23
24     sub end : Private {  
25         my ( $self, $c ) = @_;  
26         die "forced debug" if $c->req->params->{dump_info};  
27     }  
28
29 Then just add to your query string C<"&dump_info=1">, or the like, to
30 force debug output.
31
32
33 =head2 Disable statistics
34
35 Just add this line to your application class if you don't want those nifty
36 statistics in your debug messages.
37
38     sub Catalyst::Log::info { }
39
40 =head2 Scaffolding
41
42 Scaffolding is very simple with Catalyst.
43 Just use Catalyst::Model::CDBI::CRUD as your base class.
44
45     # lib/MyApp/Model/CDBI.pm
46     package MyApp::Model::CDBI;
47
48     use strict;
49     use base 'Catalyst::Model::CDBI::CRUD';
50
51     __PACKAGE__->config(
52         dsn           => 'dbi:SQLite:/tmp/myapp.db',
53         relationships => 1
54     );
55
56     1;
57
58     # lib/MyApp.pm
59     package MyApp;
60
61     use Catalyst 'FormValidator';
62
63     __PACKAGE__->config(
64         name => 'My Application',
65         root => '/home/joeuser/myapp/root'
66     );
67
68     sub my_table : Global {
69         my ( $self, $c ) = @_;
70         $c->form( optional => [ MyApp::Model::CDBI::Table->columns ] );
71         $c->forward('MyApp::Model::CDBI::Table');
72     }
73
74     1;
75
76 Modify the C<$c-E<gt>form()> parameters to match your needs, and don't
77 forget to copy the templates into the template root. Can't find the
78 templates?  They were in the CRUD model distribution, so you can do
79 B<look Catalyst::Model::CDBI::CRUD> from the CPAN shell to find them.
80
81 Other Scaffolding modules are in development at the time of writing.
82
83 =head2 Single file upload with Catalyst
84
85 To implement uploads in Catalyst you need to have a HTML form similiar to
86 this:
87
88     <form action="/upload" method="post" enctype="multipart/form-data">
89       <input type="hidden" name="form_submit" value="yes">
90       <input type="file" name="my_file">
91       <input type="submit" value="Send">
92     </form>
93
94 It's very important not to forget C<enctype="multipart/form-data"> in
95 the form.
96
97 Catalyst Controller module 'upload' action:
98
99     sub upload : Global {
100         my ($self, $c) = @_;
101
102         if ( $c->request->parameters->{form_submit} eq 'yes' ) {
103
104             if ( my $upload = $c->request->upload('my_file') ) {
105             
106                 my $filename = $upload->filename;
107                 my $target   = "/tmp/upload/$filename";
108                 
109                 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
110                     die( "Failed to copy '$filename' to '$target': $!" );
111                 }
112             }
113         }
114         
115         $c->stash->{template} = 'file_upload.html';
116     }
117
118 =head2 Multiple file upload with Catalyst
119
120 Code for uploading multiple files from one form needs a few changes:
121
122 The form should have this basic structure:
123
124     <form action="/upload" method="post" enctype="multipart/form-data">
125       <input type="hidden" name="form_submit" value="yes">
126       <input type="file" name="file1" size="50"><br>
127       <input type="file" name="file2" size="50"><br>
128       <input type="file" name="file3" size="50"><br>
129       <input type="submit" value="Send">
130     </form>
131
132 And in the controller:
133
134     sub upload : Local {
135         my ($self, $c) = @_;
136
137         if ( $c->request->parameters->{form_submit} eq 'yes' ) {
138
139             for my $field ( $c->req->upload ) {
140
141                 my $upload   = $c->req->upload($field);
142                 my $filename = $upload->filename;
143                 my $target   = "/tmp/upload/$filename";
144                 
145                 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
146                     die( "Failed to copy '$filename' to '$target': $!" );
147                 }
148             }
149         }
150
151         $c->stash->{template} = 'file_upload.html';
152     }
153
154 C<for my $field ($c-E<gt>req->upload)> loops automatically over all file
155 input fields and gets input names. After that is basic file saving code,
156 just like in single file upload.
157
158 Notice: C<die>ing might not be what you want to do, when an error
159 occurs, but it works as an example. A better idea would be to store
160 error C<$!> in $c->stash->{error} and show a custom error template
161 displaying this message.
162
163 For more information about uploads and usable methods look at
164 L<Catalyst::Request::Upload> and L<Catalyst::Request>.
165
166 =head2 Authentication with Catalyst::Plugin::Authentication::CDBI
167
168 There are (at least) two ways to implement authentication with this plugin:
169 1) only checking username and password;
170 2) checking username, password, and the roles the user has
171
172 For both variants you'll need the following code in your MyApp package:
173
174     use Catalyst qw/Session::FastMmap Static Authentication::CDBI/;
175
176     MyApp->config( authentication => { user_class => 'MyApp::M::MyApp::Users',
177                                        user_field => 'email',
178                                        password_field => 'password' });
179
180 'user_class' is a Class::DBI class for your users table.
181 'user_field' tells which field is used for username lookup (might be 
182 email, first name, surname etc.).
183 'password_field' is, well, password field in your table and by default 
184 password is stored in plain text. Authentication::CDBI looks for 'user' 
185 and 'password' fields in table, if they're not defined in the config.
186
187 In PostgreSQL, the users table might be something like:
188
189  CREATE TABLE users (
190    user_id   serial,
191    name      varchar(100),
192    surname   varchar(100),
193    password  varchar(100),
194    email     varchar(100),
195    primary key(user_id)
196  );
197
198 We'll discuss the first variant for now:
199 1. user:password login/auth without roles
200
201 To log in a user you might use an action like this:
202
203     sub login : Local {
204         my ($self, $c) = @_;
205         if ($c->req->params->{username}) {
206             $c->session_login($c->req->params->{username}, 
207                               $c->req->params->{password} );
208             if ($c->req->{user}) {
209                 $c->forward('?restricted_area');
210             }
211         }
212     }
213
214 This action should not go in your MyApp class...if it does, it will
215 conflict with the built-in method of the same name.  Instead, put it
216 in a Controller class.
217
218 $c->req->params->{username} and $c->req->params->{password} are html 
219 form parameters from a login form. If login succeeds, then 
220 $c->req->{user} contains the username of the authenticated user.
221
222 If you want to remember the user's login status in between further 
223 requests, then just use the C<$c-E<gt>session_login> method. Catalyst will 
224 create a session id and session cookie and automatically append session 
225 id to all urls. So all you have to do is just check $c->req->{user} 
226 where needed.
227
228 To log out a user, just call $c->session_logout.
229
230 Now let's take a look at the second variant:
231 2. user:password login/auth with roles
232
233 To use roles you need to add the following parameters to  MyApp->config in the 'authentication' section:
234
235     role_class      => 'MyApp::M::MyApp::Roles',
236     user_role_class => 'MyApp::M::MyApp::UserRoles',
237     user_role_user_field => 'user_id',
238     user_role_role_field => 'role_id',
239
240 Corresponding tables in PostgreSQL could look like this:
241
242  CREATE TABLE roles (
243    role_id  serial,
244    name     varchar(100),
245    primary key(role_id)
246  );
247
248  CREATE TABLE user_roles (
249    user_role_id  serial,
250    user_id       int,
251    role_id       int,
252    primary key(user_role_id),
253    foreign key(user_id) references users(user_id),
254    foreign key(role_id) references roles(role_id)
255  );
256
257 The 'roles' table is a list of role names and the 'user_role' table is 
258 used for the user -> role lookup.
259
260 Now if a logged-in user wants to see a location which is allowed only 
261 for people with an 'admin' role, in your controller you can check it 
262 with:
263
264     sub add : Local {
265         my ($self, $c) = @_;
266         if ($c->roles(qw/admin/)) {
267             $c->req->output("Your account has the role 'admin.'");
268         } else {
269             $c->req->output("You're not allowed to be here.");
270         }
271     }
272
273 One thing you might need is to forward non-authenticated users to a login 
274 form if they try to access restricted areas. If you want to do this 
275 controller-wide (if you have one controller for your admin section) then it's 
276 best to add a user check to a '!begin' action:
277
278     sub begin : Private {
279         my ($self, $c) = @_;
280         unless ($c->req->{user}) {
281             $c->req->action(undef);  ## notice this!!
282             $c->forward('?login');
283         }
284     }
285
286 Pay attention to $c->req->action(undef). This is needed because of the 
287 way $c->forward works - C<forward> to C<login> gets called, but after that 
288 Catalyst will still execute the action defined in the URI (e.g. if you 
289 tried to go to C</add>, then first 'begin' will forward to 'login', but after
290 that 'add' will nonetheless be executed). So $c->req->action(undef) undefines any 
291 actions that were to be called and forwards the user where we want him/her 
292 to be.
293
294 And this is all you need to do. 
295
296 =head2 Pass-through login (and other actions)
297
298 An easy way of having assorted actions that occur during the processing
299 of a request that are orthogonal to its actual purpose - logins, silent
300 commands etc. Provide actions for these, but when they're required for
301 something else fill e.g. a form variable __login and have a sub begin
302 like so:
303
304     sub begin : Private {
305       my ($self, $c) = @_;
306       foreach my $action (qw/login docommand foo bar whatever/) {
307         if ($c->req->params->{"__${action}"}) {
308           $c->forward($action);
309         }
310       }
311     }
312
313 =head2 How to use Catalyst without mod_perl
314
315 Catalyst applications give optimum performance when run under mod_perl.
316 However sometimes mod_perl is not an option, and running under CGI is 
317 just too slow.  There's also an alternative to mod_perl that gives
318 reasonable performance named FastCGI.
319
320 B<Using FastCGI>
321
322 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language 
323 independent, scalable, extension to CGI that provides high performance 
324 without the limitations of specific server APIs."  Web server support 
325 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
326 support in the C<FCGI> module.  To convert a CGI Catalyst application 
327 to FastCGI one needs to initialize an C<FCGI::Request> object and loop 
328 while the C<Accept> method returns zero.  The following code shows how 
329 it is done - and it also works as a normal, single-shot CGI script.
330
331     #!/usr/bin/perl
332     use strict;
333     use FCGI;
334     use MyApp;
335
336     my $request = FCGI::Request();
337     while ($request->Accept() >= 0) {
338         MyApp->run;
339     }
340
341 Any initialization code should be included outside the request-accept 
342 loop.
343
344 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
345 complete HTTP response including the status line (e.g.: 
346 "C<HTTP/1.1 200>").
347 FastCGI just wants a set of headers, so the sample code captures the 
348 output and  drops the first line if it is an HTTP status line (note: 
349 this may change).
350
351 The Apache C<mod_fastcgi> module is provided by a number of Linux 
352 distros and is straightforward to compile for most Unix-like systems.  
353 The module provides a FastCGI Process Manager, which manages FastCGI 
354 scripts.  You configure your script as a FastCGI script with the 
355 following Apache configuration directives:
356
357     <Location /fcgi-bin>
358        AddHandler fastcgi-script fcgi
359     </Location>
360
361 or:
362
363     <Location /fcgi-bin>
364        SetHandler fastcgi-script
365        Action fastcgi-script /path/to/fcgi-bin/fcgi-script
366     </Location>
367
368 C<mod_fastcgi> provides a number of options for controlling the FastCGI
369 scripts spawned; it also allows scripts to be run to handle the
370 authentication, authorization, and access check phases.
371
372 For more information see the FastCGI documentation, the C<FCGI> module 
373 and L<http://www.fastcgi.com/>.
374  
375 =head2 Serving static content
376
377 Serving static content in Catalyst can be somewhat tricky; this recipe
378 shows one possible solution. Using this recipe will serve all static
379 content through Catalyst when developing with the built-in HTTP::Daemon
380 server, and will make it easy to use Apache to serve the content when
381 your app goes into production.
382
383 Static content is best served from a single directory within your root
384 directory. Having many different directories such as C<root/css> and
385 C<root/images> requires more code to manage, because you must separately
386 identify each static directory--if you decide to add a C<root/js>
387 directory, you'll need to change your code to account for it. In
388 contrast, keeping all static directories as subdirectories of a main
389 C<root/static> directory makes things much easier to manager. Here's an
390 example of a typical root directory structure:
391
392     root/
393     root/content.tt
394     root/controller/stuff.tt
395     root/header.tt
396     root/static/
397     root/static/css/main.css
398     root/static/images/logo.jpg
399     root/static/js/code.js
400
401
402 All static content lives under C<root/static> with everything else being
403 Template Toolkit files. Now you can identify the static content by
404 matching C<static> from within Catalyst.
405
406 =head3 Serving with HTTP::Daemon (myapp_server.pl)
407
408 To serve these files under the standalone server, we first must load the
409 Static plugin. Install L<Catalyst::Plugin::Static> if it's not already
410 installed.
411
412 In your main application class (MyApp.pm), load the plugin:
413
414     use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
415
416 You will also need to make sure your end method does I<not> forward
417 static content to the view, perhaps like this:
418
419     sub end : Private {
420         my ( $self, $c ) = @_;
421
422         $c->forward( 'MyApp::V::TT' ) 
423           unless ( $c->res->body || !$c->stash->{template} );
424     }
425
426 This code will only forward to the view if a template has been
427 previously defined by a controller and if there is not already data in
428 C<$c-E<gt>res-E<gt>body>.
429
430 Next, create a controller to handle requests for the /static path. Use
431 the Helper to save time. This command will create a stub controller as
432 C<lib/MyApp/C/Static.pm>.
433
434     $ script/myapp_create.pl controller Static
435
436 Edit the file and add the following methods:
437
438     # serve all files under /static as static files
439     sub default : Path('/static') {
440         my ( $self, $c ) = @_;
441     
442         # Optional, allow the browser to cache the content
443         $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
444
445         $c->serve_static; # from Catalyst::Plugin::Static
446     }
447
448     # also handle requests for /favicon.ico
449     sub favicon : Path('/favicon.ico') {
450         my ( $self, $c ) = @_;
451     
452         $c->serve_static;
453     }
454
455 You can also define a different icon for the browser to use instead of
456 favicon.ico by using this in your HTML header:
457
458     <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
459
460 =head3 Common problems
461
462 The Static plugin makes use of the C<shared-mime-info> package to
463 automatically determine MIME types. This package is notoriously
464 difficult to install, especially on win32 and OSX. For OSX the easiest
465 path might be to install Fink, then use C<apt-get install
466 shared-mime-info>. Restart the server, and everything should be fine.
467
468 Make sure you are using the latest version (>= 0.16) for best
469 results. If you are having errors serving CSS files, or if they get
470 served as text/plain instead of text/css, you may have an outdated
471 shared-mime-info version. You may also wish to simply use the following
472 code in your Static controller:
473
474     if ($c->req->path =~ /css$/i) {
475         $c->serve_static( "text/css" );
476     } else {
477         $c->serve_static;
478     }
479
480 =head3 Serving with Apache
481
482 When using Apache, you can completely bypass Catalyst and the Static
483 controller by intercepting requests for the C<root/static> path at the
484 server level. All that is required is to define a DocumentRoot and add a
485 separate Location block for your static content. Here is a complete
486 config for this application under mod_perl 1.x; variations, some of
487 which could be simpler, are left as an exercise for the reader:
488
489     <Perl>
490         use lib qw(/var/www/MyApp/lib);
491     </Perl>
492     PerlModule MyApp
493     
494     <VirtualHost *>
495         ServerName myapp.example.com
496         DocumentRoot /var/www/MyApp/root
497         <Location />
498             SetHandler perl-script
499             PerlHandler MyApp
500         </Location>
501         <LocationMatch "/(static|favicon.ico)">
502             SetHandler default-handler
503         </LocationMatch>
504     </VirtualHost>
505
506 =head2 Forwarding with arguments
507
508 Sometimes you want to pass along arguments when forwarding to another
509 action. As of version 5.30, arguments can be passed in the call to
510 C<forward>; in earlier versions, you can manually set the arguments in
511 the Catalyst Request object:
512
513   # version 5.30 and later:
514   $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
515
516   # pre-5.30
517   $c->req->args([qw/arg1 arg2 arg3/]);
518   $c->forward('/wherever');
519
520 (See L<Catalyst::Manual::Intro#Flow_Control> for more information on
521 passing arguments via C<forward>.)
522
523 =head1 AUTHOR
524
525 Sebastian Riedel, C<sri@oook.de>
526 Danijel Milicevic, C<me@danijel.de>
527 Viljo Marrandi, C<vilts@yahoo.com>  
528 Marcus Ramberg, C<mramberg@cpan.org>  
529 Andy Grundman, C<andy@hybridized.org> 
530 Marcus Ramberg C<mramberg@cpan.org>
531
532 =head1 COPYRIGHT
533
534 This program is free software, you can redistribute it and/or modify it
535 under the same terms as Perl itself.