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->param->{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 $filename = $upload->filename;
131 my $target = "/tmp/upload/$filename";
133 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
134 die( "Failed to copy '$filename' to '$target': $!" );
139 $c->stash->{template} = 'file_upload.html';
142 C<for my $field ($c-E<gt>req->upload)> loops automatically over all file input
143 fields and gets input names. After that is basic file saving code, just like in
146 Notice: C<die>ing might not be what you want to do, when an error occurs, but
147 it works as an example. A better idea would be to store error C<$!> in
148 $c->stash->{error} and show a custom error template displaying this message.
150 For more information about uploads and usable methods look at
151 C<Catalyst::Request::Upload> and C<Catalyst::Request>.
153 =head2 Authentication with Catalyst::Plugin::Authentication::CDBI
155 There are (at least) two ways to implement authentication with this plugin:
156 1) only checking username and password;
157 2) checking username, password and the roles the user has
159 For both variants you'll need the following code in your MyApp package:
161 use Catalyst qw/Session::FastMmap Static Authentication::CDBI/;
163 MyApp->config( authentication => { user_class => 'MyApp::M::MyApp::Users',
164 user_field => 'email',
165 password_field => 'password' });
167 'user_class' is a Class::DBI class for your users table.
168 'user_field' tells which field is used for username lookup (might be
169 email, first name, surname etc.).
170 'password_field' is, well, password field in your table and by default
171 password is stored in plain text. Authentication::CDBI looks for 'user'
172 and 'password' fields in table, if they're not defined in the config.
174 In PostgreSQL, the users table might be something like:
179 surname varchar(100),
180 password varchar(100),
185 We'll discuss the first variant for now:
186 1. user:password login/auth without roles
188 To log in a user you might use an action like this:
190 sub 'login' : Local {
192 if ($c->req->params->{username}) {
193 $c->session_login($c->req->params->{username},
194 $c->req->params->{password} );
195 if ($c->req->{user}) {
196 $c->forward('?restricted_area');
201 $c->req->params->{username} and $c->req->params->{password} are html
202 form parameters from a login form. If login succeeds, then
203 $c->req->{user} contains the username of the authenticated user.
205 If you want to remember the user's login status in between further
206 requests, then just use the C<$c-E<gt>session_login> method. Catalyst will
207 create a session id and session cookie and automatically append session
208 id to all urls. So all you have to do is just check $c->req->{user}
211 To log out a user, just call $c->session_logout.
213 Now let's take a look at the second variant:
214 2. user:password login/auth with roles
216 To use roles you need to add the following parameters to MyApp->config in the 'authentication' section:
218 role_class => 'MyApp::M::MyApp::Roles',
219 user_role_class => 'MyApp::M::MyApp::UserRoles',
220 user_role_user_field => 'user_id',
221 user_role_role_field => 'role_id',
223 Corresponding tables in PostgreSQL could look like this:
231 CREATE TABLE user_roles (
235 primary key(user_role_id),
236 foreign key(user_id) references users(user_id),
237 foreign key(role_id) references roles(role_id)
240 The 'roles' table is a list of role names and the 'user_role' table is
241 used for the user -> role lookup.
243 Now if a logged-in user wants to see a location which is allowed only
244 for people with an 'admin' role, in your controller you can check it
249 if ($c->roles(qw/admin/)) {
250 $c->req->output("Your account has the role 'admin.'");
252 $c->req->output("You're not allowed to be here.");
256 One thing you might need is to forward non-authenticated users to a login
257 form if they try to access restricted areas. If you want to do this
258 controller-wide (if you have one controller for your admin section) then it's
259 best to add a user check to a '!begin' action:
261 sub begin : Private {
263 unless ($c->req->{user}) {
264 $c->req->action(undef); ## notice this!!
265 $c->forward('?login');
269 Pay attention to $c->req->action(undef). This is needed because of the
270 way $c->forward works - C<forward> to C<login> gets called, but after that
271 Catalyst will still execute the action defined in the URI (e.g. if you
272 tried to go to C</add>, then first 'begin' will forward to 'login', but after
273 that 'add' will nonetheless be executed). So $c->req->action(undef) undefines any
274 actions that were to be called and forwards the user where we want him/her
277 And this is all you need to do.
280 =head2 How to use Catalyst without mod_perl
282 Catalyst applications give optimum performance when run under mod_perl.
283 However sometimes mod_perl is not an option, and running under CGI is
284 just too slow. There's also an alternative to mod_perl that gives
285 reasonable performance named FastCGI.
289 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language
290 independent, scalable, extension to CGI that provides high performance
291 without the limitations of specific server APIs." Web server support
292 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
293 support in the C<FCGI> module. To convert a CGI Catalyst application
294 to FastCGI one needs to initialize an C<FCGI::Request> object and loop
295 while the C<Accept> method returns zero. The following code shows how
296 it is done - and it also works as a normal, single-shot CGI script.
303 my $request = FCGI::Request();
304 while ($request->Accept() >= 0) {
308 Any initialization code should be included outside the request-accept
311 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
312 complete HTTP response including the status line (e.g.:
314 FastCGI just wants a set of headers, so the sample code captures the
315 output and drops the first line if it is an HTTP status line (note:
318 The Apache C<mod_fastcgi> module is provided by a number of Linux
319 distros and is straightforward to compile for most Unix-like systems.
320 The module provides a FastCGI Process Manager, which manages FastCGI
321 scripts. You configure your script as a FastCGI script with the
322 following Apache configuration directives:
325 AddHandler fastcgi-script fcgi
331 SetHandler fastcgi-script
332 Action fastcgi-script /path/to/fcgi-bin/fcgi-script
335 C<mod_fastcgi> provides a number of options for controlling the FastCGI
336 scripts spawned; it also allows scripts to be run to handle the
337 authentication, authorization, and access check phases.
339 For more information see the FastCGI documentation, the C<FCGI> module
340 and L<http://www.fastcgi.com/>.
344 Sebastian Riedel, C<sri@oook.de>
345 Danijel Milicevic C<me@danijel.de>
346 Viljo Marrandi C<vilts@yahoo.com>
347 Marcus Ramberg C<mramberg@cpan.org>
351 This program is free software, you can redistribute it and/or modify it
352 under the same terms as Perl itself.