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:
191 sub 'login' : Local {
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 $c->req->params->{username} and $c->req->params->{password} are html
203 form parameters from a login form. If login succeeds, then
204 $c->req->{user} contains the username of the authenticated user.
206 If you want to remember the user's login status in between further
207 requests, then just use the C<$c-E<gt>session_login> method. Catalyst will
208 create a session id and session cookie and automatically append session
209 id to all urls. So all you have to do is just check $c->req->{user}
212 To log out a user, just call $c->session_logout.
214 Now let's take a look at the second variant:
215 2. user:password login/auth with roles
217 To use roles you need to add the following parameters to MyApp->config in the 'authentication' section:
219 role_class => 'MyApp::M::MyApp::Roles',
220 user_role_class => 'MyApp::M::MyApp::UserRoles',
221 user_role_user_field => 'user_id',
222 user_role_role_field => 'role_id',
224 Corresponding tables in PostgreSQL could look like this:
232 CREATE TABLE user_roles (
236 primary key(user_role_id),
237 foreign key(user_id) references users(user_id),
238 foreign key(role_id) references roles(role_id)
241 The 'roles' table is a list of role names and the 'user_role' table is
242 used for the user -> role lookup.
244 Now if a logged-in user wants to see a location which is allowed only
245 for people with an 'admin' role, in your controller you can check it
250 if ($c->roles(qw/admin/)) {
251 $c->req->output("Your account has the role 'admin.'");
253 $c->req->output("You're not allowed to be here.");
257 One thing you might need is to forward non-authenticated users to a login
258 form if they try to access restricted areas. If you want to do this
259 controller-wide (if you have one controller for your admin section) then it's
260 best to add a user check to a '!begin' action:
262 sub begin : Private {
264 unless ($c->req->{user}) {
265 $c->req->action(undef); ## notice this!!
266 $c->forward('?login');
270 Pay attention to $c->req->action(undef). This is needed because of the
271 way $c->forward works - C<forward> to C<login> gets called, but after that
272 Catalyst will still execute the action defined in the URI (e.g. if you
273 tried to go to C</add>, then first 'begin' will forward to 'login', but after
274 that 'add' will nonetheless be executed). So $c->req->action(undef) undefines any
275 actions that were to be called and forwards the user where we want him/her
278 And this is all you need to do.
281 =head2 How to use Catalyst without mod_perl
283 Catalyst applications give optimum performance when run under mod_perl.
284 However sometimes mod_perl is not an option, and running under CGI is
285 just too slow. There's also an alternative to mod_perl that gives
286 reasonable performance named FastCGI.
290 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language
291 independent, scalable, extension to CGI that provides high performance
292 without the limitations of specific server APIs." Web server support
293 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
294 support in the C<FCGI> module. To convert a CGI Catalyst application
295 to FastCGI one needs to initialize an C<FCGI::Request> object and loop
296 while the C<Accept> method returns zero. The following code shows how
297 it is done - and it also works as a normal, single-shot CGI script.
304 my $request = FCGI::Request();
305 while ($request->Accept() >= 0) {
309 Any initialization code should be included outside the request-accept
312 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
313 complete HTTP response including the status line (e.g.:
315 FastCGI just wants a set of headers, so the sample code captures the
316 output and drops the first line if it is an HTTP status line (note:
319 The Apache C<mod_fastcgi> module is provided by a number of Linux
320 distros and is straightforward to compile for most Unix-like systems.
321 The module provides a FastCGI Process Manager, which manages FastCGI
322 scripts. You configure your script as a FastCGI script with the
323 following Apache configuration directives:
326 AddHandler fastcgi-script fcgi
332 SetHandler fastcgi-script
333 Action fastcgi-script /path/to/fcgi-bin/fcgi-script
336 C<mod_fastcgi> provides a number of options for controlling the FastCGI
337 scripts spawned; it also allows scripts to be run to handle the
338 authentication, authorization, and access check phases.
340 For more information see the FastCGI documentation, the C<FCGI> module
341 and L<http://www.fastcgi.com/>.
345 Sebastian Riedel, C<sri@oook.de>
346 Danijel Milicevic C<me@danijel.de>
347 Viljo Marrandi C<vilts@yahoo.com>
348 Marcus Ramberg C<mramberg@cpan.org>
352 This program is free software, you can redistribute it and/or modify it
353 under the same terms as Perl itself.