=head1 NAME

Catalyst::Manual::Cookbook - Cooking with Catalyst

=head1 DESCRIPTION

Yummy code like your mum used to bake!

=head1 RECIPES

=head2 Force debug screen

You can force Catalyst to display the debug screen at the end of the request by
placing a C<die()> call in the C<end> action.

     sub end : Private {
         my ( $self, $c ) = @_;
         die "forced debug";
     }

If you're tired of removing and adding this all the time, you can add a
condition in the C<end> action. For example:

    sub end : Private {  
        my ( $self, $c ) = @_;  
        die "forced debug" if $c->req->params->{dump_info};  
    }  

Then just add to your query string C<"&dump_info=1">, or the like, to
force debug output.


=head2 Disable statistics

Just add this line to your application class if you don't want those nifty
statistics in your debug messages.

    sub Catalyst::Log::info { }

=head2 Scaffolding

Scaffolding is very simple with Catalyst.

The recommended way is to use Catalyst::Helper::Controller::Scaffold.

Just install this module, and to scaffold a Class::DBI Model class, do the following:

./script/myapp_create controller <name> Scaffold <CDBI::Class>Scaffolding




=head2 File uploads

=head3 Single file upload with Catalyst

To implement uploads in Catalyst, you need to have a HTML form similar to
this:

    <form action="/upload" method="post" enctype="multipart/form-data">
      <input type="hidden" name="form_submit" value="yes">
      <input type="file" name="my_file">
      <input type="submit" value="Send">
    </form>

It's very important not to forget C<enctype="multipart/form-data"> in
the form.

Catalyst Controller module 'upload' action:

    sub upload : Global {
        my ($self, $c) = @_;

        if ( $c->request->parameters->{form_submit} eq 'yes' ) {

            if ( my $upload = $c->request->upload('my_file') ) {

                my $filename = $upload->filename;
                my $target   = "/tmp/upload/$filename";

                unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
                    die( "Failed to copy '$filename' to '$target': $!" );
                }
            }
        }

        $c->stash->{template} = 'file_upload.html';
    }

=head3 Multiple file upload with Catalyst

Code for uploading multiple files from one form needs a few changes:

The form should have this basic structure:

    <form action="/upload" method="post" enctype="multipart/form-data">
      <input type="hidden" name="form_submit" value="yes">
      <input type="file" name="file1" size="50"><br>
      <input type="file" name="file2" size="50"><br>
      <input type="file" name="file3" size="50"><br>
      <input type="submit" value="Send">
    </form>

And in the controller:

    sub upload : Local {
        my ($self, $c) = @_;

        if ( $c->request->parameters->{form_submit} eq 'yes' ) {

            for my $field ( $c->req->upload ) {

                my $upload   = $c->req->upload($field);
                my $filename = $upload->filename;
                my $target   = "/tmp/upload/$filename";

                unless ( $upload->link_to($target) || $upload->copy_to($target) ) {
                    die( "Failed to copy '$filename' to '$target': $!" );
                }
            }
        }

        $c->stash->{template} = 'file_upload.html';
    }

C<for my $field ($c-E<gt>req->upload)> loops automatically over all file
input fields and gets input names. After that is basic file saving code,
just like in single file upload.

Notice: C<die>ing might not be what you want to do, when an error
occurs, but it works as an example. A better idea would be to store
error C<$!> in $c->stash->{error} and show a custom error template
displaying this message.

For more information about uploads and usable methods look at
L<Catalyst::Request::Upload> and L<Catalyst::Request>.

=head2 Authentication with Catalyst::Plugin::Authentication

In this example, we'll use the
L<Catalyst::Plugin::Authentication::Store::DBIC> store and the
L<Catalyst::Plugin::Authentication::Credential::Password> credentials.

In the lib/MyApp.pm package, we'll need to change the C<use Catalyst;>
line to include the following modules:

    use Catalyst qw/
        ConfigLoader 
        Authentication
        Authentication::Store::DBIC
        Authentication::Credential::Password
        Session
        Session::Store::FastMmap
        Session::State::Cookie
        HTML::Widget
        Static::Simple
        /;

