Fixed: Applied Cookbook patch
[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 "testing";
19      }
20
21 If you're tired of removing and adding this all the time, you
22 can easily add a condition. For example:
23
24   die "Testing" if $c->params->{dump_info};
25
26 =head2 Disable statistics
27
28 Just add this line to your application class if you don't want those nifty
29 statistics in your debug messages.
30
31     sub Catalyst::Log::info { }
32
33 =head2 Scaffolding
34
35 Scaffolding is very simple with Catalyst.
36 Just use Catalyst::Model::CDBI::CRUD as your base class.
37
38     # lib/MyApp/Model/CDBI.pm
39     package MyApp::Model::CDBI;
40
41     use strict;
42     use base 'Catalyst::Model::CDBI::CRUD';
43
44     __PACKAGE__->config(
45         dsn           => 'dbi:SQLite:/tmp/myapp.db',
46         relationships => 1
47     );
48
49     1;
50
51     # lib/MyApp.pm
52     package MyApp;
53
54     use Catalyst 'FormValidator';
55
56     __PACKAGE__->config(
57         name => 'My Application',
58         root => '/home/joeuser/myapp/root'
59     );
60
61     sub my_table : Global {
62         my ( $self, $c ) = @_;
63         $c->form( optional => [ MyApp::Model::CDBI::Table->columns ] );
64         $c->forward('MyApp::Model::CDBI::Table');
65     }
66
67     1;
68
69 Modify the $c->form() parameters to match your needs, and don't forget to copy
70 the templates. ;)
71
72 =head2 Single file upload with Catalyst
73
74 To implement uploads in Catalyst you need to have a HTML form similiar to
75 this:
76
77     <form action="/upload" method="post" enctype="multipart/form-data">
78       <input type="hidden" name="form_submit" value="yes">
79       <input type="file" name="my_file">
80       <input type="submit" value="Send">
81     </form>
82
83 It's very important not to forget C<enctype="multipart/form-data"> in form. Uploads will not work without this.
84
85 Catalyst Controller module 'upload' action:
86
87     sub upload : Global {
88         my ($self, $c) = @_;
89
90         if ( $c->request->parameters->{form_submit} eq 'yes' ) {
91
92             if ( my $upload = $c->request->upload('my_file') ) {
93             
94                 my $filename = $upload->filename;
95                 my $target   = "/tmp/upload/$filename";
96                 
97                 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
98                     die( "Failed to copy '$filename' to '$target': $!" );
99                 }
100             }
101         }
102         
103         $c->stash->{template} = 'file_upload.html';
104     }
105
106 =head2 Multiple file upload with Catalyst
107
108 Code for uploading multiple files from one form needs little changes compared
109 to single file upload.
110
111 Form goes like this:
112
113     <form action="/upload" method="post" enctype="multipart/form-data">
114       <input type="hidden" name="form_submit" value="yes">
115       <input type="file" name="file1" size="50"><br>
116       <input type="file" name="file2" size="50"><br>
117       <input type="file" name="file3" size="50"><br>
118       <input type="submit" value="Send">
119     </form>
120
121 Controller:
122
123     sub upload : Local {
124         my ($self, $c) = @_;
125
126         if ( $c->request->parameters->{form_submit} eq 'yes' ) {
127
128             for my $field ( $c->req->upload ) {
129
130                 my $upload   = $c->req->upload($field);
131                 my $filename = $upload->filename;
132                 my $target   = "/tmp/upload/$filename";
133                 
134                 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
135                     die( "Failed to copy '$filename' to '$target': $!" );
136                 }
137             }
138         }
139
140         $c->stash->{template} = 'file_upload.html';
141     }
142
143 C<for my $field ($c-E<gt>req->upload)> loops automatically over all file input
144 fields and gets input names. After that is basic file saving code, just like in
145 single file upload.
146
147 Notice: C<die>ing might not be what you want to do, when an error occurs, but
148 it works as an example. A better idea would be to store error C<$!> in
149 $c->stash->{error} and show a custom error template displaying this message.
150
151 For more information about uploads and usable methods look at
152 C<Catalyst::Request::Upload> and C<Catalyst::Request>.
153
154 =head2 Authentication with Catalyst::Plugin::Authentication::CDBI
155
156 There are (at least) two ways to implement authentication with this plugin:
157 1) only checking username and password;
158 2) checking username, password and the roles the user has
159
160 For both variants you'll need the following code in your MyApp package:
161
162     use Catalyst qw/Session::FastMmap Static Authentication::CDBI/;
163
164     MyApp->config( authentication => { user_class => 'MyApp::M::MyApp::Users',
165                                        user_field => 'email',
166                                        password_field => 'password' });
167
168 'user_class' is a Class::DBI class for your users table.
169 'user_field' tells which field is used for username lookup (might be 
170 email, first name, surname etc.).
171 'password_field' is, well, password field in your table and by default 
172 password is stored in plain text. Authentication::CDBI looks for 'user' 
173 and 'password' fields in table, if they're not defined in the config.
174
175 In PostgreSQL, the users table might be something like:
176
177  CREATE TABLE users (
178    user_id   serial,
179    name      varchar(100),
180    surname   varchar(100),
181    password  varchar(100),
182    email     varchar(100),
183    primary key(user_id)
184  );
185
186 We'll discuss the first variant for now:
187 1. user:password login/auth without roles
188
189 To log in a user you might use an action like this:
190
191     sub login : Local {
192         my ($self, $c) = @_;
193         if ($c->req->params->{username}) {
194             $c->session_login($c->req->params->{username}, 
195                               $c->req->params->{password} );
196             if ($c->req->{user}) {
197                 $c->forward('?restricted_area');
198             }
199         }
200     }
201
202 This action should not go in your MyApp class...if it does, it will
203 conflict with the built-in method of the same name.  Instead, put it
204 in a Controller class.
205
206 $c->req->params->{username} and $c->req->params->{password} are html 
207 form parameters from a login form. If login succeeds, then 
208 $c->req->{user} contains the username of the authenticated user.
209
210 If you want to remember the user's login status in between further 
211 requests, then just use the C<$c-E<gt>session_login> method. Catalyst will 
212 create a session id and session cookie and automatically append session 
213 id to all urls. So all you have to do is just check $c->req->{user} 
214 where needed.
215
216 To log out a user, just call $c->session_logout.
217
218 Now let's take a look at the second variant:
219 2. user:password login/auth with roles
220
221 To use roles you need to add the following parameters to  MyApp->config in the 'authentication' section:
222
223     role_class      => 'MyApp::M::MyApp::Roles',
224     user_role_class => 'MyApp::M::MyApp::UserRoles',
225     user_role_user_field => 'user_id',
226     user_role_role_field => 'role_id',
227
228 Corresponding tables in PostgreSQL could look like this:
229
230  CREATE TABLE roles (
231    role_id  serial,
232    name     varchar(100),
233    primary key(role_id)
234  );
235
236  CREATE TABLE user_roles (
237    user_role_id  serial,
238    user_id       int,
239    role_id       int,
240    primary key(user_role_id),
241    foreign key(user_id) references users(user_id),
242    foreign key(role_id) references roles(role_id)
243  );
244
245 The 'roles' table is a list of role names and the 'user_role' table is 
246 used for the user -> role lookup.
247
248 Now if a logged-in user wants to see a location which is allowed only 
249 for people with an 'admin' role, in your controller you can check it 
250 with:
251
252     sub add : Local {
253         my ($self, $c) = @_;
254         if ($c->roles(qw/admin/)) {
255             $c->req->output("Your account has the role 'admin.'");
256         } else {
257             $c->req->output("You're not allowed to be here.");
258         }
259     }
260
261 One thing you might need is to forward non-authenticated users to a login 
262 form if they try to access restricted areas. If you want to do this 
263 controller-wide (if you have one controller for your admin section) then it's 
264 best to add a user check to a '!begin' action:
265
266     sub begin : Private {
267         my ($self, $c) = @_;
268         unless ($c->req->{user}) {
269             $c->req->action(undef);  ## notice this!!
270             $c->forward('?login');
271         }
272     }
273
274 Pay attention to $c->req->action(undef). This is needed because of the 
275 way $c->forward works - C<forward> to C<login> gets called, but after that 
276 Catalyst will still execute the action defined in the URI (e.g. if you 
277 tried to go to C</add>, then first 'begin' will forward to 'login', but after
278 that 'add' will nonetheless be executed). So $c->req->action(undef) undefines any 
279 actions that were to be called and forwards the user where we want him/her 
280 to be.
281
282 And this is all you need to do. 
283
284
285 =head2 How to use Catalyst without mod_perl
286
287 Catalyst applications give optimum performance when run under mod_perl.
288 However sometimes mod_perl is not an option, and running under CGI is 
289 just too slow.  There's also an alternative to mod_perl that gives
290 reasonable performance named FastCGI.
291
292 B<Using FastCGI>
293
294 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language 
295 independent, scalable, extension to CGI that provides high performance 
296 without the limitations of specific server APIs."  Web server support 
297 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
298 support in the C<FCGI> module.  To convert a CGI Catalyst application 
299 to FastCGI one needs to initialize an C<FCGI::Request> object and loop 
300 while the C<Accept> method returns zero.  The following code shows how 
301 it is done - and it also works as a normal, single-shot CGI script.
302
303     #!/usr/bin/perl
304     use strict;
305     use FCGI;
306     use MyApp;
307
308     my $request = FCGI::Request();
309     while ($request->Accept() >= 0) {
310         MyApp->run;
311     }
312
313 Any initialization code should be included outside the request-accept 
314 loop.
315
316 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
317 complete HTTP response including the status line (e.g.: 
318 "C<HTTP/1.1 200>").
319 FastCGI just wants a set of headers, so the sample code captures the 
320 output and  drops the first line if it is an HTTP status line (note: 
321 this may change).
322
323 The Apache C<mod_fastcgi> module is provided by a number of Linux 
324 distros and is straightforward to compile for most Unix-like systems.  
325 The module provides a FastCGI Process Manager, which manages FastCGI 
326 scripts.  You configure your script as a FastCGI script with the 
327 following Apache configuration directives:
328
329     <Location /fcgi-bin>
330        AddHandler fastcgi-script fcgi
331     </Location>
332
333 or:
334
335     <Location /fcgi-bin>
336        SetHandler fastcgi-script
337        Action fastcgi-script /path/to/fcgi-bin/fcgi-script
338     </Location>
339
340 C<mod_fastcgi> provides a number of options for controlling the FastCGI
341 scripts spawned; it also allows scripts to be run to handle the
342 authentication, authorization, and access check phases.
343
344 For more information see the FastCGI documentation, the C<FCGI> module 
345 and L<http://www.fastcgi.com/>.
346
347 =head1 AUTHOR
348
349 Sebastian Riedel, C<sri@oook.de>
350 Danijel Milicevic C<me@danijel.de>
351 Viljo Marrandi C<vilts@yahoo.com>
352 Marcus Ramberg C<mramberg@cpan.org>
353
354 =head1 COPYRIGHT
355
356 This program is free software, you can redistribute it and/or modify it
357 under the same terms as Perl itself.