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 "Testing" if $c->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
72 =head2 Single file upload with Catalyst
74 To implement uploads in Catalyst you need to have a HTML form similiar to
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">
83 It's very important not to forget C<enctype="multipart/form-data"> in form. Uploads will not work without this.
85 Catalyst Controller module 'upload' action:
90 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
92 if ( my $upload = $c->request->upload('my_file') ) {
94 my $filename = $upload->filename;
95 my $target = "/tmp/upload/$filename";
97 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
98 die( "Failed to copy '$filename' to '$target': $!" );
103 $c->stash->{template} = 'file_upload.html';
106 =head2 Multiple file upload with Catalyst
108 Code for uploading multiple files from one form needs little changes compared
109 to single file upload.
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">
126 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
128 for my $field ( $c->req->upload ) {
130 my $upload = $c->req->upload($field);
131 my $filename = $upload->filename;
132 my $target = "/tmp/upload/$filename";
134 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
135 die( "Failed to copy '$filename' to '$target': $!" );
140 $c->stash->{template} = 'file_upload.html';
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
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.
151 For more information about uploads and usable methods look at
152 C<Catalyst::Request::Upload> and C<Catalyst::Request>.
154 =head2 Authentication with Catalyst::Plugin::Authentication::CDBI
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
160 For both variants you'll need the following code in your MyApp package:
162 use Catalyst qw/Session::FastMmap Static Authentication::CDBI/;
164 MyApp->config( authentication => { user_class => 'MyApp::M::MyApp::Users',
165 user_field => 'email',
166 password_field => 'password' });
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.
175 In PostgreSQL, the users table might be something like:
180 surname varchar(100),
181 password varchar(100),
186 We'll discuss the first variant for now:
187 1. user:password login/auth without roles
189 To log in a user you might use an action like this:
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');
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.
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.
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}
216 To log out a user, just call $c->session_logout.
218 Now let's take a look at the second variant:
219 2. user:password login/auth with roles
221 To use roles you need to add the following parameters to MyApp->config in the 'authentication' section:
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',
228 Corresponding tables in PostgreSQL could look like this:
236 CREATE TABLE user_roles (
240 primary key(user_role_id),
241 foreign key(user_id) references users(user_id),
242 foreign key(role_id) references roles(role_id)
245 The 'roles' table is a list of role names and the 'user_role' table is
246 used for the user -> role lookup.
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
254 if ($c->roles(qw/admin/)) {
255 $c->req->output("Your account has the role 'admin.'");
257 $c->req->output("You're not allowed to be here.");
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:
266 sub begin : Private {
268 unless ($c->req->{user}) {
269 $c->req->action(undef); ## notice this!!
270 $c->forward('?login');
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
282 And this is all you need to do.
284 =head2 Pass-through login (and other actions)
286 An easy way of having assorted actions that occur during the processing of
287 a request that are orthogonal to its actual purpose - logins, silent
288 commands etc. Provide actions for these, but when they're required for
289 something else fill e.g. a form variable __login and have a sub begin like so:
291 sub begin : Private {
293 foreach my $action (qw/login docommand foo bar whatever/) {
294 if ($c->req->params->{"__${action}"}) {
295 $c->forward($action);
300 =head2 How to use Catalyst without mod_perl
302 Catalyst applications give optimum performance when run under mod_perl.
303 However sometimes mod_perl is not an option, and running under CGI is
304 just too slow. There's also an alternative to mod_perl that gives
305 reasonable performance named FastCGI.
309 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language
310 independent, scalable, extension to CGI that provides high performance
311 without the limitations of specific server APIs." Web server support
312 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
313 support in the C<FCGI> module. To convert a CGI Catalyst application
314 to FastCGI one needs to initialize an C<FCGI::Request> object and loop
315 while the C<Accept> method returns zero. The following code shows how
316 it is done - and it also works as a normal, single-shot CGI script.
323 my $request = FCGI::Request();
324 while ($request->Accept() >= 0) {
328 Any initialization code should be included outside the request-accept
331 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
332 complete HTTP response including the status line (e.g.:
334 FastCGI just wants a set of headers, so the sample code captures the
335 output and drops the first line if it is an HTTP status line (note:
338 The Apache C<mod_fastcgi> module is provided by a number of Linux
339 distros and is straightforward to compile for most Unix-like systems.
340 The module provides a FastCGI Process Manager, which manages FastCGI
341 scripts. You configure your script as a FastCGI script with the
342 following Apache configuration directives:
345 AddHandler fastcgi-script fcgi
351 SetHandler fastcgi-script
352 Action fastcgi-script /path/to/fcgi-bin/fcgi-script
355 C<mod_fastcgi> provides a number of options for controlling the FastCGI
356 scripts spawned; it also allows scripts to be run to handle the
357 authentication, authorization, and access check phases.
359 For more information see the FastCGI documentation, the C<FCGI> module
360 and L<http://www.fastcgi.com/>.
364 Sebastian Riedel, C<sri@oook.de>
365 Danijel Milicevic C<me@danijel.de>
366 Viljo Marrandi C<vilts@yahoo.com>
367 Marcus Ramberg C<mramberg@cpan.org>
371 This program is free software, you can redistribute it and/or modify it
372 under the same terms as Perl itself.