The Session, Session::Store::* and Session::State::* modules listed above
ensure that we stay logged-in across multiple page-views.

In our MyApp.yml configuration file, we'll need to add:

    authentication:
      dbic:
        user_class: MyApp::Model::DBIC::User
        user_field: username
        password_field: password
        password_type: hashed
        password_hash_type: SHA-1

'user_class' is a DBIx::Class package for your users table.
'user_field' tells which field (column) is used for username lookup.
'password_field' is the password field in your table.
The above settings for 'password_type' and 'password_hash_type' ensure that
the password won't be stored in the database in clear text.

In SQLite, the users table might be something like:

    CREATE TABLE user (
        id       INTEGER PRIMARY KEY,
        username VARCHAR(100),
        password VARCHAR(100)
    );

Now we need to create a DBIC::SchemaLoader component for this database
(changing "myapp.db" to wherever your SQLite database is).

    script/myapp_create.pl model DBIC DBIC::SchemaLoader 'dbi:SQLite:myapp.db'

Now we can start creating our page controllers and templates.
For our homepage, we create the file "root/index.tt" containing:

    <html>
    <body>
    [% IF c.user %]
        <p>hello [% c.user.username %]</p>
        <p><a href="[% c.uri_for( '/logout' ) %]">logout</a></p>
    [% ELSE %]
        <p><a href="[% c.uri_for( '/login' ) %]">login</a></p>
    [% END %]
    </body>
    </html>

If the user is logged in, they will be shown their name, and a logout link.
Otherwise, they will be shown a login link.

To display the homepage, we can uncomment the C<default> and C<end>
subroutines in lib/MyApp/Controller/Root.pm and populate them as so:

    sub default : Private {
        my ( $self, $c ) = @_;
    
        $c->stash->{template} = 'index.tt';
    }

    sub end : Private {
        my ( $self, $c ) = @_;
    
        $c->forward( $c->view('TT') )
            unless $c->response->body || $c->response->redirect;
    }

The login template is very simple, as L<HTML::Widget> will handle the
HTML form creation for use. This is saved as "root/login.tt".

    <html>
    <head>
    <link href="[% c.uri_for('/static/simple.css') %]" rel="stylesheet" type="text/css">
    </head>
    <body>
    [% result %]
    </body>
    </html>

For the HTML form to look correct, we also copy the C<simple.css> file
from the L<HTML::Widget> distribution into our "root/static" folder.
This file is automatically server by the L<Catalyst::Plugin::Static::Simple>
module which we loaded in our lib/MyApp.pm package.

To handle login requests, we first create a controller, like so:

    script/myapp_create.pl controller Login

In the lib/MyApp/Controller/Login.pm package, we can then uncomment the
C<default> subroutine, and populate it, as below.

First the widget is created, it needs the 'action' set, and 'username' and
'password' fields and a submit button added.

Then, if we've received a username and password in the request, we attempt
to login. If successful, we redirect to the homepage; if not the login form
will be displayed again.

    sub default : Private {
        my ( $self, $c ) = @_;
    
        $c->widget->method('POST')->action( $c->uri_for('/login') );
        $c->widget->element( 'Textfield', 'username' )->label( 'Username' );
        $c->widget->element( 'Password', 'password' )->label( 'Password' );
        $c->widget->element( 'Submit' )->value( 'Login' );
        
        my $result = $c->widget->process( $c->req );
        
        if ( my $user = $result->param('username')
            and my $pass = $result->param('password') )
        {    
            if ( $c->login( $user, $pass ) ) {
                $c->response->redirect( $c->uri_for( "/" ) );
                return;
            }
        }
        
        $c->stash->{template} = 'login.tt';
        $c->stash->{result}   = $result;
    }

To handle logout's, we create a new controller:

    script/myapp_create.pl controller Logout

