Remove extraneous 'TT bogus assignment' and update comment to still explain situation...
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Manual / Tutorial.pod
index b05112a..af5e1fa 100644 (file)
 =head1 NAME
 
-Catalyst::Manual::Tutorial - Getting started with Catalyst
+Catalyst::Manual::Tutorial - Catalyst Tutorial: Overview
 
 =head1 DESCRIPTION
 
-This document aims to get you up and running with Catalyst.
+The Catalyst framework is a flexible and comprehensive environment for
+quickly building high-functionality web applications.  This tutorial is
+designed to provide a rapid introduction to its basics and its most
+commonly used features while focusing on real-world best practices.
 
-=head2 Installation
+The tutorial is divided into the following sections:
 
-The first step is to install Catalyst, and the simplest way to do this 
-is to install the Catalyst bundle from CPAN:
+=over 4
 
-    $ perl -MCPAN -e 'install Task::Catalyst'
+=item *
 
-This will retrieve Catalyst and a number of useful extensions and 
-install them for you. This process might not be totally painless
-though, and you might want to look at CatInABox 
-L<http://use.perl.org/~jk2addict/journal/28071>, especially if you are
-on a system that lacks a compiler.
+L<Introduction|Catalyst::Manual::Tutorial::Intro>
 
+=item * 
 
-=head2 The very basics - Setting up the skeleton application.
+L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
 
-Catalyst includes a helper script, C<catalyst.pl>, that will set up a 
-skeleton application for you:
+=item * 
 
-    $ catalyst tutorial
+L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
 
-    created "tutorial"
-    created "tutorial/script"
-    ... output snipped
-    created "tutorial/script/tutorial_create.pl"
+=item * 
 
-This creates the directory structure, populated with skeleton 
-files.
+L<Authentication|Catalyst::Manual::Tutorial::Authentication>
 
-=head2 Testing out the skeleton application
+=item * 
 
-You can test out your new application by running the server script that
-Catalyst provides:
+L<Authorization|Catalyst::Manual::Tutorial::Authorization>
 
-    $ cd tutorial
-    $ script/tutorial_server.pl 
+=item * 
 
-    [...] [catalyst] [debug] Debug messages enabled
-    [...] [catalyst] [debug] Loaded plugins:
-    .------------------------------------------------------------------------------.
-    | Catalyst::Plugin::Static::Simple                                             |
-    '------------------------------------------------------------------------------'
-    [...] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
-    [...] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
-    [...] [catalyst] [debug] Found home "/home/users/me/tutorial"
-    [...] [catalyst] [debug] Loaded Private actions:
-    .--------------------------------------+---------------------------------------.
-    | Private                              | Class                                 |
-    +--------------------------------------+---------------------------------------+
-    | /default                             | tutorial                              |
-    '--------------------------------------+---------------------------------------'
+L<Testing|Catalyst::Manual::Tutorial::Testing>
 
-    [...] [catalyst] [info] tutorial powered by Catalyst 5.66
-    You can connect to your server at http://localhost:3000
+=item * 
 
-(Note that each line logged by Catalyst begins with a timestamp, which has
-been replaced here with "C<...>" so that the text fits onto the lines.)
+L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
 
-The server is now waiting for you to make requests of it.  Try using 
-telnet to manually make a simple GET request of the server (when 
-telnet responds with "Escape character is '^]'.", type "GET / HTTP/1.0"
-and hit return twice):
+=item * 
 
-    $ telnet localhost 3000
-    Trying 127.0.0.1...
-    Connected to localhost.
-    Escape character is '^]'.
-    GET / HTTP/1.0
+L<Appendices|Catalyst::Manual::Tutorial::Appendices>
 
-    HTTP/1.0 200 OK
-    Date: Mon, 07 Nov 2005 14:57:39 GMT
-    Content-Length: 5525
-    Content-Type: text/html; charset=utf-8
-    Status: 200
-    X-Catalyst: 5.66
+=back
 
-    [...]
-    Connection closed by foreign host.
-    $
+A tarball of the final application is available at
+C<to_be_compled_in_final_version>.
 
-You can see the full welcome message by visiting
-http://localhost:3000/ with your browser.
+=head1 Detailed Table Of Contents
 
-More trace messages will appear in the original terminal window:
+=head2 Part 1: Introduction
 
-    [...] [catalyst] [debug] **********************************
-    [...] [catalyst] [debug] * Request 1 (0.063/s) [2148]
-    [...] [catalyst] [debug] **********************************
-    [...] [catalyst] [debug] Arguments are ""
-    [...] [catalyst] [debug] "GET" request for "" from localhost
-    [...] [catalyst] [info] Request took 0.046883s (21.330/s)
-    .------------------------------------------------------------------+-----------.
-    | Action                                                           | Time      |
-    +------------------------------------------------------------------+-----------+
-    | /default                                                         | 0.000000s |
-    '------------------------------------------------------------------+-----------'
+=over 4
 
