3 Catalyst::Manual::Cookbook - Cooking with Catalyst
7 Yummy code like your mum used to bake!
11 =head2 Force debug screen
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.
17 my ( $self, $c ) = @_;
21 If you're tired of removing and adding this all the time, you
22 can easily add a condition. For example:
24 die "force debug" if $c->req->params->{dump_info};
26 =head2 Disable statistics
28 Just add this line to your application class if you don't want those nifty
29 statistics in your debug messages.
31 sub Catalyst::Log::info { }
35 Scaffolding is very simple with Catalyst.
36 Just use Catalyst::Model::CDBI::CRUD as your base class.
38 # lib/MyApp/Model/CDBI.pm
39 package MyApp::Model::CDBI;
42 use base 'Catalyst::Model::CDBI::CRUD';
45 dsn => 'dbi:SQLite:/tmp/myapp.db',
54 use Catalyst 'FormValidator';
57 name => 'My Application',
58 root => '/home/joeuser/myapp/root'
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');
69 Modify the $c->form() parameters to match your needs, and don't forget to copy
70 the templates into the template root. Can't find the templates? They were in the
71 CRUD model distribution, so you can do B<look Catalyst::Model::CDBI::CRUD> from
72 the CPAN shell to find them.
74 =head2 Single file upload with Catalyst
76 To implement uploads in Catalyst you need to have a HTML form similiar to
79 <form action="/upload" method="post" enctype="multipart/form-data">
80 <input type="hidden" name="form_submit" value="yes">
81 <input type="file" name="my_file">
82 <input type="submit" value="Send">
85 It's very important not to forget C<enctype="multipart/form-data"> in form. Uploads will not work without this.
87 Catalyst Controller module 'upload' action:
92 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
94 if ( my $upload = $c->request->upload('my_file') ) {
96 my $filename = $upload->filename;
97 my $target = "/tmp/upload/$filename";
99 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
100 die( "Failed to copy '$filename' to '$target': $!" );
105 $c->stash->{template} = 'file_upload.html';
108 =head2 Multiple file upload with Catalyst
110 Code for uploading multiple files from one form needs little changes compared
111 to single file upload.
115 <form action="/upload" method="post" enctype="multipart/form-data">
116 <input type="hidden" name="form_submit" value="yes">
117 <input type="file" name="file1" size="50"><br>
118 <input type="file" name="file2" size="50"><br>
119 <input type="file" name="file3" size="50"><br>
120 <input type="submit" value="Send">
128 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
130 for my $field ( $c->req->upload ) {
132 my $upload = $c->req->upload($field);
133 my $filename = $upload->filename;
134 my $target = "/tmp/upload/$filename";
136 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
137 die( "Failed to copy '$filename' to '$target': $!" );
142 $c->stash->{template} = 'file_upload.html';
145 C<for my $field ($c-E<gt>req->upload)> loops automatically over all file input
146 fields and gets input names. After that is basic file saving code, just like in
149 Notice: C<die>ing might not be what you want to do, when an error occurs, but
150 it works as an example. A better idea would be to store error C<$!> in
151 $c->stash->{error} and show a custom error template displaying this message.
153 For more information about uploads and usable methods look at
154 C<Catalyst::Request::Upload> and C<Catalyst::Request>.
156 =head2 Authentication with Catalyst::Plugin::Authentication::CDBI
158 There are (at least) two ways to implement authentication with this plugin:
159 1) only checking username and password;
160 2) checking username, password and the roles the user has
162 For both variants you'll need the following code in your MyApp package:
164 use Catalyst qw/Session::FastMmap Static Authentication::CDBI/;
166 MyApp->config( authentication => { user_class => 'MyApp::M::MyApp::Users',
167 user_field => 'email',
168 password_field => 'password' });
170 'user_class' is a Class::DBI class for your users table.
171 'user_field' tells which field is used for username lookup (might be
172 email, first name, surname etc.).
173 'password_field' is, well, password field in your table and by default
174 password is stored in plain text. Authentication::CDBI looks for 'user'
175 and 'password' fields in table, if they're not defined in the config.
177 In PostgreSQL, the users table might be something like:
182 surname varchar(100),
183 password varchar(100),
188 We'll discuss the first variant for now:
189 1. user:password login/auth without roles
191 To log in a user you might use an action like this:
195 if ($c->req->params->{username}) {
196 $c->session_login($c->req->params->{username},
197 $c->req->params->{password} );
198 if ($c->req->{user}) {
199 $c->forward('?restricted_area');
204 This action should not go in your MyApp class...if it does, it will
205 conflict with the built-in method of the same name. Instead, put it
206 in a Controller class.
208 $c->req->params->{username} and $c->req->params->{password} are html
209 form parameters from a login form. If login succeeds, then
210 $c->req->{user} contains the username of the authenticated user.
212 If you want to remember the user's login status in between further
213 requests, then just use the C<$c-E<gt>session_login> method. Catalyst will
214 create a session id and session cookie and automatically append session
215 id to all urls. So all you have to do is just check $c->req->{user}
218 To log out a user, just call $c->session_logout.
220 Now let's take a look at the second variant:
221 2. user:password login/auth with roles
223 To use roles you need to add the following parameters to MyApp->config in the 'authentication' section:
225 role_class => 'MyApp::M::MyApp::Roles',
226 user_role_class => 'MyApp::M::MyApp::UserRoles',
227 user_role_user_field => 'user_id',
228 user_role_role_field => 'role_id',
230 Corresponding tables in PostgreSQL could look like this:
238 CREATE TABLE user_roles (
242 primary key(user_role_id),
243 foreign key(user_id) references users(user_id),
244 foreign key(role_id) references roles(role_id)
247 The 'roles' table is a list of role names and the 'user_role' table is
248 used for the user -> role lookup.
250 Now if a logged-in user wants to see a location which is allowed only
251 for people with an 'admin' role, in your controller you can check it
256 if ($c->roles(qw/admin/)) {
257 $c->req->output("Your account has the role 'admin.'");
259 $c->req->output("You're not allowed to be here.");
263 One thing you might need is to forward non-authenticated users to a login
264 form if they try to access restricted areas. If you want to do this
265 controller-wide (if you have one controller for your admin section) then it's
266 best to add a user check to a '!begin' action:
268 sub begin : Private {
270 unless ($c->req->{user}) {
271 $c->req->action(undef); ## notice this!!
272 $c->forward('?login');
276 Pay attention to $c->req->action(undef). This is needed because of the
277 way $c->forward works - C<forward> to C<login> gets called, but after that
278 Catalyst will still execute the action defined in the URI (e.g. if you
279 tried to go to C</add>, then first 'begin' will forward to 'login', but after
280 that 'add' will nonetheless be executed). So $c->req->action(undef) undefines any
281 actions that were to be called and forwards the user where we want him/her
284 And this is all you need to do.
286 =head2 Pass-through login (and other actions)
288 An easy way of having assorted actions that occur during the processing of
289 a request that are orthogonal to its actual purpose - logins, silent
290 commands etc. Provide actions for these, but when they're required for
291 something else fill e.g. a form variable __login and have a sub begin like so:
293 sub begin : Private {
295 foreach my $action (qw/login docommand foo bar whatever/) {
296 if ($c->req->params->{"__${action}"}) {
297 $c->forward($action);
302 =head2 How to use Catalyst without mod_perl
304 Catalyst applications give optimum performance when run under mod_perl.
305 However sometimes mod_perl is not an option, and running under CGI is
306 just too slow. There's also an alternative to mod_perl that gives
307 reasonable performance named FastCGI.
311 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language
312 independent, scalable, extension to CGI that provides high performance
313 without the limitations of specific server APIs." Web server support
314 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
315 support in the C<FCGI> module. To convert a CGI Catalyst application
316 to FastCGI one needs to initialize an C<FCGI::Request> object and loop
317 while the C<Accept> method returns zero. The following code shows how
318 it is done - and it also works as a normal, single-shot CGI script.
325 my $request = FCGI::Request();
326 while ($request->Accept() >= 0) {
330 Any initialization code should be included outside the request-accept
333 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
334 complete HTTP response including the status line (e.g.:
336 FastCGI just wants a set of headers, so the sample code captures the
337 output and drops the first line if it is an HTTP status line (note:
340 The Apache C<mod_fastcgi> module is provided by a number of Linux
341 distros and is straightforward to compile for most Unix-like systems.
342 The module provides a FastCGI Process Manager, which manages FastCGI
343 scripts. You configure your script as a FastCGI script with the
344 following Apache configuration directives:
347 AddHandler fastcgi-script fcgi
353 SetHandler fastcgi-script
354 Action fastcgi-script /path/to/fcgi-bin/fcgi-script
357 C<mod_fastcgi> provides a number of options for controlling the FastCGI
358 scripts spawned; it also allows scripts to be run to handle the
359 authentication, authorization, and access check phases.
361 For more information see the FastCGI documentation, the C<FCGI> module
362 and L<http://www.fastcgi.com/>.
364 =head1 Forwarding with a parameter
366 Sometimes you want to pass along arguments when forwarding to another
367 action. This can easily be accomplished like this:
369 $c->req->args([qw/arg1 arg2 arg3/]);
370 $c->forward('/wherever');
374 Sebastian Riedel, C<sri@oook.de>
375 Danijel Milicevic C<me@danijel.de>
376 Viljo Marrandi C<vilts@yahoo.com>
377 Marcus Ramberg C<mramberg@cpan.org>
381 This program is free software, you can redistribute it and/or modify it
382 under the same terms as Perl itself.