Then in the lib/MyApp/Controller/Logout.pm package, we change the
C<default> subroutine, to logout and then redirect back to the
homepage.

    sub default : Private {
        my ( $self, $c ) = @_;
    
        $c->logout;
        
        $c->response->redirect( $c->uri_for( "/" ) );
    }

Remember that to test this, we would first need to add a user to the
database, ensuring that the password field is saved as the SHA1 hash
of our desired password.


=head2 Pass-through login (and other actions)

An easy way of having assorted actions that occur during the processing
of a request that are orthogonal to its actual purpose - logins, silent
commands etc. Provide actions for these, but when they're required for
something else fill e.g. a form variable __login and have a sub begin
like so:

    sub begin : Private {
      my ($self, $c) = @_;
      foreach my $action (qw/login docommand foo bar whatever/) {
        if ($c->req->params->{"__${action}"}) {
          $c->forward($action);
        }
      }
    }

=head2 How to use Catalyst without mod_perl

Catalyst applications give optimum performance when run under mod_perl.
However sometimes mod_perl is not an option, and running under CGI is 
just too slow.  There's also an alternative to mod_perl that gives
reasonable performance named FastCGI.

=head3 Using FastCGI

To quote from L<http://www.fastcgi.com/>: "FastCGI is a language 
independent, scalable, extension to CGI that provides high performance 
without the limitations of specific server APIs."  Web server support 
is provided for Apache in the form of C<mod_fastcgi> and there is Perl
support in the C<FCGI> module.  To convert a CGI Catalyst application 
to FastCGI one needs to initialize an C<FCGI::Request> object and loop 
while the C<Accept> method returns zero.  The following code shows how 
it is done - and it also works as a normal, single-shot CGI script.

    #!/usr/bin/perl
    use strict;
    use FCGI;
    use MyApp;

    my $request = FCGI::Request();
    while ($request->Accept() >= 0) {
        MyApp->run;
    }

Any initialization code should be included outside the request-accept 
loop.

There is one little complication, which is that C<MyApp-E<gt>run> outputs a
complete HTTP response including the status line (e.g.: 
"C<HTTP/1.1 200>").
FastCGI just wants a set of headers, so the sample code captures the 
output and  drops the first line if it is an HTTP status line (note: 
this may change).

The Apache C<mod_fastcgi> module is provided by a number of Linux 
distro's and is straightforward to compile for most Unix-like systems.  
The module provides a FastCGI Process Manager, which manages FastCGI 
scripts.  You configure your script as a FastCGI script with the 
following Apache configuration directives:

    <Location /fcgi-bin>
       AddHandler fastcgi-script fcgi
    </Location>

or:

    <Location /fcgi-bin>
       SetHandler fastcgi-script
       Action fastcgi-script /path/to/fcgi-bin/fcgi-script
    </Location>

C<mod_fastcgi> provides a number of options for controlling the FastCGI
scripts spawned; it also allows scripts to be run to handle the
authentication, authorization, and access check phases.

For more information see the FastCGI documentation, the C<FCGI> module 
and L<http://www.fastcgi.com/>.

=head2 Serving static content

Serving static content in Catalyst can be somewhat tricky; this recipe
shows one possible solution. Using this recipe will serve all static
content through Catalyst when developing with the built-in HTTP::Daemon
server, and will make it easy to use Apache to serve the content when
your app goes into production.

Static content is best served from a single directory within your root
directory. Having many different directories such as C<root/css> and
C<root/images> requires more code to manage, because you must separately
identify each static directory--if you decide to add a C<root/js>
directory, you'll need to change your code to account for it. In
contrast, keeping all static directories as subdirectories of a main
C<root/static> directory makes things much easier to manager. Here's an
example of a typical root directory structure:

    root/
    root/content.tt
    root/controller/stuff.tt
    root/header.tt
    root/static/
    root/static/css/main.css
    root/static/images/logo.jpg
    root/static/js/code.js


All static content lives under C<root/static> with everything else being
Template Toolkit files. Now you can identify the static content by
matching C<static> from within Catalyst.

=head3 Serving with HTTP::Daemon (myapp_server.pl)