-The server will continue running until you interrupt it.
+=item *
 
-The application can also be tested from the command line using the generated
-helper script, C<script/tutorial_test.pl>.
+VERSIONS AND CONVENTIONS USED IN THIS TUTORIAL
 
-=head2 Getting started
+=item *
 
-So you picked Catalyst. Good choice. I assume you have installed it as
-well. For this tutorial you will also need the following modules:
+CATALYST INSTALLATION
 
-L<Catalyst::Plugin::Session>
+=item *
 
-L<Catalyst::Plugin::Session::Store::File>
+DATABASES
 
-L<Catalyst::Plugin::Session::State::Cookie>
+=item *
 
-L<Catalyst::Plugin::Authentication>
+WHERE TO GET WORKING CODE
 
-L<Catalyst::Plugin::Authentication::Store::Minimal>
+=back
 
-L<Catalyst::Plugin::Authentication::::Minimal>
 
-L<Catalyst::Plugin::Authentication::Credential::Password>
+=head2 Part 2: Catalyst Application Development Basics
 
-L<Catalyst::Plugin::Authorization::Roles>
+=over 4
 
-L<DBD::SQLite>
+=item *
 
-...
+CREATE A CATALYST PROJECT
 
-If you have not already done this following the example above, then to get 
-started all you need to do is type:
+=item *
 
-    catalyst.pl tutorial
+CREATE A SQLITE DATABASE
 
-=for commentary
-Poor choice of application name - searching for "tutorial" in the docs
-also results in discussion of the tutorial process, which is probably
-not what the reader wants.
+=item *
 
-=cut
+EDIT THE LIST OF CATALYST PLUGINS
 
-This should create a directory called F<tutorial> and fill it with the
-default (standard) Catalyst installation. Change to this directory
-because we will be running all further commands from inside the
-F<tutorial> directory.
+=item *
 
-If you now run the built-in mini-server with:
-    
-    script/tutorial_server.pl
+DATABASE ACCESS WITH DBIx::Class
 
-it will show some standard debug messages in the console screen 
-(more about those in a minute), and then inform you that you can now 
-connect to the test server on port 3000. Point your browser at 
-http://localhost:3000/ to see the built-in catalyst welcome screen.
 
-The other important thing B<catalyst.pl> did was create your root
-controller. This file is a standard perl module like all the other
-controllers that you might add to your application. It lives in the
-F<lib/> directory, and will have the same name as you supplied to the
-command above. In our case it is F<tutorial.pm>. Alongside this file is
-a directory of the same name, which is the top level namespace for the
-entire application. Thus every other module we create will be
-"tutorial::something";
+=over 4
 
-The root controller is used to load plugins, to configure the
-application and its plugins, and for generic private actions.  We will
-explain more about those later.
+=item *
 
-=head2 Debugging
+Create a DBIC Schema File
 
-The simplest way to debug your Catalyst application is to run it using
-the built-in mini-server as described in L<Getting started>. 
+=item *
 
-If you want to output any debugging information to the console, then
-call C<< $c->log->debug() >>, passing it a string to output. For
-data structures, use L<Data::Dumper> and call C<<
-$c->log->debug(Dumper($structure)) >>
+Create the DBIC ``Result Source'' Files
 
-=head2 Model/View/Controller
+=item *
 
