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 can add a
22 condition in the C<end> action. For example:
25 my ( $self, $c ) = @_;
26 die "forced debug" if $c->req->params->{dump_info};
29 Then just add to your query string C<"&dump_info=1">, or the like, to
33 =head2 Disable statistics
35 Just add this line to your application class if you don't want those nifty
36 statistics in your debug messages.
38 sub Catalyst::Log::info { }
42 Scaffolding is very simple with Catalyst.
43 Just use Catalyst::Model::CDBI::CRUD as your base class.
45 # lib/MyApp/Model/CDBI.pm
46 package MyApp::Model::CDBI;
49 use base 'Catalyst::Model::CDBI::CRUD';
52 dsn => 'dbi:SQLite:/tmp/myapp.db',
61 use Catalyst 'FormValidator';
64 name => 'My Application',
65 root => '/home/joeuser/myapp/root'
68 sub my_table : Global {
69 my ( $self, $c ) = @_;
70 $c->form( optional => [ MyApp::Model::CDBI::Table->columns ] );
71 $c->forward('MyApp::Model::CDBI::Table');
76 Modify the C<$c-E<gt>form()> parameters to match your needs, and don't
77 forget to copy the templates into the template root. Can't find the
78 templates? They were in the CRUD model distribution, so you can do
79 B<look Catalyst::Model::CDBI::CRUD> from the CPAN shell to find them.
81 Other Scaffolding modules are in development at the time of writing.
83 =head2 Single file upload with Catalyst
85 To implement uploads in Catalyst you need to have a HTML form similiar to
88 <form action="/upload" method="post" enctype="multipart/form-data">
89 <input type="hidden" name="form_submit" value="yes">
90 <input type="file" name="my_file">
91 <input type="submit" value="Send">
94 It's very important not to forget C<enctype="multipart/form-data"> in
97 Catalyst Controller module 'upload' action:
102 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
104 if ( my $upload = $c->request->upload('my_file') ) {
106 my $filename = $upload->filename;
107 my $target = "/tmp/upload/$filename";
109 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
110 die( "Failed to copy '$filename' to '$target': $!" );
115 $c->stash->{template} = 'file_upload.html';
118 =head2 Multiple file upload with Catalyst
120 Code for uploading multiple files from one form needs a few changes:
122 The form should have this basic structure:
124 <form action="/upload" method="post" enctype="multipart/form-data">
125 <input type="hidden" name="form_submit" value="yes">
126 <input type="file" name="file1" size="50"><br>
127 <input type="file" name="file2" size="50"><br>
128 <input type="file" name="file3" size="50"><br>
129 <input type="submit" value="Send">
132 And in the controller:
137 if ( $c->request->parameters->{form_submit} eq 'yes' ) {
139 for my $field ( $c->req->upload ) {
141 my $upload = $c->req->upload($field);
142 my $filename = $upload->filename;
143 my $target = "/tmp/upload/$filename";
145 unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
146 die( "Failed to copy '$filename' to '$target': $!" );
151 $c->stash->{template} = 'file_upload.html';
154 C<for my $field ($c-E<gt>req->upload)> loops automatically over all file
155 input fields and gets input names. After that is basic file saving code,
156 just like in single file upload.
158 Notice: C<die>ing might not be what you want to do, when an error
159 occurs, but it works as an example. A better idea would be to store
160 error C<$!> in $c->stash->{error} and show a custom error template
161 displaying this message.
163 For more information about uploads and usable methods look at
164 L<Catalyst::Request::Upload> and L<Catalyst::Request>.
166 =head2 Authentication with Catalyst::Plugin::Authentication::CDBI
168 There are (at least) two ways to implement authentication with this plugin:
169 1) only checking username and password;
170 2) checking username, password, and the roles the user has
172 For both variants you'll need the following code in your MyApp package:
174 use Catalyst qw/Session::FastMmap Static Authentication::CDBI/;
176 MyApp->config( authentication => { user_class => 'MyApp::M::MyApp::Users',
177 user_field => 'email',
178 password_field => 'password' });
180 'user_class' is a Class::DBI class for your users table.
181 'user_field' tells which field is used for username lookup (might be
182 email, first name, surname etc.).
183 'password_field' is, well, password field in your table and by default
184 password is stored in plain text. Authentication::CDBI looks for 'user'
185 and 'password' fields in table, if they're not defined in the config.
187 In PostgreSQL, the users table might be something like:
192 surname varchar(100),
193 password varchar(100),
198 We'll discuss the first variant for now:
199 1. user:password login/auth without roles
201 To log in a user you might use an action like this:
205 if ($c->req->params->{username}) {
206 $c->session_login($c->req->params->{username},
207 $c->req->params->{password} );
208 if ($c->req->{user}) {
209 $c->forward('?restricted_area');
214 This action should not go in your MyApp class...if it does, it will
215 conflict with the built-in method of the same name. Instead, put it
216 in a Controller class.
218 $c->req->params->{username} and $c->req->params->{password} are html
219 form parameters from a login form. If login succeeds, then
220 $c->req->{user} contains the username of the authenticated user.
222 If you want to remember the user's login status in between further
223 requests, then just use the C<$c-E<gt>session_login> method. Catalyst will
224 create a session id and session cookie and automatically append session
225 id to all urls. So all you have to do is just check $c->req->{user}
228 To log out a user, just call $c->session_logout.
230 Now let's take a look at the second variant:
231 2. user:password login/auth with roles
233 To use roles you need to add the following parameters to MyApp->config in the 'authentication' section:
235 role_class => 'MyApp::M::MyApp::Roles',
236 user_role_class => 'MyApp::M::MyApp::UserRoles',
237 user_role_user_field => 'user_id',
238 user_role_role_field => 'role_id',
240 Corresponding tables in PostgreSQL could look like this:
248 CREATE TABLE user_roles (
252 primary key(user_role_id),
253 foreign key(user_id) references users(user_id),
254 foreign key(role_id) references roles(role_id)
257 The 'roles' table is a list of role names and the 'user_role' table is
258 used for the user -> role lookup.
260 Now if a logged-in user wants to see a location which is allowed only
261 for people with an 'admin' role, in your controller you can check it
266 if ($c->roles(qw/admin/)) {
267 $c->req->output("Your account has the role 'admin.'");
269 $c->req->output("You're not allowed to be here.");
273 One thing you might need is to forward non-authenticated users to a login
274 form if they try to access restricted areas. If you want to do this
275 controller-wide (if you have one controller for your admin section) then it's
276 best to add a user check to a '!begin' action:
278 sub begin : Private {
280 unless ($c->req->{user}) {
281 $c->req->action(undef); ## notice this!!
282 $c->forward('?login');
286 Pay attention to $c->req->action(undef). This is needed because of the
287 way $c->forward works - C<forward> to C<login> gets called, but after that
288 Catalyst will still execute the action defined in the URI (e.g. if you
289 tried to go to C</add>, then first 'begin' will forward to 'login', but after
290 that 'add' will nonetheless be executed). So $c->req->action(undef) undefines any
291 actions that were to be called and forwards the user where we want him/her
294 And this is all you need to do.
296 =head2 Pass-through login (and other actions)
298 An easy way of having assorted actions that occur during the processing
299 of a request that are orthogonal to its actual purpose - logins, silent
300 commands etc. Provide actions for these, but when they're required for
301 something else fill e.g. a form variable __login and have a sub begin
304 sub begin : Private {
306 foreach my $action (qw/login docommand foo bar whatever/) {
307 if ($c->req->params->{"__${action}"}) {
308 $c->forward($action);
313 =head2 How to use Catalyst without mod_perl
315 Catalyst applications give optimum performance when run under mod_perl.
316 However sometimes mod_perl is not an option, and running under CGI is
317 just too slow. There's also an alternative to mod_perl that gives
318 reasonable performance named FastCGI.
322 To quote from L<http://www.fastcgi.com/>: "FastCGI is a language
323 independent, scalable, extension to CGI that provides high performance
324 without the limitations of specific server APIs." Web server support
325 is provided for Apache in the form of C<mod_fastcgi> and there is Perl
326 support in the C<FCGI> module. To convert a CGI Catalyst application
327 to FastCGI one needs to initialize an C<FCGI::Request> object and loop
328 while the C<Accept> method returns zero. The following code shows how
329 it is done - and it also works as a normal, single-shot CGI script.
336 my $request = FCGI::Request();
337 while ($request->Accept() >= 0) {
341 Any initialization code should be included outside the request-accept
344 There is one little complication, which is that C<MyApp-E<gt>run> outputs a
345 complete HTTP response including the status line (e.g.:
347 FastCGI just wants a set of headers, so the sample code captures the
348 output and drops the first line if it is an HTTP status line (note:
351 The Apache C<mod_fastcgi> module is provided by a number of Linux
352 distros and is straightforward to compile for most Unix-like systems.
353 The module provides a FastCGI Process Manager, which manages FastCGI
354 scripts. You configure your script as a FastCGI script with the
355 following Apache configuration directives:
358 AddHandler fastcgi-script fcgi
364 SetHandler fastcgi-script
365 Action fastcgi-script /path/to/fcgi-bin/fcgi-script
368 C<mod_fastcgi> provides a number of options for controlling the FastCGI
369 scripts spawned; it also allows scripts to be run to handle the
370 authentication, authorization, and access check phases.
372 For more information see the FastCGI documentation, the C<FCGI> module
373 and L<http://www.fastcgi.com/>.
375 =head2 Serving static content
377 Serving static content in Catalyst can be somewhat tricky; this recipe
378 shows one possible solution. Using this recipe will serve all static
379 content through Catalyst when developing with the built-in HTTP::Daemon
380 server, and will make it easy to use Apache to serve the content when
381 your app goes into production.
383 Static content is best served from a single directory within your root
384 directory. Having many different directories such as C<root/css> and
385 C<root/images> requires more code to manage, because you must separately
386 identify each static directory--if you decide to add a C<root/js>
387 directory, you'll need to change your code to account for it. In
388 contrast, keeping all static directories as subdirectories of a main
389 C<root/static> directory makes things much easier to manager. Here's an
390 example of a typical root directory structure:
394 root/controller/stuff.tt
397 root/static/css/main.css
398 root/static/images/logo.jpg
399 root/static/js/code.js
402 All static content lives under C<root/static> with everything else being
403 Template Toolkit files. Now you can identify the static content by
404 matching C<static> from within Catalyst.
406 =head3 Serving with HTTP::Daemon (myapp_server.pl)
408 To serve these files under the standalone server, we first must load the
409 Static plugin. Install L<Catalyst::Plugin::Static> if it's not already
412 In your main application class (MyApp.pm), load the plugin:
414 use Catalyst qw/-Debug FormValidator Static OtherPlugin/;
416 You will also need to make sure your end method does I<not> forward
417 static content to the view, perhaps like this:
420 my ( $self, $c ) = @_;
422 $c->forward( 'MyApp::V::TT' )
423 unless ( $c->res->body || !$c->stash->{template} );
426 This code will only forward to the view if a template has been
427 previously defined by a controller and if there is not already data in
428 C<$c-E<gt>res-E<gt>body>.
430 Next, create a controller to handle requests for the /static path. Use
431 the Helper to save time. This command will create a stub controller as
432 C<lib/MyApp/C/Static.pm>.
434 $ script/myapp_create.pl controller Static
436 Edit the file and add the following methods:
438 # serve all files under /static as static files
439 sub default : Path('/static') {
440 my ( $self, $c ) = @_;
442 # Optional, allow the browser to cache the content
443 $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );
445 $c->serve_static; # from Catalyst::Plugin::Static
448 # also handle requests for /favicon.ico
449 sub favicon : Path('/favicon.ico') {
450 my ( $self, $c ) = @_;
455 You can also define a different icon for the browser to use instead of
456 favicon.ico by using this in your HTML header:
458 <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />
460 =head3 Common problems
462 The Static plugin makes use of the C<shared-mime-info> package to
463 automatically determine MIME types. This package is notoriously
464 difficult to install, especially on win32 and OSX. For OSX the easiest
465 path might be to install Fink, then use C<apt-get install
466 shared-mime-info>. Restart the server, and everything should be fine.
468 Make sure you are using the latest version (>= 0.16) for best
469 results. If you are having errors serving CSS files, or if they get
470 served as text/plain instead of text/css, you may have an outdated
471 shared-mime-info version. You may also wish to simply use the following
472 code in your Static controller:
474 if ($c->req->path =~ /css$/i) {
475 $c->serve_static( "text/css" );
480 =head3 Serving with Apache
482 When using Apache, you can completely bypass Catalyst and the Static
483 controller by intercepting requests for the C<root/static> path at the
484 server level. All that is required is to define a DocumentRoot and add a
485 separate Location block for your static content. Here is a complete
486 config for this application under mod_perl 1.x; variations, some of
487 which could be simpler, are left as an exercise for the reader:
490 use lib qw(/var/www/MyApp/lib);
495 ServerName myapp.example.com
496 DocumentRoot /var/www/MyApp/root
498 SetHandler perl-script
501 <LocationMatch "/(static|favicon.ico)">
502 SetHandler default-handler
506 =head2 Forwarding with arguments
508 Sometimes you want to pass along arguments when forwarding to another
509 action. As of version 5.30, arguments can be passed in the call to
510 C<forward>; in earlier versions, you can manually set the arguments in
511 the Catalyst Request object:
513 # version 5.30 and later:
514 $c->forward('/wherever', [qw/arg1 arg2 arg3/]);
517 $c->req->args([qw/arg1 arg2 arg3/]);
518 $c->forward('/wherever');
520 (See L<Catalyst::Manual::Intro#Flow_Control> for more information on
521 passing arguments via C<forward>.)
525 Sebastian Riedel, C<sri@oook.de>
526 Danijel Milicevic, C<me@danijel.de>
527 Viljo Marrandi, C<vilts@yahoo.com>
528 Marcus Ramberg, C<mramberg@cpan.org>
529 Andy Grundman, C<andy@hybridized.org>
530 Marcus Ramberg C<mramberg@cpan.org>
534 This program is free software, you can redistribute it and/or modify it
535 under the same terms as Perl itself.