To serve these files under the standalone server, we first must load the
Static plugin. Install L<Catalyst::Plugin::Static> if it's not already
installed.

In your main application class (MyApp.pm), load the plugin:

    use Catalyst qw/-Debug FormValidator Static OtherPlugin/;

You will also need to make sure your end method does I<not> forward
static content to the view, perhaps like this:

    sub end : Private {
        my ( $self, $c ) = @_;

        $c->forward( 'MyApp::V::TT' ) 
          unless ( $c->res->body || !$c->stash->{template} );
    }

This code will only forward to the view if a template has been
previously defined by a controller and if there is not already data in
C<$c-E<gt>res-E<gt>body>.

Next, create a controller to handle requests for the /static path. Use
the Helper to save time. This command will create a stub controller as
C<lib/MyApp/C/Static.pm>.

    $ script/myapp_create.pl controller Static

Edit the file and add the following methods:

    # serve all files under /static as static files
    sub default : Path('/static') {
        my ( $self, $c ) = @_;

        # Optional, allow the browser to cache the content
        $c->res->headers->header( 'Cache-Control' => 'max-age=86400' );

        $c->serve_static; # from Catalyst::Plugin::Static
    }

    # also handle requests for /favicon.ico
    sub favicon : Path('/favicon.ico') {
        my ( $self, $c ) = @_;

        $c->serve_static;
    }

You can also define a different icon for the browser to use instead of
favicon.ico by using this in your HTML header:

    <link rel="icon" href="/static/myapp.ico" type="image/x-icon" />

=head3 Common problems

The Static plugin makes use of the C<shared-mime-info> package to
automatically determine MIME types. This package is notoriously
difficult to install, especially on win32 and OS X. For OS X the easiest
path might be to install Fink, then use C<apt-get install
shared-mime-info>. Restart the server, and everything should be fine.

Make sure you are using the latest version (>= 0.16) for best
results. If you are having errors serving CSS files, or if they get
served as text/plain instead of text/css, you may have an outdated
shared-mime-info version. You may also wish to simply use the following
code in your Static controller:

    if ($c->req->path =~ /css$/i) {
        $c->serve_static( "text/css" );
    } else {
        $c->serve_static;
    }

=head3 Serving with Apache

When using Apache, you can completely bypass Catalyst and the Static
controller by intercepting requests for the C<root/static> path at the
server level. All that is required is to define a DocumentRoot and add a
separate Location block for your static content. Here is a complete
config for this application under mod_perl 1.x:

    <Perl>
        use lib qw(/var/www/MyApp/lib);
    </Perl>
    PerlModule MyApp

    <VirtualHost *>
        ServerName myapp.example.com
        DocumentRoot /var/www/MyApp/root
        <Location />
            SetHandler perl-script
            PerlHandler MyApp
        </Location>
        <LocationMatch "/(static|favicon.ico)">
            SetHandler default-handler
        </LocationMatch>
    </VirtualHost>

And here's a simpler example that'll get you started:

    Alias /static/ "/my/static/files/"
    <Location "/static">
        SetHandler none
    </Location>

=head2 Forwarding with arguments

Sometimes you want to pass along arguments when forwarding to another
action. As of version 5.30, arguments can be passed in the call to
C<forward>; in earlier versions, you can manually set the arguments in
the Catalyst Request object:

  # version 5.30 and later:
  $c->forward('/wherever', [qw/arg1 arg2 arg3/]);

  # pre-5.30
  $c->req->args([qw/arg1 arg2 arg3/]);
  $c->forward('/wherever');

(See the L<Catalyst::Manual::Intro> Flow_Control section for more 
information on passing arguments via C<forward>.)

=head2 Configure your application

You configure your application with the C<config> method in your
application class. This can be hard-coded, or brought in from a
separate configuration file.

=head3 Using YAML

YAML is a method for creating flexible and readable configuration
files. It's a great way to keep your Catalyst application configuration
in one easy-to-understand location.