-The recommended method for code organization in a Catalyst application
-is known as the "Model View Controller" design pattern (also referred to
-"MVC". See L<http://en.wikipedia.org/wiki/Model-view-controller>). 
+Use Catalyst::Model::DBIC::Schema to Load the Model Class
 
-The point of the MVC pattern is to divorce the dependencies of
-parts of the application from each other, and give them standard
-interfaces. Following this theory of organization should give your code
-all the benefits of modularity. The main benefits are interchangeability
-of parts and reusable code.
+=back
 
-Thus you could replace your file data storage with a database or your
-Oracle database with a MySQL database and not have to change any of your
-controlling or view logic. Or you could later decide to output
-information from your application as RSS instead of HTML just by adding
-a new view module.
 
-=head3 Model
+=item *
 
-Models deal with the storage of data. For a complex website, you may
-need multiple varied data sources, each will have it's own model class
-that provides an abstracted interface to it. In this tutorial we are
-going to be using a simple database.
+CREATE A CATALYST CONTROLLER
 
-=head3 View
+=item *
 
-Views are used to display information to the user. In a web framework,
-it is generally used to output HTML to the browser. As mentioned
-previously, views can also be used to output RSS or any other kind of
-data format.  One easy way to do this with Catalyst is to use a
-templating system such as Template Toolkit. If outputting HTML is all
-you are going to do, then you will probably only need one view.
+CATALYST VIEWS
 
-=head3 Controller
 
-A controller deals with reacting to user choices, and thus controls what
-the application does. Since this is a web framework, Catalyst
-controllers are frequently used to react directly to URLs requested by
-the user. This tutorial will describe the simplest way of using
-controllers, where each path or part of a path is assigned its own
-action (or subroutine). More complex controlling mechanisms will be
-mentioned briefly, and can be read about in detail in the manual.
-
-
-=head2 Controlling
-
-Now lets write our first bit of application code. First, we would like
-our application to greet our users. We'll assume for now that our users
-will be sent to the I<users/greet> URL. To create a controller that
-serves the I<users> namespace, we run the following command in our
-F<tutorial> directory:
-
-    script/tutorial_create.pl controller Users
-
-This will create a Users.pm in F<lib/tutorial/Controller>. Open this
-file in an editor and take a look. You will notice there is some
-commented out code which we will ignore for now. To make something
-happen when our URL is visited, we will write a "greet" action which
-looks like this:
-
-  sub greet : Local {
-    my ($self, $c) = @_;
-
-    my $name = $c->req->param('name');
-    $c->log->debug("Got name: $name\n");
-
-    if ($c->req->method eq 'POST') {
-       if(!$name) {
-            $c->stash->{message} = 'Please fill in a name!';
-        }
-        else {
-            $c->stash->{message} = "Hello $name!";     
-        }
-    }
-    $c->stash->{template} = 'greet.tt';
-  }
-
-Whew! So, what does all this do? Lets take it one step at a time.
-The subroutine declaration gives the action a name.  To the right of the
-name there is an attribute type that looks like this:   
-
-    : Local 
-    
-That defines which URIs will translate to this action. "Local", matches
-exactly one URI: 
-
-    /users/greet
-    
-The URI matched by "Local" is composed from the namespace minus the 
-tutorial::controller portion, that is common to all controllers, 
-and the action name itself.  Because it is a URI, we use forward slashes 
-instead of double colons.  So, in summary, when a user requests:
-    http://localhost:3000/users/greet
-    
-the "greet" action defined above in the Users controller will be executed.
-
-The second line retrieves the parameters Catalyst gives us when it calls
-our method. The first is the instance of our Users class, and the second
-is commonly called the context, and named $c.  From now on, whenever we 
-are talking about the context object, it will be represented as $c in 
-the code.
-
-The context is the magical object containing any information you need from 
-catalyst, or want to send to it, and is passed from action to action. 
-You will see it used frequently in Catalyst applications, and a list of all 
-its methods is available in the L<Catalyst> POD.
-
-On the third line we use the ->param method of the context's request object
-to retrieve one of the query parameters, just like in L<CGI>.
-
-On the fourth, we make a debug output of this object on the server console,
-or the error log if running under CGI or mod_perl.
-
-Next, if we have a post request, we check if the name field contains anything 
-(or is "true"), if it isn't, we assign an error message to a "message" field 
-in the stash. The stash is yet another method of the context object, it allows 
-us to pass data on to other methods we call later, most usefully the View 
-modules.
-
-If the username did contain a value, then we just set our message to
-greet the user by name.
-
-Finally, we set the special "template" variable in the stash to the name
-of the template we want our view to use to display this page.
-
-=head2 Viewing
-
-Ok, so reacting and checking the users data is all fine, but how do we
-actually display the page/form in the first place, and our results? As
-previously mentioned, we'll use Template Toolkit for our viewing. To
-create out TT based view, just run the following command:
-
-    script/tutorial_create.pl view TToolkit TT
-
-Notice that this time we not only gave it the type of module we wanted
-to create (a view), and a name, but also a third argument, "TT". This is
-a Catalyst helper module, which will make a standard template toolkit
-module for you. And that's all you need to do there.
-
-To use the view, the easiest way is to set up a standard "end" action.
-This a private action which will not be matched to a path like our
-"greet" action, but instead will be called after all other processing is
-done. Only one end action will be called, if there is one in a
-controller, it will be preferred over one in the application module, and
-so on.
-
-Since we're writing a simple application, just add an end action like
-this to F<tutorial.pm>:
-
-    sub end : Private {
-        my ($self, $c) = @_;
-        $c->forward('tutorial::View::TToolkit') unless $c->res->body();
-    }
-
-The first line declares the end sub, and marks it as a Private action.
-(The second and last attribute type we'll be using). The second line
-collects our standard parameters as shown in the controller's greet action.
-
-The third line directs Catalyst to pass processing on to our TToolkit
-view. The forward method, when just passed a class name, calls process
-on that class. The standard TT view's process method renders the
-template named in the template variable in the stash, using all the
-other variables in the stash as values to fill it in.
-
-NB: This is such a common way to end you processing that there is a
-plugin which does it for you: L<Catalyst::Plugin::DefaultEnd>.
-
-Template Toolkit also has access to the entire context object via "c",
-for example, using [% c.config.name %] in our template will output
-"tutorial", our project name.
-
-All that remains is to create a simple template called "greet.tt",
-containing a form with a text field called "name" like below.
-
-    <html><head><title> [% c.name %]</head><body>
-    <p>[%message%]</p>
-    <form action="[%c.req.uri%]" method="post">
-    <input type="text" name="name"/>
-    <input type="submit" value="Submit" name="submit"/>
-    </form>
-    </body></html>
-
-In the example above, we use [%c.req.uri%], since we're posting to ourself.
-if we post to another action, we commonly use the uri_for method, like this:
-
-    [% c.uri_for('/users/greet')%]
-
-Place this file in the F<root> directory. By default, templates are 
-searched for here, but we can change that, which brings us to...
-
-=head2 Configuring
-
-As previously mentioned, the configuration of modules, plugins and so on
-is done in the main application file. This is especially true for bits
-which need to be done before an instance of them is created, for example
-Template Toolkit.
-
-The TT View looks for its templates in the F<root> directory by default.
-Since this is also the directory that static files go in, we'd rather
-have a separate F<templates> directory. To do this, change the config
-call in F<tutorial.pm> like this:
-
- __PACKAGE__->config( name => 'tutorial',
-                      'View::TToolkit' => {
-                          'INCLUDE_PATH' => __PACKAGE__->path_to('templates')
-     }
-  );
-
-And move the F<greet.tt> file from F<root> to the F<templates> directory
-(after creating it).
-
-Now we can run our application again by killing (B<ctrl-c>) and restarting
-B<script/tutorial_server.pl>. Try connecting to
-I<localhost:3000/users/greet> with a browser and see what happens. What
-happens if you try to visit I<localhost:3000/users> ? 
-
-=head2 Users and Authenticating
-
-One of the many reasons to write dynamic websites instead of just using static 
-HTML, is to allow us to produce different content for different users, as well
- as just restricting access to pages (which we could do with just Apaches 
-htpasswd system).
-
-In this tutorial, we will just be using basic authentication, when writing 
-a real application, you'll want to use a database or other secure store to 
-contain your user data.
-
-To add authentication, all we need to do is add the
-L<Catalyst::Plugin::Authentication> module to our main application file. Then
-we need to pick a storage method (one of the
-L<Catalyst::Plugin::Authentication::Store> modules), and a method of verifying
-the users credentials (one of the
-L<Catalyst::Plugin::Authentication::Credential> modules), so just edit
-F<tutorial.pm> to look like this: 
-
- use Catalyst qw/-Debug Static::Simple Authentication 
-                Authentication::Store::Minimal 
-                Authentication::Credential::Password/;
-
-To configure, add some users to the config call, for example: 
-
- authentication => { 'users' =>
-                       { 'fred' =>
-                           { 'password' => 'fred1234',
-                           }
-                       }
-                   }
-
-Generally, setting up configuration data for plugins is done based on the 
-type of plugin. Check the documentation of the plugin for exact details. The 
-details of this one are in L<Catalyst::Plugin::Authentication::Store::Minimal>.
-
-Since our user data is in the config, we can update it at runtime, and thus 
-add users dynamically. (Of course, to keep them permanently we'll need to 
-export our data to disk and read it back into the config on startup)
-
-To allow creation of new users we'll add a create action to our Users 
-controller.
-
- sub create : Local {
-    my ($self, $c) = @_;
-    my ($username, $passwd1, $passwd2) = map { $c->req->param($_)} 
-       ('username', 'password', 'passwordverify');
-
-    if($username && $passwd1 && $passwd2) {
-       if($c->config->{authentication}{users}{$username}) {
-          $c->stash->{message} = 'Sorry that user already exists';
-          $c->stash->{username} = $username;
-       }
-       elsif($passwd1 eq $passwd2) {
-            $c->config->{authentication}->{users}->{$username} =
-                {password => $passwd1};
-          $c->stash->{message} = 'User created!';
-       }
-       else {
-          $c->stash->{username} = $username;
-          $c->stash->{message} = 'Passwords do not match!';
-       }
-    }
-    $c->stash->{template} = 'usercreate.tt';
- }
-
-All this is doing is checking that all the appropriate fields are filled, 
-the password fields contain the same data, and then adding the user to the 
-config hash.  All the checks produce a message which can be displayed to 
-the user via the View.
-
-The usercreate.tt template looks like this:
-
- <html><head><title>[% c.config.name %]</title></head><body>
- <h1>Create a new user</h1>
- <h2>Current users are:</h2>
- <p>
-    [% FOREACH key = c.config.authentication.users.keys %]
-        [% key %]<br/>
-    [% END %]
- </p>
- <p> [% c.stash.message %] </p>
- <form action="/users/create" method="post">
- <p>User Name: <input type="text" name="username"/></p>
- <p>Password: <input type="password" name="password"/></p>
- <p>Confirm Password: <input type="password" name="passwordverify"/></p>
- <p><input type="submit" name="submit" value="submit"></p>
- </form>
- </body></html>
-
-So our that users can login, we need a login action which we put in the
-Users controller:
-
- sub login : Local {
-     my ($self, $c) = @_;
-     $c->stash->{template} = 'userlogin.tt';
-     if(!$c->login()) {
-             $c->stash->{message} = 'Please login.';
-     }
-     else {
-         $c->stash->{message} = "Welcome " . $c->user->id;
-     }
- }
-
-
-And the userlogin.tt template:
-
- <html><head><title>[% c.config.name %]</title></head><body>
- <p> [% c.stash.message %] </p>
- <form name='login' action='/users/login' method='post'>
- <p>Username: <input type='text' name='user' /></p>
- <p>Password: <input type='password' name='password' /></p>
- <p><input type="submit" /></form>
- </body></html>
-
-
-Verrrry simple. Since Credential::Password's "login" call extracts the 
-username/password data from the query itself (assuming we use a standard 
-name for our form fields), we don't have to do anything but call it.
-
-To keep the user logged in, all we need to do is add the Session modules to 
-our collection, and the Auth modules will automatically use them; 
-
- use Catalyst qw/-Debug Static::Simple Authentication 
-                 Authentication::Store::Minimal 
-                 Authentication::Credential::Password
-                 Session Session::Store::File Session::State::Cookie/;
-
-Magic!
-
-=head2 Exercise
-
-As an exercise for the reader, do the following:
-
-Change users/greet and greet.tt so that the welcome message greets the
-user by name.
-
-Enforce user logging in by adding an auto action in tutorial.pm (see
-the L<Catalyst> documentation to find out about the auto action).
-
-=head2 Authorising
-
-Authentication is about verifying users, Authorisation is about
-allowing them to do things. Catalyst currently has two Authorisation
-modules, Roles and ACL. The Roles module allows you to define groups
-which you can assign your users to, and then allow access to areas of
-your website to the groups. The ACL module lets you do more fine
-grained access/restriction by allowing of denying access however you
-like (It also supports Roles as done by the roles module). This
-example uses L<Catalyst::Plugin::Authorization::Roles>. To use this add
-"Authorization::Roles" into the "use Catalyst" statement in
-tutorial.pm.
-
-Adding Roles via the Minimal store we are already using is quite simple,
-we just add a roles key to each user, defining the names of the roles
-they belong to.
-
- authentication => { 'users' =>
-                            { 'fred' => 
-                               { 'password' => 'fred1234',
-                                 'roles'       => ['admin']
-                               }
-                            }
-                         }
-
-We need an interface for our admins to administer the roles, i.e. assign
-the users to groups. To restrict access to certain actions, we just need
-to call C<< $c->check_user_roles() >> in each action. So we can
-make a restricted I<http://localhost:3000/users/groups> page like this:
-
- sub groups : Local {
-    my ($self, $c) = @_;
-    if($c->check_user_roles('admin')) {
-       # Now we can do things only an admin will see
-       if(my $params = $c->req->params) {
-          my $users = $c->config->{authentication}{users};
-          foreach my $u (keys %$params) {
-             $users->{$u}{roles} = $params->{$u} if($users->{$u});
-          }
-          $c->stash->{message} = 'Updated user roles!';
-       }
-       else {
-           $c->stash->{users} = $c->config->{authentication};
-       }
-       $c->stash->{template} = 'usersgroups.tt';
-    }
-    else {
-        $c->stash->{message} = 'Admins Only!';
-        $c->stash->{template} = 'error.tt';
-    }
- }
-
-What we are doing here is checking whether the logged in user (used by
-default in the check_user_roles method), is a member of the admin group.
-If it is, then we display the usergroups template, and update the users
-hash as required. Otherwise, we just show the user an error page.
-
-For this simple example, the usersgroups.tt and error.tt templates could
-both look like this:
-
- <html><head><title>[% c.config.name %]</title></head><body>
- <p>[% c.stash.message %]</p>
- <p>[% c.stash.users %]</p>
- </body></html>
-
-And that's all there is to it.
-
-=for authors
-So it's not clear what the groups action is doing - and with the
-current template, nothing happens.  Running through the sample code,
-it's clear what's happening, (which is very little), but the purpose,
-and how to display data is not clear.
-
-=cut
-
-So that you can test this out properly without having to go to the
-trouble of deleting browser cookies manually, we will add a logout
-action in the Users controller:
-
- sub logout : Local {
-    my ($self, $c) = @_;
-    $c->stash->{message} = "You have successfully logged out";
-    $c->logout;
- }
-
-
-=head2 Data Storage (Modelling)
-
-Whether we want our users to be able to contribute to our website, or just
-create it from changeable data, we need to store the data somewhere. Generally
-this is done using a database, models can also be other data sources, for
-example another website, or RSS feeds. 
-
-If you have or want a database, there are still choices to be made, there are
-several modules about for accessing databases via OO. The best known are
-probably L<DBIx::Class> and L<Class::DBI>. Catalyst supports making models
-using either of these.  
-
-For a simple example, we will allow our users to store their favourite
-greeting in our database. Create a table called "greetings" in a database,
-that contains a "user" field and a "greeting" field. The simplest way to
-create a model of your database is to use these helper modules, for example
-with L<DBIx::Class>: 
-
-    script/tutorial_create.pl model UserData DBIC dbi:SQLite:/path/to/mydb.db
-
-This will cause the DBIx::Class Loader to inspect your database, and create a
-module in the Model::UserData namespace for each table in your database. 
-
-Now we need a form for our users to enter/edit their personal greetings in,
-we'll make a I<http://localhost:3000/users/editgreeting> page: 
-
- sub editgreeting : Local {
-    my ($self, $c) = @_;
-    if($c->req->params->{greeting}) {
-       if(!$c->user_exists) {
-          $c->stash->{message} = "You're not logged in!";
-       }
-       else {
-          my $grtable = $c->model('UserData::Greetings');
-          my $record = $grtable->find_or_create(user => $c->user->id);
-          $record->greeting($c->req->params->{greeting});
-          $record->update;
-          $c->stash->{message} = 'Greeting updated';
-       }
-    }
-    $c->stash->{template} = 'usersgreeting.tt';
- }
-
-Using C<< $c->user_exists >> from the Authentication plugin, this checks
-whether the user is logged in already. If they are, if they are, and they have
-entered a new greeting, we use DBIx::Class' C<find_or_create> to fetch or
-create a new record in the greetings table for the user. Once we have the
-record, we change the value of the greeting field, and call C<update> to store
-the new value in the database. 
-
-=head2 Engines (Apache and FastCGI)
-
-Now that we have the basics together, we can try running our application on a
-"real" server instead of just using the test server that catalyst comes
-with. L<Catalyst::Engine> is the module used to implement various types of
-servers to run it on. The current popular ones are Apache and FastCGI.
+=over 4
 
-=head3 Apache
+=item *
 
-Apache needs to be configured: we need to tell it to load your
-application. You can either use Catalyst for your entire website, or
-subsections. Use the Location directive to choose a path to run your
-application under: 
+Create a Catalyst View Using TTSite
 
- <Location />
-   SetHandler                perl-script
-   PerlResponseHandler  tutorial
- </Location>
+=item *
 
-You will need to install the perl modules of your application into one of
-perls library directories, as listed by B<perl -V>, so that Apache can find
-them. Alternatively you can use the C<PerlSwitches> directive to tell Apache
-where to look: 
+Using RenderView for the Default View
 
- PerlSwitches -I/path/to/tutorial/
+=item *
 
-These instructions are for using Apache2 and mod_perl 2.0. If you are using
-mod_perl 1.3 or 1.99, please refer to either L<Catalyst::Engine::Apache::MP13>
-or L<Catalyst::Engine::Apache2::MP19> for slightly different ways to do it. 
+Globally Customize Every View
 
-If you wish to ensure that Apache pre-loads your application, use the
-PerlModule directive. This means that there will be less of a delay when your
-application is accessed. 
+=item *
 
- PerlModule tutorial
+Create a TT Template Page
 
-=head3 FastCGI
+=back
 
-These instructions apply to the use of C<mod_fastcgi> under Apache
-(either 1 or 2 series).
 
-There are 3 ways to attach a program to a URL with C<mod_fastcgi>;
-we'll examine all of them, and explain how to avoid having the
-C<tutorial_fastcgi.pl> substring in the user-visible URLs.
+=item *
 
-In all of these examples, we assume that the C<DocumentRoot> is
-C</var>, that our app is called C<tutorial> and is kept in C</usr>, that
-you want the users to access the app either from the root of the
-server-uri-space, or from C</theapp>. We also assume that the general
-FastCGI settings (C<FastCgiIpcDir>, loading the module) are already
-correct (they don't depend on Catalyst or your application layout).
+RUN THE APPLICATION
 
-=head4 static application
+=back
 
-In this setup, you tell C<mod_fastcgi> that a particular I<file> is to
-be run as a FastCGI handler. Put this somewhere in Apache's
-configuration:
+=head2 Part 3: Basic CRUD
 
-  FastCgiServer /usr/apps/tutorial/script/tutorial_fastcgi.pl
-  Alias / /usr/apps/tutorial/script/tutorial_fastcgi.pl/
+=over 4
 
-If you want your app under C</theapp>, change the C<Alias> line to:
+=item *
 
-  Alias /theapp /usr/apps/tutorial/script/tutorial_fastcgi.pl
+FORMLESS SUBMISSION
 
-Note the detail of the trailing C</ >: this is a general rule of the
-C<Alias> directive, both sides must end with C</ >, or both must not;
-you can't have one with C</ > and the other without, or strange things
-happen.
+=over 4
 
-=head4 dynamic application
+=item *
 
-In this setup, you tell C<mod_fastcgi> that certain files are to be
-treated as FastCGI handlers, in the same way you have to tell
-C<mod_cgi>. Put this in the configuration:
+Include a Create Action in the Books Controller
 
-  FastCgiConfig -autoUpdate
+=item *
 
-  <Directory /usr/apps/tutorial/script>
-   Options +ExecCGI
-   <Files *_fastcgi.pl>
-    SetHandles fastcgi-script
-   </Files>
-  </Directory>
+Include a Template for the url_create Action:
 
-  Alias / /usr/apps/tutorial/script/tutorial_fastcgi.pl/
+=item *
 
-Again, if you want your app under C</theapp>, change the C<Alias> line to:
+Try the url_create Feature
 
-  Alias /theapp /usr/apps/tutorial/script/tutorial_fastcgi.pl
+=back
 
-=head4 external server
+=item *
 
-In this setup, the application is started separately from Apache, and
-communicates via a socket with C<mod_fastcgi>. This can be useful if
-you need to have a particular environment for your application (maybe
-different between applications), or you want to run them on different
-machines, or under different users for security reasons.
+MANUALLY BUILDING A CREATE FORM
 
-If you want to use a UNIX socket (on the filesystem), put this in
-Apache's configuration:
+=over 4
 
-  FastCgiExternalServer /tmp/somewhere -socket /tmp/tutorial-socket
-  Alias / /tmp/somewhere/
+=item *
 
-Note that C</tmp> should I<not> exist: it's just a name to connect the
-two parts.
+Add a Method to Display the Form
 
-Again, if you want your app under C</theapp>, change the C<Alias> line
-to:
+=item *
 
-  Alias /theapp /tmp/somewhere
+Add a Template for the Form
 
-Then start your Catalyst application:
+=item *
 
-  $ cd /usr/apps/tutorial
-  $ ./script/tutorial_fastcgi -l /tmp/tutorial-socket
+Add Method to Process Form Values and Update Database
 
-If you want to use a TCP socket, simply change the C</tmp> to a
-C<host:port> pair, both in Apache's configuration and on the command
-line of your application.
+=item *
 
-=head2 Upgrading
+Test Out the Form
 
-Upgrading your application to newer Catalyst versions is quite simple. After
-installing the new Catalyst package, just run: 
+=back
 
-    catalyst.pl -scripts
+=item *
 
-One level above your application directory. This will update the
-scripts directory only, and leave the rest of your app alone, If you
-wish to make use of other parts of Catalyst that have been updated,
-leave off the B<-scripts> argument, this will cause .new files to
-appear, for each module that has either been updated, or is different
-to the original because you have changed it. To find out what these
-changes are, type:
+A SIMPLE DELETE FEATURE
 
-    diff tutorial/lib/tutorial/View/TT.pm tutorial/lib/tutorial/View/TT.pm.new
+=over 4
 
-for each of the changed files. (This is a Unix command, Windows users
-will need to find some equivalent). Copy any changes you need into
-your original file, then remove the .new files. (This makes life less
-complicated when the next upgrade comes around.)
+=item *
 
-=head1 AUTHORS
+Include a Delete Link in the List
 
-Jess Robinson, C<jrobinson@cpan.org>
-Andrew Ford, C<A.Ford@ford-mason.co.uk>
-Marcus Ramberg, C<mramberg@cpan.org>
-Kieren Diment, C<kd@totaldatasolution.com>
-Gavin Henry, C<ghenry@cpan.org>
+=item *
 
-Please send comments, corrections and suggestions for improvements to
-jrobinson@cpan.org, ghenry@cpan.org
+Add a Delete Action to the Controller
 
-=head1 TODO
+=item *
 
-Finish DBIC examples with templates and tested code.  Make
-/users/groups do something "useful"
+Try the Delete Feature
 
-Many other things..
+=back
 
-=head1 COPYRIGHT
+=back
 
-This program is free software, you can redistribute it and/or modify 
-it under the same terms as Perl itself.
+=head2 Part 4: Authentication
+
+=over 4
+
+=item *
+
+BASIC AUTHENTICATION
+
+=over 4
+
+=item *
+
+Add Users and Roles to the Database
+
+=item *
+
+Add User and Role Information to DBIC Schema
+
+=item *
+
+Create New ``Result Source Objects''
+
+=item *
+
+Sanity-Check Reload of Development Server
+
+=item *
+
+Include Authentication and Session Plugins
+
+=item *
+
+Configure Authentication
+
+=item *
+
+Add Login and Logout Controllers
+
+=item *
+
+Add a Login Form TT Template Page
+
+=item *
+
+Add Valid User Check
+
+=item *
+
+Displaying Content Only to Authenticated Users
+
+=item *
+
+Try Out Authentication
+
+=back
+
+=item *
+
+USING PASSWORD HASHES
+
+=over 4
+
+=item *
+
+Get a SHA-1 Hash for the Password
+
+=item *
+
+Switch to SHA-1 Password Hashes in the Database
+
+=item *
+
+Enable SHA-1 Hash Passwords in Catalyst::Plugin::Authentication::Store::DBIC
+
+=item *
+
+Try Out the Hashed Passwords
+
+=back
+
+=back
+
+=head2 Part 5: Authorization
+
+=over 4
+
+=item *
+
+BASIC AUTHORIZATION
+
+=over 4
+
+=item *
+
+Update Plugins to Include Support for Authorization
+
+=item *
+
+Add Config Information for Authorization
+
+=item *
+
+Add Role-Specific Logic to the ``Book List'' Template
+
+=item *
+
+Limit Books::add to admin Users
+
+=item *
+
+Try Out Authentication And Authorization
+
+=back
+
+=item *
+
+ENABLE ACL-BASED AUTHORIZATION
+
+=over 4
+
+=item *
+
+Add the Catalyst::Plugin::Authorization::ACL Plugin
+
+=item *
+
+Add ACL Rules to the Application Class
+
+=item *
+
+Add a Method to Handle Access Violations
+
+=back
+
+=back
+
+=head2 Part 6: Debugging
+
+=over 4
+
+=item *
+
+LOG STATEMENTS
+
+=item *
+
+RUNNING CATALYST UNDER THE PERL DEBUGGER
+
+=item *
+
+DEBUGGING MODULES FROM CPAN
+
+=back
+
+=head2 Part 7: Testing
+
+=over 4
+
+=item *
+
+RUNNING THE "CANNED" CATALYST TESTS
+
+=item *
+
+RUNNING A SINGLE TEST
+
+=item *
+
+ADDING YOUR OWN TEST SCRIPT
+
+=item *
+
+SUPPORTING BOTH PRODUCTION AND TEST DATABASES
+
+=back
+
+=head2 Part 8: Advanced CRUD
+
+=over 4
+
+=item *
+
+HTML::WIDGET FORM CREATION
+
+=over 4
+
+=item *
+
+Add the HTML::Widget Plugin
+
+=item *
+
+Add a Form Creation Helper Method
+
+=item *
+
+Add Actions to Display and Save the Form
+
+=item *
+
+Update the CSS
+
+=item *
+
+Create a Template Page To Display The Form
+
+=item *
+
+Add Links for Create and Update via HTML::Widget
+
+=item *
+
+Test The <HTML::Widget> Create Form
+
+=back
+
+=item *
+
+HTML::WIDGET VALIDATION AND FILTERING
+
+=over 4
+
+=item *
+
+Add Constraints and Filters to the Widget Creation Method
+
+=item *
+
+Rebuild the Form Submission Method to Include Validation
+
+=item *
+
+Try Out the Form
+
+=back
+
+=item *
+
+Enable DBIx::Class::HTMLWidget Support
+
+=over 4
+
+=item *
+
+Add DBIx::Class::HTMLWidget to DBIC Model
+
+=item *
+
+Use populate_from_widget in hw_create_do
+
+=back
+
+=back
+
+=head2 Part 9: Appendices
+
+=over 4
+
+=item *
+
+APPENDIX 1: CUT AND PASTE FOR POD-BASED EXAMPLES
+
+=over 4
+
+=item *
+
+"Un-indenting" with Vi/Vim
+
+=item *
+
+"Un-indenting" with Emacs
+
+=back
+
+=item *
+
+APPENDIX 2: USING MYSQL AND POSTGRESQL
+
+=over 4
+
+=item *
+
+MySQL
+
+=item *
+
+PostgreSQL
+
+=back
+
+=item *
+
+APPENDIX 3: IMPROVED HASHING SCRIPT
+
+=back
+
+
+=head1 THANKS
+
+This tutorial would not have been possible without the input of many 
+different people in the Catalyst community.  In particular, the 
+primary author would like to thank:
+
+=over 4
+
+=item *
+
+Sebastian Riedel for founding the Catalyst project.
+
+=item *
+
+The members of the Catalyst Core Team for their tireless efforts to
+advance the Catalyst project.  Although all of the Core Team members
+have played a key role in this tutorial, it would have never been
+possible without the critical contributions of: Matt Trout, for his
+unfathomable knowledge of all things Perl and Catalyst (and his
+willingness to answer lots of my questions); Jesse Sheidlower, for his
+incredible skill with the written word and dedication to improving the
+Catalyst documentation; and Yuval Kogman, for his work on the Catalyst
+"Auth & Authz" plugins (the original focus of the tutorial) and other
+key Catalyst modules.
+
+=item *
+
+Other Catalyst documentation folks like Kieren Diment, Gavin Henry,
+and Jess Robinson (including their work on the original Catalyst
+tutorial).
+
+=item *
+
+Everyone on #catalyst and #catalyst-dev.
+
+=item *
+
+People who have emailed me with corrections and suggestions on the 
+tutorial.  As of the most recent release, this include: Florian Ragwitz, 
+Mauro Andreolini, Jim Howard, Giovanni Gigante, William Moreno,  
+Bryan Roach, Ashley Berlin, and David Kamholz.  
+
+=back
+
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark@gmail.com>
+
+Please report any errors, issues or suggestions to the author.  The
+most recent version of the Catalyst Tutorial can be found at
+L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Runtime/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).