In your application class (e.g. C<lib/MyApp.pm>):

  use YAML;
  # application setup
  __PACKAGE__->config( YAML::LoadFile(__PACKAGE__->config->{'home'} . '/myapp.yml') );
  __PACKAGE__->setup;

Now create C<myapp.yml> in your application home:

  --- #YAML:1.0
  # DO NOT USE TABS FOR INDENTATION OR label/value SEPARATION!!!
  name:     MyApp

  # session; perldoc Catalyst::Plugin::Session::FastMmap
  session:
    expires:        '3600'
    rewrite:        '0'
    storage:        '/tmp/myapp.session'

  # emails; perldoc Catalyst::Plugin::Email
  # this passes options as an array :(
  email:
    - SMTP
    - localhost

This is equivalent to:

  # configure base package
  __PACKAGE__->config( name => MyApp );
  # configure authentication
  __PACKAGE__->config->{authentication} = {
    user_class => 'MyApp::M::MyDB::Customer',
    ...
  };
  # configure sessions
  __PACKAGE__->config->{session} = {
    expires => 3600,
    ...
  };
  # configure email sending
  __PACKAGE__->config->{email} = [qw/SMTP localhost/];

See also L<YAML>.

=head2 Using existing DBIC (etc.) classes with Catalyst

Many people have existing Model classes that they would like to use with
Catalyst (or, conversely, they want to write Catalyst models that can be
used outside of Catalyst, e.g.  in a cron job). It's trivial to write a
simple component in Catalyst that slurps in an outside Model:

    package MyApp::Model::DB;
    use base qw/Catalyst::Model::DBIC::Schema/;
    __PACKAGE__->config(
        schema_class => 'Some::DBIC::Schema',
        connect_info => ['dbi:SQLite:foo.db', '', '', {AutoCommit=>1}];
    );
    1;

and that's it! Now C<Some::DBIC::Schema> is part of your
Cat app as C<MyApp::Model::DB>.

=head2 Delivering a Custom Error Page

By default, Catalyst will display its own error page whenever it
encounters an error in your application. When running under C<-Debug>
mode, the error page is a useful screen including the error message and
a full Data::Dumper output of the C<$c> context object. When not in
C<-Debug>, users see a simple "Please come back later" screen.

To use a custom error page, use a special C<end> method to short-circuit
the error processing. The following is an example; you might want to
adjust it further depending on the needs of your application (for
example, any calls to C<fillform> will probably need to go into this
C<end> method; see L<Catalyst::Plugin::FillInForm>).

    sub end : Private {
        my ( $self, $c ) = @_;

        if ( scalar @{ $c->error } ) {
            $c->stash->{errors}   = $c->error;
            $c->stash->{template} = 'errors.tt';
            $c->forward('MyApp::View::TT');
            $c->error(0);
        }

        return 1 if $c->response->status =~ /^3\d\d$/;
        return 1 if $c->response->body;

        unless ( $c->response->content_type ) {
            $c->response->content_type('text/html; charset=utf-8');
        }

        $c->forward('MyApp::View::TT');
    }

You can manually set errors in your code to trigger this page by calling

    $c->error( 'You broke me!' );

=head2 Require user logins

It's often useful to restrict access to your application to a set of
registered users, forcing everyone else to the login page until they're
signed in.

To implement this in your application make sure you have a customer
table with username and password fields and a corresponding Model class
in your Catalyst application, then make the following changes:

=head3 lib/MyApp.pm

  use Catalyst qw/
      Authentication
      Authentication::Store::DBIC
      Authentication::Credential::Password
  /;

  __PACKAGE__->config->{authentication}->{dbic} = {
    'user_class'        => 'My::Model::DBIC::User',
    'user_field'        => 'username',
    'password_field'    => 'password'
    'password_type'     => 'hashed',
    'password_hash_type'=> 'SHA-1'
  };

  sub auto : Private {
    my ($self, $c) = @_;
    my $login_path = 'user/login';

    # allow people to actually reach the login page!
    if ($c->request->path eq $login_path) {
      return 1;
    }

    # if a user doesn't exist, force login
    if ( !$c->user_exists ) {
      # force the login screen to be shown
      $c->response->redirect($c->request->base . $login_path);
    }

    # otherwise, we have a user - continue with the processing chain
    return 1;
  }

=head3 lib/MyApp/C/User.pm

  sub login : Path('/user/login') {
    my ($self, $c) = @_;

    # default template
    $c->stash->{'template'} = "user/login.tt";
    # default form message
    $c->stash->{'message'} = 'Please enter your username and password';

    if ( $c->request->param('username') ) {
      # try to log the user in
      # login() is provided by ::Authentication::Credential::Password
      if( $c->login(
        $c->request->param('username'),
        $c->request->param('password'),
        );

        # if login() returns 1, user is now logged in
        $c->response->redirect('/some/page');
      }

      # otherwise we failed to login, try again!
      $c->stash->{'message'} = 
         'Unable to authenticate the login details supplied';
    }
  }

  sub logout : Path('/user/logout') {
    my ($self, $c) = @_;
    # log the user out
    $c->logout;

    # do the 'default' action
    $c->response->redirect($c->request->base);
  }


=head3 root/base/user/login.tt

 [% INCLUDE header.tt %]
 <form action="/user/login" method="POST" name="login_form">
    [% message %]<br />
    <label for="username">username:</label><br />
    <input type="text" id="username" name="username" /><br />

    <label for="password">password:</label><br />
    <input type="password" id="password" name="password" /><br />

    <input type="submit" value="log in" name="form_submit" />
  </form>
  [% INCLUDE footer.tt %]

=head2 Role-based Authorization

For more advanced access control, you may want to consider using role-based
authorization. This means you can assign different roles to each user, e.g.
"user", "admin", etc.

The C<login> and C<logout> methods and view template are exactly the same as
in the previous example.

The L<Catalyst::Plugin::Authorization::Roles> plugin is required when
implementing roles:

 use Catalyst qw/
    Authentication
    Authentication::Credential::Password
    Authentication::Store::Htpasswd
    Authorization::Roles
  /;

Roles are implemented automatically when using
L<Catalyst::Authentication::Store::Htpasswd>:

  # no additional role configuration required
  __PACKAGE__->config->{authentication}{htpasswd} = "passwdfile";

Or can be set up manually when using L<Catalyst::Authentication::Store::DBIC>:

  # Authorization using a many-to-many role relationship
  __PACKAGE__->config->{authorization}{dbic} = {
    'role_class'           => 'My::Model::DBIC::Role',
    'role_field'           => 'name',
    'user_role_user_field' => 'user',

    # DBIx::Class only (omit if using Class::DBI)
    'role_rel'             => 'user_role',

    # Class::DBI only, (omit if using DBIx::Class)
    'user_role_class'      => 'My::Model::CDBI::UserRole'
    'user_role_role_field' => 'role',
  };

To restrict access to any action, you can use the C<check_user_roles> method:

  sub restricted : Local {
     my ( $self, $c ) = @_;

     $c->detach("unauthorized")
       unless $c->check_user_roles( "admin" );

     # do something restricted here
  }

You can also use the C<assert_user_roles> method. This just gives an error if
the current user does not have one of the required roles:

  sub also_restricted : Global {
    my ( $self, $c ) = @_;
    $c->assert_user_roles( qw/ user admin / );
  }

=head1 AUTHOR

Sebastian Riedel, C<sri@oook.de>
Danijel Milicevic, C<me@danijel.de>
Viljo Marrandi, C<vilts@yahoo.com>  
Marcus Ramberg, C<mramberg@cpan.org>
Jesse Sheidlower, C<jester@panix.com>
Andy Grundman, C<andy@hybridized.org> 
Chisel Wright, C<pause@herlpacker.co.uk>
Will Hawes, C<info@whawes.co.uk>
Gavin Henry, C<ghenry@cpan.org> (Spell checking)


=head1 COPYRIGHT

This program is free software, you can redistribute it and/or modify it
under the same terms as Perl itself.
