[Catalyst-commits] r10277 - in Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial: . 09_AdvancedCRUD

hkclark at dev.catalyst.perl.org hkclark at dev.catalyst.perl.org
Sun May 24 22:30:48 GMT 2009


Author: hkclark
Date: 2009-05-24 22:30:47 +0000 (Sun, 24 May 2009)
New Revision: 10277

Added:
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/01_Intro.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/04_BasicCRUD.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/05_Authentication.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/06_Authorization.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/07_Debugging.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/08_Testing.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormBuilder.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/10_Appendices.pod
Removed:
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/FormBuilder.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/FormFu.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Appendices.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Intro.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod
   Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod
Log:
Add numbers back to names of chapters

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/01_Intro.pod (from rev 10276, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Intro.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/01_Intro.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/01_Intro.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,642 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::01_Intro - Catalyst Tutorial - Chapter 1: Introduction
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 1 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+B<01_Introduction>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This tutorial provides a multi-part introduction to the Catalyst web
+framework. It seeks to provide a rapid overview of many of its most
+commonly used features. The focus is on the real-world best practices
+required in the construction of nearly all Catalyst applications.
+
+Although the primary target of the tutorial is users new to the Catalyst
+framework, experienced users may wish to review specific sections (for
+example, how to use DBIC for their model classes, how to add
+authentication and authorization to an existing application, or form
+management).
+
+You can obtain the code for all the tutorial examples from the
+catalyst subversion repository by issuing the command:
+
+    svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/ CatalystTutorial
+
+This will download the most recent tarball for each chapter of the 
+tutorial into the CatalystTutorial directory on your machine. 
+
+B<These reference implementations are provided so that when you follow
+the tutorial, you can use the code from the subversion repository to
+ensure that your system is set up correctly, and that you have not
+inadvertently made any typographic errors, or accidentally skipped
+part of the tutorial.>
+
+B<NOTE: You can use any Perl-supported OS and environment to run 
+Catalyst.> It should make little or no difference to Catalyst's 
+operation, B<but this tutorial has been written using the Debian 5 
+live CD> because that represents a quick and easy for most people to 
+try out Catalyst with virtually zero setup time and hassles.  Also, 
+the tutorial has been tested to work correctly with the versions of 
+Catalyst and all the supporting modules in Debian 5 (see "VERSIONS 
+AND CONVENTIONS USED IN THIS TUTORIAL" below for the specific versions 
+for some of the key modules), so B<if you think you might be running 
+into an issue related to versions> (for example, a module changed its 
+behavior in a newer version or a bug was introduced), B<it might be 
+worth giving Debian 5 a try>.  See the "CATALYST INSTALLATION" 
+section below for more information.
+
+If you're reading this manual online, you can download the example 
+program and all the necessary dependencies to your local machine by 
+installing the C<Task::Catalyst::Tutorial> distribution from CPAN:
+
+     cpan Task::Catalyst::Tutorial
+
+This will also test to make sure the dependencies are working.  If you
+have trouble installing these, please ask for help on the #catalyst
+IRC channel, or the Catalyst mailing list.
+
+Subjects covered by the tutorial include:
+
+=over 4
+
+=item * 
+
+A simple application that lists and adds books.
+
+=item *
+
+The use of L<DBIx::Class|DBIx::Class> (DBIC) for the model (including 
+some of the more advanced techniques you will probably want to use in 
+your applications).
+
+=item * 
+
+How to write CRUD (Create, Read, Update, and Delete) operations in
+Catalyst.
+
+=item *
+
+Authentication ("auth").
+
+=item * 
+
+Role-based authorization ("authz").
+
+=item * 
+
+Attempts to provide an example showing current (5.8XXX) Catalyst
+practices. For example, the use of 
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>,
+DBIC, L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader> 
+with C<myapp.conf>, the use of C<lib/MyApp/Controller/Root.pm> 
+vs. C<lib/MyApp.pm>, etc.
+
+=item * 
+
+The use of Template Toolkit (TT).
+
+=item * 
+
+Useful techniques for troubleshooting and debugging Catalyst
+applications.
+
+=item * 
+
+The use of SQLite as a database (with code also provided for MySQL and
+PostgreSQL).
+
+=item * 
+
+The use of L<HTML::FormFu|HTML::FormFu> for automated form processing 
+and validation.
+
+=back
+
+This tutorial makes the learning process its main priority.  For
+example, the level of comments in the code found here would likely be
+considered excessive in a "normal project."  Because of their contextual
+value, this tutorial will generally favor inline comments over a
+separate discussion in the text.  It also deliberately tries to
+demonstrate multiple approaches to various features (in general, you
+should try to be as consistent as possible with your own production
+code).
+
+Furthermore, this tutorial tries to minimize the number of controllers,
+models, TT templates, and database tables.  Although this does result in
+things being a bit contrived at times, the concepts should be applicable
+to more complex environments.  More complete and complicated example
+applications can be found in the C<examples> area of the Catalyst
+Subversion repository at
+L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/>.
+
+
+=head1 VERSIONS AND CONVENTIONS USED IN THIS TUTORIAL
+
+This tutorial was built using the following resources. Please note that
+you may need to make adjustments for different environments and
+versions:
+
+=over 4
+
+=item * 
+
+Debian 5 (Lenny)
+
+=item * 
+
+Catalyst v5.80004
+
+=item *
+
+Catalyst::Devel v1.10
+
+=item * 
+
+DBIx::Class v0.08102
+
+=item * 
+
+Catalyst Plugins
+
+The plugins used in this tutorial all have sufficiently stable APIs that
+you shouldn't need to worry about versions. However, there could be
+cases where the tutorial is affected by what version of plugins you
+use. This tutorial has been tested against the following set of plugins:
+
+=over 4
+
+=item * 
+
+Catalyst::Plugin::Authentication -- v0.10011
+
+=item *
+
+Catalyst::Plugin::Authorization::Roles -- v0.07
+
+=item *
+
+Catalyst::Plugin::ConfigLoader -- v0.22
+
+=item *
+
+Catalyst::Plugin::Session -- v0.20
+
+=item *
+
+Catalyst::Plugin::Session::State::Cookie -- v0.10
+
+=item *
+
+Catalyst::Plugin::Session::Store::FastMmap -- v0.07
+
+=item *
+
+Catalyst::Plugin::StackTrace -- v0.09
+
+=item *
+
+Catalyst::Plugin::Static::Simple -- v0.21
+
+=back
+
+=item * 
+
+B<NOTE:> You can check the versions you have installed with the
+following command:
+
+    perl -M<_mod_name_> -e '"print $<_mod_name_>::VERSION\n"'
+
+For example:
+    perl -MCatalyst::Plugin::StackTrace -e 'print "$Catalyst::Plugin::StackTrace::VERSION\n"'
+
+Since the web browser is being used on the same box where Perl and the
+Catalyst development server is running, the URL of
+C<http://localhost:3000> will be used (the Catalyst development server
+defaults to port 3000).  If you are running Perl on a different box than
+where your web browser is located (or using a different port number via
+the C<-p> I<port_number> option to the development server), then you
+will need to update the URL you use accordingly.
+
+=item * 
+
+Depending on the web browser you are using, you might need to hit 
+C<Shift+Reload> or C<Ctrl+Reload> to pull a fresh page when testing 
+your application at various points (see 
+L<http://en.wikipedia.org/wiki/Bypass_your_cache> for a comprehensive
+list of options for each browser).  Also, the C<-k> keepalive option 
+to the development server can be necessary with some browsers 
+(especially Internet Explorer).
+
+=back
+
+
+=head1 CATALYST INSTALLATION
+
+Although Catalyst installation has been a challenge in the past, the 
+good news is that there are a growing number of options to eliminate 
+(or at least dramatically simplify) this concern.  Although a 
+compelling strength of Catalyst is that it makes use of many of the 
+modules in the vast repository that is CPAN, this can complicate the 
+installation process if you approach it in the wrong way.  Consider 
+the following suggestions on the most common ways to get started with 
+a Catalyst development environment:
+
+=over 4
+
+=item *
+
+Debian
+
+The Debian 5 live CD represents a great way for newcomers to 
+experiment with Catalyst.  As a "live CD," you can simple boot from 
+the CD, run a few commands, and in a matter of minutes you should have 
+a fully function environment in which do this tutorial. B<The tutorial 
+was fully tested to work under Debian 5.  Although it SHOULD work 
+under any Catalyst installation method you might choose, it can be 
+hard to guarantee this.>
+
+=over 4
+
+=item * 
+
+Download one of the ISO files from 
+L<http://cdimage.debian.org/cdimage/release/current-live/i386/iso-cd/>. 
+You can pick any one of the live CD variations will work, but 
+you may wish to consider the following points:
+
+=over 4
+
+=item *
+
+"C<debian-live-500-i386-rescue.iso>" is probably the best all-around 
+option for most people because it includes many extra tools such as 
+the GCC compiler, therefore saving RAM (every package you need to 
+install when running from live CD consumes memory because RAM disk is 
+being used in lieu of real disk space).  When initially booting under 
+this image, you may see some cryptic warning messages having to do 
+with various diagnostic tools it tries to load or enable, but you 
+should be able to safely ignore these.
+
+=item *
+
+"C<debian-live-500-i386-standard.iso>" is a great option because of 
+its compact size, but you will probably need approximately 1 GB of RAM 
+in the computer where you will run the tutorial.  Because the 
+"standard" live CD comes with with a minimal set of tools, we will 
+have to install extra packages (such as the GCC compiler), all of 
+which will require RAM when running from a live CD. 
+
+=item *
+
+The other ISO images include different flavors of X-Windows desktop 
+managers.  You can select one of these if you don't mind the larger 
+download size and prefer a graphical environment.  Be aware that these 
+disks do not come with the extra tools found on the "rescue" image, so 
+you will need adequate RAM to be able to install them just as you 
+would under the "standard" image. B<Use one of the "graphical" ISO 
+images if you want a graphical web browser on the same machine as 
+where you will run the tutorial.>  (If you are using one of the non-
+graphical images discussed above, you can still use a graphical web 
+browser from another machine and point it to your Catalyst development 
+machine.)
+
+=back
+
+=item *
+
+Boot off the CD.
+
+=item *
+
+Select "C<Live>" from the initial boot menu.
+
+=item *
+
+Once the system has booted to a "C<user at debian:~$>" prompt, enter the 
+following command to add the more current "unstable" package 
+repository:
+
+    sudo vi /etc/apt/sources.list
+
+Add the following line to the bottom of this file:
+
+    deb http://ftp.us.debian.org/debian/ unstable main
+
+If you are not familiar with VI, you can move to the bottom of this 
+file and press the "o" key to insert a new line and type the line 
+above.  Then press the "Esc" key followed by a colon (":"), the 
+letters "wq" and then the "Enter" key.  The rest of the tutorial will 
+assume that you know how to use some editor that is available from the 
+Linux command-line environment.
+
+=item *
+
+Install Catalyst:
+
+    sudo aptitude update
+    sudo aptitude -y install sqlite3 libdbd-sqlite3-perl libcatalyst-perl \
+        libcatalyst-modules-perl libconfig-general-perl libsql-translator-perl \
+        libdatetime-perl libdatetime-format-mysql-perl libio-all-perl \
+        libperl6-junction-perl libmoosex-emulate-class-accessor-fast-perl
+
+Let it install (normally about a 30-second operaton) and you are 
+done.  
+
+If you are using an image other than the "rescue" ISO, you will also need
+to run the following command to install additional packages:
+
+    sudo aptitude -y install gcc make libc6-dev
+
+If you are running from the Live CD, you probably also want to free up 
+some RAM disk space with the following:
+
+    sudo aptitude clean
+
+NOTE: While the instructions above mention the Live CD because that 
+makes it easy for people new to Linux, you can obviously pick a 
+different Debian ISO image and install it to your hard drive. 
+Although there are many different ways to download and install Debian, 
+the "netinst" ISO image (such as "C<debian-500-i386-netinst.iso>" 
+represents a great option because it keeps your initial download small 
+(but still let's you install anything you want "over the network").
+
+Here are some tips if you are running from a live CD and are running
+out of disk space (which really means you are running out of RAM):
+
+=over 4
+
+=item *
+
+Always run "C<aptitude clean>" after you install new packages to 
+delete the original .deb files (the files installed B<by> the .deb 
+package B<will> remain available, just the .deb package itself is 
+deleted).
+
+=item *
+
+If you are installing modules from CPAN, you can free up some space 
+with "C<rm -rf /root/.cpan/*>".
+
+=item *
+
+If necessary, you can remove the cached package information with the 
+command "C<rm -f /var/lib/apt/lists/*>".  You can later pull this 
+information again via the command "C<aptitude update>".
+
+=item * 
+
+You can save a small amount of space by commenting out the lines in 
+C</etc/apt/sources.list> that reference "deb-src" and 
+"security.debian.org".  If you have already done an "C<aptitude 
+update>" with these repositories enabled, you can use the tip in the 
+previous bullet to free the space up (and then do another "C<aptitude 
+update>").
+
+=item *
+
+Although you can free up space by removing packages you installed 
+since you last booted (check out "C<aptitude remove _pkg_name>"), 
+don't bother trying to remove packages already available at the time 
+of boot. Instead of freeing up space, it will actual I<consume> some 
+space. (The live CD uses these "burn in" packages right from the CD 
+disk vs. first loading them on the virtual RAM disk. However, if you 
+remove them, the system has to update various files, something that 
+I<does> consume some space on the virtual RAM disk.)
+
+=back
+
+=back
+
+=item *
+
+Ubuntu
+
+Ubuntu is an extremely popular offshoot of Debian.  It provides 
+cutting edge versions of many common tools, application and libraries 
+in an easy-to-run live CD configuration (and because a single download 
+option can be used for both live CD and install-to-disk usage, it 
+keeps your download options nice and simple).  As with Debian 5, you 
+should be able to generate a fully function Catalyst environment in a 
+matter of minutes.  Here are quick instructions on how to use Ubuntu 
+to prepare for the tutorial:
+
+=over 4
+
+=item * 
+
+Download the Ubuntu Desktop edition and boot from the CD and/or image 
+file, select your language, and then "Try Ubuntu without any changes 
+to your computer."
+
+=item *
+
+Open a terminal session (click "Applications" in the upper-left 
+corner, then "Accessories," then "Terminal").
+
+=item *
+
+Add the 'universe' repositories:
+
+    sudo gedit /etc/apt/sources.list
+
+And remove the comments from the lines under the comments about the
+'universe' repositories.
+
+=item *
+
+Install Catalyst:
+
+    sudo aptitude update
+    sudo aptitude install libdbd-sqlite3-perl libcatalyst-perl libcatalyst-modules-perl libconfig-general-perl
+
+Accept all of the dependencies.  Done.  
+
+If you are running from the Live CD, you probably also want to free up 
+some disk space with the following:
+
+    sudo aptitude clean
+
+NOTE: While the instructions above mention the live CD because that 
+makes it easy for people new to Linux, you can obviously also use one 
+of the options to install Ubuntu on your drive.
+
+=back
+
+=item * 
+
+Matt Trout's C<cat-install>
+
+Available at L<http://www.shadowcatsystems.co.uk/static/cat-install>, 
+C<cat-install> can be a fairly painless way to get Catalyst up and 
+running.  Just download the script from the link above and type C<perl 
+cat-install>.  Depending on the speed of your Internet connection and 
+your computer, it will probably take 30 to 60 minutes to install because 
+it downloads, makes, compiles, and tests every module.  But this is an 
+excellent way to automate the installation of all the latest modules 
+used by Catalyst from CPAN.
+
+
+=item * 
+
+Other Possibilities
+
+=over 4
+
+=item *
+
+OpenBSD Packages
+
+The 2008 Advent Day 4 entry has more information on using OpenBSD 
+packages to quickly build a system: 
+L<http://www.catalystframework.org/calendar/2008/4>.
+
+=item *
+
+NetBSD Package Collection on Solaris
+
+The 2008 Advent Day 15 entry has more information on using C<pkgsrc> and 
+NetBSD packages on Solaris: 
+L<http://www.catalystframework.org/calendar/2008/15>.
+
+=item * 
+
+CatInABox
+
+You can get more information at 
+L<http://www.catalystframework.org/calendar/2008/7>
+or L<Perl::Dist::CatInABox|Perl::Dist::CatInABox>.
+
+=item * 
+
+Frank Speiser's Amazon EC2 Catalyst SDK
+
+There are currently two flavors of publicly available Amazon Machine
+Images (AMI) that include all the elements you'd need to begin
+developing in a fully functional Catalyst environment within minutes.
+See L<Catalyst::Manual::Installation|Catalyst::Manual::Installation>
+for more details.
+
+=back
+
+=back
+
+For additional information and recommendations on Catalyst installation,
+please refer to 
+L<Catalyst::Manual::Installation|Catalyst::Manual::Installation>.
+
+
+=head1 DATABASES
+
+This tutorial will primarily focus on SQLite because of its simplicity
+of installation and use; however, modifications in the script required
+to support MySQL and PostgreSQL will be presented in Appendix.
+
+B<Note:> One of the advantages of the MVC design patterns is that
+applications become much more database independent.  As such, you will
+notice that only the C<.sql> files used to initialize the database
+change between database systems: the Catalyst code generally remains the
+same.
+
+
+=head1 WHERE TO GET WORKING CODE
+
+Each chapter of the tutorial has complete code available as a tarball in 
+the main Catalyst Subversion repository (see the note at the beginning 
+of each part for the appropriate svn command to use).
+
+B<NOTE:> You can run the test cases for the final code through Chapter 8 
+with the following commands:
+
+    sudo cpan Catalyst::Model::DBIC::Schema Time::Warp DBICx::TestDatabase \
+        DBIx::Class::DynamicDefault DBIx::Class::TimeStamp DBIx::Class::EncodedColumn
+    wget http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter8.tgz
+    tar zxvf MyApp_Chapter8.tgz
+    cd MyApp
+    CATALYST_DEBUG=0 prove --lib lib t
+
+If you wish to include the L<HTML::FormFu|HTML::FormFu> section in 
+your tests, substitute C<MyApp_Chapter9_FormFu.tgz> for 
+C<MyApp_Chapter8.tgz> in the URL above.  However, you will also need to 
+run the following additional commands:
+
+    sudo aptitude -y install libhtml-formfu-perl libmoose-perl \
+        libregexp-assemble-perl libhtml-formfu-model-dbic-perl
+    sudo aptitude clean
+    sudo cpan Catalyst::Component::InstancePerContext Catalyst::Controller::HTML::FormFu
+
+You can also fire up the application under the development server that is conveniently
+built in to Catalyst.  Just issue this command from the C<MyApp> directory where you
+ran the test suite above:
+
+    script/myapp_server.pl
+
+And the application will start.  You can try out the application by 
+pulling up C<http://localhost:3000> in your web browser (as mentioned 
+earlier, change C<localhost> to a different IP address or DNS name if 
+you are running your web browser and your Catalyst development on 
+different boxes).  We will obviously see more about how to use the 
+application as we go through the remaining chapters of the tutorial, but 
+for now you can log in using the username "test01" and a password of 
+"mypass".
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,462 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::02_CatalystBasics - Catalyst Tutorial - Chapter 2: Catalyst Application Development Basics
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 2 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+B<02_Catalyst Basics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+In this chapter of the tutorial, we will create a very basic Catalyst 
+web application, demonstrating a number of powerful capabilities, such 
+as:
+
+=over 4
+
+=item * Helper Scripts
+
+Catalyst helper scripts that can be used to rapidly bootstrap the
+skeletal structure of an application.
+
+=item * MVC
+
+Model/View/Controller (MVC) provides an architecture that facilitates a
+clean "separation of control" between the different portions of your
+application. Given that many other documents cover this subject in
+detail, MVC will not be discussed in depth here (for an excellent
+introduction to MVC and general Catalyst concepts, please see
+L<Catalyst::Manual::About|Catalyst::Manual::About>). In short:
+
+=over 4
+
+=item * Model
+
+The model usually represents a data store. In most applications, the
+model equates to the objects that are created from and saved to your SQL
+database.
+
+=item * View
+
+The view takes model objects and renders them into something for the end
+user to look at. Normally this involves a template-generation tool that
+creates HTML for the user's web browser, but it could easily be code
+that generates other forms such as PDF documents, e-mails, spreadsheets, 
+or even "behind the scenes" formats such as XML and JSON.
+
+=item * Controller
+
+As suggested by its name, the controller takes user requests and routes
+them to the necessary model and view.
+
+=back
+
+=item * ORM
+
+The use of Object-Relational Mapping (ORM) technology for database
+access. Specifically, ORM provides an automated and standardized means
+to persist and restore objects to/from a relational database.
+
+=back
+
+You can checkout the source code for this example from the catalyst
+subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+
+
+=head1 CREATE A CATALYST PROJECT
+
+Catalyst provides a number of helper scripts that can be used to 
+quickly flesh out the basic structure of your application. All 
+Catalyst projects begin with the C<catalyst.pl> helper (see 
+L<Catalyst::Helper|Catalyst::Helper> for more information on helpers). 
+Also note that as of Catalyst 5.7000, you will not have the helper 
+scripts unless you install both L<Catalyst::Runtime|Catalyst::Runtime> 
+and L<Catalyst::Devel|Catalyst::Devel>.
+
+In this first chapter of the tutorial, use the Catalyst C<catalyst.pl> 
+script to initialize the framework for an application called C<Hello>:
+
+    $ catalyst.pl Hello
+    created "Hello"
+    created "Hello/script"
+    created "Hello/lib"
+    created "Hello/root"
+    ...
+    created "Hello/script/hello_create.pl"
+    $ cd Hello
+
+The C<catalyst.pl> helper script will display the names of the
+directories and files it creates:
+
+    Changes               # Record of application changes
+    lib                   # Lib directory for your app's Perl modules
+        Hello             # Application main code directory
+            Controller    # Directory for Controller modules 
+            Model         # Directory for Models
+            View          # Directory for Views
+        Hello.pm          # Base application module
+    Makefile.PL           # Makefile to build application
+    hello.conf            # Application configuration file
+    README                # README file
+    root                  # Equiv of htdocs, dir for templates, css, javascript
+        favicon.ico
+        static            # Directory for static files
+            images        # Directory for image files used in welcome screen
+    script                # Directory for Perl scripts
+        hello_cgi.pl      # To run your app as a cgi (not recommended)
+        hello_create.pl   # To create models, views, controllers
+        hello_fastcgi.pl  # To run app as a fastcgi program
+        hello_server.pl   # The normal development server
+        hello_test.pl     # Test your app from the command line
+    t                     # Directory for tests
+        01app.t           # Test scaffold       
+        02pod.t           
+        03podcoverage.t 
+
+
+Catalyst will "auto-discover" modules in the Controller, Model, and 
+View directories. When you use the hello_create.pl script it will 
+create Perl module scaffolds in those directories, plus test files in 
+the "t" directory. The default location for templates is in the "root" 
+directory. The scripts in the script directory will always start with 
+the lowercased version of your application name. If your app is 
+MaiTai, then the create script would be "maitai_create.pl".
+
+Though it's too early for any significant celebration, we already have 
+a functioning application. We can use the Catalyst supplied script to 
+start up a development server and view the default Catalyst page in 
+your browser. All scripts in the script directory should be run from 
+the base directory of your application, so change to the Hello 
+directory.
+
+Run the following command to start up the built-in development web 
+server (make sure you didn't forget the "C<cd Hello>" from the 
+previous step):
+
+    $ script/hello_server.pl
+    [debug] Debug messages enabled
+    [debug] Statistics enabled
+    [debug] Loaded plugins:
+    .----------------------------------------------------------------------------.
+    | Catalyst::Plugin::ConfigLoader  0.20                                       |
+    | Catalyst::Plugin::Static::Simple  0.20                                     |
+    '----------------------------------------------------------------------------'
+    
+    [debug] Loaded dispatcher "Catalyst::Dispatcher"
+    [debug] Loaded engine "Catalyst::Engine::HTTP"
+    [debug] Found home "/home/me/Hello"
+    [debug] Loaded Config "/home/me/Hello/hello.conf"
+    [debug] Loaded components:
+    .-----------------------------------------------------------------+----------.
+    | Class                                                           | Type     |
+    +-----------------------------------------------------------------+----------+
+    | Hello::Controller::Root                                         | instance |
+    '-----------------------------------------------------------------+----------'
+    
+    [debug] Loaded Private actions:
+    .----------------------+--------------------------------------+--------------.
+    | Private              | Class                                | Method       |
+    +----------------------+--------------------------------------+--------------+
+    | /default             | Hello::Controller::Root              | default      |
+    | /end                 | Hello::Controller::Root              | end          |
+    | /index               | Hello::Controller::Root              | index        |
+    '----------------------+--------------------------------------+--------------'
+    
+    [debug] Loaded Path actions:
+    .-------------------------------------+--------------------------------------.
+    | Path                                | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /                                   | /default                             |
+    | /                                   | /index                               |
+    '-------------------------------------+--------------------------------------'
+    
+    [info] Hello powered by Catalyst 5.80003
+    You can connect to your server at http://debian:3000
+
+Point your web browser to L<http://localhost:3000> (substituting a 
+different hostname or IP address as appropriate) and you should be 
+greeted by the Catalyst welcome screen (if you get some other welcome 
+screen or an "Index" screen, you probably forgot to specify port 3000 
+in your URL).  Information similar to the following should be appended 
+to the logging output of the development server:
+
+    [info] *** Request 1 (0.005/s) [20712] [Sun Mar  8 15:49:09 2009] ***
+    [debug] "GET" request for "/" from "1.1.1.98"
+    [info] Request took 0.007342s (136.203/s)
+    .----------------------------------------------------------------+-----------.
+    | Action                                                         | Time      |
+    +----------------------------------------------------------------+-----------+
+    | /index                                                         | 0.000491s |
+    | /end                                                           | 0.000595s |
+    '----------------------------------------------------------------+-----------'
+
+Press Ctrl-C to break out of the development server.
+
+
+=head1 HELLO WORLD
+
+=head2 The Simplest Way
+
+The Root.pm controller is a place to put global actions that usually 
+execute on the root URL. Open the C<lib/Hello/Controller/Root.pm> file in 
+your editor. You will see the "index" subroutine, which is 
+responsible for displaying the welcome screen that you just saw in 
+your browser. Later on you'll want to change that to something more 
+reasonable, such as a "404" message or a redirect, but for now just 
+leave it alone.
+
+    sub index :Path :Args(0) {
+        my ( $self, $c ) = @_;
+        
+        # Hello World
+        $c->response->body( $c->welcome_message );
+    }
+
+The "C<$c>" here refers to the Catalyst context, which is used to 
+access the Catalyst application. In addition to many other things, 
+the Catalyst context provides access to "response" and "request" 
+objects. (See L<Catalyst|Catalyst>, 
+L<Catalyst::Response|Catalyst::Response>, and 
+L<Catalyst::Request|Catalyst::Request>) 
+
+C<$c-E<gt>response-E<gt>body> sets the HTTP response (see 
+L<Catalyst::Response|Catalyst::Response>), while C<$c-E<gt>welcome_message> 
+is a special method that returns the welcome message that you saw in 
+your browser.
+
+The ":Path :Args(0)" after the method name are attributes which determine 
+which URLs will be dispatched to this method. (Depending on your version of 
+Catalyst, it used to say "Private" but using that with 'default' or 'index' 
+is currently deprecated.)
+
+Some MVC frameworks handle dispatching in a central place. Catalyst, 
+by policy, prefers to handle URL dispatching with attributes on 
+controller methods. There is a lot of flexibility in specifying which 
+URLs to match.  This particular method will match all URLs, because it 
+doesn't specify the path (nothing comes after "Path"), but will only 
+accept a single args because of the ":Args(0)". 
+
+The default is to map URLs to controller names, and because of 
+the way that Perl handles namespaces through package names, 
+it is simple to create hierarchical structures in 
+Catalyst. This means that you can create controllers with deeply 
+nested actions in a clean and logical way. 
+
+For example, the URL C<http://hello.com/admin/articles/create> maps 
+to the package C<Hello::Controller::Admin::Articles>, and the C<create>
+method. 
+
+Add the following subroutine to your C<lib/Hello/Controller/Root.pm> 
+file:
+
+    sub hello : Global {
+        my ( $self, $c ) = @_;
+        
+        $c->response->body("Hello, World!");
+    }
+
+B<TIP>: See Appendix 1 for tips on removing the leading spaces when
+cutting and pasting example code from POD-based documents.
+
+Here you're sending your own string to the webpage.
+
+Save the file, start the server (stop and restart it if it's still 
+up), and go to L<http://localhost:3000/hello> to 
+see "Hello, World!"
+
+
+=head2 Hello, World! Using a View and a Template
+
+In the Catalyst world  a "View" is not a page of XHTML or a template 
+designed to present a page to a browser. It is the module that 
+determines the I<type> of view -- HTML, pdf, XML, etc. For the 
+thing that generates the I<content> of that view, (such as the 
+default Toolkit Template) the actual templates go under the 
+"root" directory.
+
+To create a TT view, run:
+
+    $ script/hello_create.pl view TT TT
+
+This creates the C<lib/Hello/View/TT.pm> module, which is a subclass of 
+C<Catalyst::View::TT>. 
+
+=over 4
+
+=item *
+
+The "view" keyword tells the create script that you are creating a view.
+
+=item *
+
+The first "TT" tells the script to name the View module "TT.pm", which is a
+commonly used name for TT views.  (You can name it anything you want, such as
+"HTML.pm".)
+
+=item *
+
+The final "TT" tells it that you are creating a Template Toolkit view.
+
+=back
+
+If you look at C<lib/Hello/View/TT.pm> you will find that it only contains a
+config statement to set the TT extension to ".tt".
+
+Now that the TT.pm "View" exists, Catalyst will autodiscover it and be 
+able to use it to display the view templates, using the "process" 
+method that it inherits from the C<Catalyst::View::TT class>.
+
+Template Toolkit is a very full featured template facility, with 
+excellent documentation at L<http://template-toolkit.org/>, 
+but since this is not a TT tutorial, we'll stick to only basic TT 
+usage here (and explore some of the more common TT features in later 
+chapters of the tutorial).
+
+Create a C<root/hello.tt> template file (put it in the C<root> under 
+the C<Hello> directory that is the base of your application). Here is 
+a simple sample:
+  
+    <p>
+        This is a TT view template, called '[% template.name %]'.
+    </p>
+
+[% and %] are markers for the TT parts of the template. Inside you can 
+access Perl variables and classes, and use TT directives. In this 
+case, we're using a special TT variable that defines the name of the 
+template file (C<hello.tt>).  The rest of the template is normal HTML. 
+
+Change the hello method in C<lib/Hello/Controller/Root.pm> to the 
+following:
+
+    sub hello : Global {
+        my ( $self, $c ) = @_;
+        
+        $c->stash->{template} = 'hello.tt';
+    }
+
+This time, instead of doing C<$c-E<gt>response-E<gt>body()>, you are setting 
+the value of the "template" hash key in the Catalyst "stash", an area 
+for putting information to share with other parts of your application. 
+The "template" key determines which template will be displayed at the 
+end of the method. Catalyst controllers have a default "end" action 
+for all methods which causes the first (or default) view to be 
+rendered (unless there's a C<$c-E<gt>response-E<gt>body()> statement). So your 
+template will be magically displayed at the end of your method.
+
+After saving the file, restart the development server, and look at 
+L<http://localhost:3000/hello> again. You should 
+see the template that you just made.
+
+
+=head1 CREATE A SIMPLE CONTROLLER AND AN ACTION
+
+Create a controller named "Site" by executing the create script:
+
+    $ script/hello_create.pl controller Site
+
+This will create a C<lib/Hello/Controller/Site.pm> file (and a test 
+file). Bring Site.pm up in your editor, and you can see that there's 
+not much there. Most people probably don't bother to use the create 
+script to make controllers after they're used to using Catalyst.
+
+In C<lib/Hello/Controller/Site.pm>, add the following method:
+
+    sub test : Local {
+        my ( $self, $c ) = @_;
+    
+        $c->stash->{username} = "John";
+        $c->stash->{template} = 'site/test.tt';
+    }
+
+Notice the "Local" attribute on the C<test> method. This will cause 
+the C<test> action (now that we have assigned an action type to the 
+method it appears as a controller "action" to Catalyst) to be executed 
+on the "controller/method" URL, or, in this case, "site/test".  We 
+will see additional information on controller actions throughout the 
+rest of the tutorial, but if you are curious take a look at 
+L<Catalyst::Manual::Intro/Actions>.
+
+It's not actually necessary to set the template value as we do here. 
+By default TT will attempt to render a template that follows the 
+naming pattern "controller/method.tt", and we're following that 
+pattern here. However, in other situations you will need to specify 
+the template (such as if you've "forwarded" to the method, or if it 
+doesn't follow the default naming convention).
+
+We've also put the variable "username" into the stash, for use in the 
+template.
+
+Make a subdirectory "site" in the "root" directory. Copy the hello.tt 
+file into the directory as C<root/site/test.tt>, or create a new 
+template file at that location. Include a line like: 
+
+    <p>Hello, [% username %]!</p>
+
+Bring up or restart the server.  Notice in the server output that 
+C</site/test> is listed in the Loaded Path actions. Go to 
+L<http://localhost:3000/site/test> in your browser.
+
+You should see your test.tt file displayed, including the name "John"
+that you set in the controller.
+
+
+=head1 AUTHORS
+
+Gerda Shank, C<gerda.shank at gmail.com>
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark & Gerda Shank, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/03_MoreCatalystBasics.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,1498 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::03_MoreCatalystBasics - Catalyst Tutorial - Chapter 3: More Catalyst Application Development Basics
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 3 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+B<03_More Catalyst Basics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This chapter of the tutorial builds on the work done in Chapter 2 to 
+explore some features that are more typical of "real world" web 
+applications. From this chapter of the tutorial onward, we will be 
+building a simple book database application.  Although the application 
+will be too limited to be of use to anyone, it should provide a basic 
+environment where we can explore a variety of features used in 
+virtually all web applications.
+
+You can check out the source code for this example from the Catalyst
+Subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+
+Please take a look at 
+L<Catalyst::Manual::Tutorial::01_Intro/CATALYST INSTALLATION> before 
+doing the rest of this tutorial.  Although the tutorial should work 
+correctly under most any recent version of Perl running on any 
+operating system, the tutorial has been written using Debian 5 and 
+tested to be sure it runs correctly in this environment.  
+
+
+=head1 CREATE A NEW APPLICATION
+
+The remainder of the tutorial will build an application called C<MyApp>.
+First use the Catalyst C<catalyst.pl> script to initialize the framework
+for the C<MyApp> application (make sure you aren't still inside the
+directory of the C<Hello> application from the previous chapter of the
+tutorial or in a directory that already has a "MyApp" subdirectory):
+
+    $ catalyst.pl MyApp
+    created "MyApp"
+    created "MyApp/script"
+    created "MyApp/lib"
+    created "MyApp/root"
+    ...
+    created "MyApp/script/myapp_create.pl"
+    $ cd MyApp
+
+This creates a similar skeletal structure to what we saw in Chapter 2 of
+the tutorial, except with C<MyApp> and C<myapp> substituted for
+C<Hello> and C<hello>.
+
+
+=head1 EDIT THE LIST OF CATALYST PLUGINS
+
+One of the greatest benefits of Catalyst is that it has such a large
+library of plugins and base classes available.  Plugins are used to
+seamlessly integrate existing Perl modules into the overall Catalyst
+framework.  In general, they do this by adding additional methods to the
+C<context> object (generally written as C<$c>) that Catalyst passes to
+every component throughout the framework.
+
+By default, Catalyst enables three plugins/flags:
+
+=over 4
+
+=item *
+
+C<-Debug> Flag
+
+Enables the Catalyst debug output you saw when we started the
+C<script/myapp_server.pl> development server earlier.  You can remove
+this item when you place your application into production.
+
+As you may have noticed, C<-Debug> is not a plugin, but a I<flag>. 
+Although most of the items specified on the C<__PACKAGE__-E<gt>setup> 
+line of your application class will be plugins, Catalyst supports a 
+limited number of flag options (of these, C<-Debug> is the most 
+common).  See the documentation for C<Catalyst.pm> to get details on 
+other flags (currently C<-Engine>, C<-Home>, and C<-Log>).
+
+If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
+messages.
+
+B<TIP>: Depending on your needs, it can be helpful to permanently
+remove C<-Debug> from C<lib/MyApp.pm> and then use the C<-d> option
+to C<script/myapp_server.pl> to re-enable it just for the development
+server.  We will not be using that approach in the tutorial, but feel
+free to make use of it in your own projects.
+
+=item *
+
+L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
+
+C<ConfigLoader> provides an automatic way to load configurable
+parameters for your application from a central
+L<Config::General|Config::General> file (versus having the values
+hard-coded inside your Perl modules).  Config::General uses syntax
+very similar to Apache configuration files.  We will see how to use
+this feature of Catalyst during the authentication and authorization
+sections (Chapter 5 and Chapter 6).
+
+B<IMPORTANT NOTE:> If you are using a version of 
+L<Catalyst::Devel|Catalyst::Devel> prior to version 1.06, be aware 
+that Catalyst changed the default format from YAML to the more 
+straightforward C<Config::General> style.  This tutorial uses the 
+newer C<myapp.conf> file for C<Config::General>. However, Catalyst 
+supports both formats and will automatically use either C<myapp.conf> 
+or C<myapp.yml> (or any other format supported by 
+L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader> and 
+L<Config::Any|Config::Any>).  If you are using a version of 
+Catalyst::Devel prior to 1.06, you can convert to the newer format by 
+simply creating the C<myapp.conf> file manually and deleting 
+C<myapp.yml>.  The default contents of the C<myapp.conf> you create 
+should only consist of one line: 
+
+    name MyApp
+
+B<TIP>: This script can be useful for converting between configuration
+formats:
+
+    perl -Ilib -e 'use MyApp; use Config::General;
+        Config::General->new->save_file("myapp.conf", MyApp->config);'
+
+=item *
+
+L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
+
+C<Static::Simple> provides an easy way to serve static content, such
+as images and CSS files, from the development server.
+
+=back
+
+For our application, we want to add one new plugin into the mix.  To 
+do this, edit C<lib/MyApp.pm> (this file is generally referred to as 
+your I<application class>) and delete the lines with:
+
+    use Catalyst qw/-Debug
+                    ConfigLoader
+                    Static::Simple/;
+
+Then replace it with:
+
+    # Load plugins
+    use Catalyst qw/-Debug
+                    ConfigLoader
+                    Static::Simple
+                
+                    StackTrace
+                    /;
+
+B<Note:> Recent versions of C<Catalyst::Devel> have used a variety of 
+techniques to load these plugins/flags.  For example, you might see
+the following:
+
+    __PACKAGE__->setup(qw/-Debug ConfigLoader Static::Simple/);
+
+Don't let these variations confuse you -- they all accomplish the same 
+result.
+
+This tells Catalyst to start using one new plugin, 
+L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>, to add a 
+stack trace to the standard Catalyst "debug screen" (the screen 
+Catalyst sends to your browser when an error occurs). Be aware that 
+L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your 
+browser, not in the console window from which you're running your 
+application, which is where logging output usually goes.
+
+Make sure that when adding new plugins that you include them as a new
+dependancies within the Makefile.PL file. For example, after adding
+the StackTrace plugin the Makefile.PL should include the following
+line:
+
+    requires 'Catalyst::Plugin::StackTrace';
+
+
+B<Notes:> 
+
+=over 4
+
+=item *
+
+C<__PACKAGE__> is just a shorthand way of referencing the name of the 
+package where it is used.  Therefore, in C<MyApp.pm>, C<__PACKAGE__> 
+is equivalent to C<MyApp>.
+
+=item *
+
+You will want to disable L<StackTrace|Catalyst::Plugin::StackTrace> 
+before you put your application into production, but it can be helpful 
+during development.
+
+=item *
+
+When specifying plugins on the C<__PACKAGE__-E<gt>setup> line, you can 
+omit C<Catalyst::Plugin::> from the name.  Additionally, you can 
+spread the plugin names across multiple lines as shown here, or place 
+them all on one (or more) lines as with the default configuration.
+
+=back
+
+
+=head1 CREATE A CATALYST CONTROLLER
+
+As discussed earlier, controllers are where you write methods that
+interact with user input.  Typically, controller methods respond to
+C<GET> and C<POST> requests from the user's web browser.
+
+Use the Catalyst C<create> script to add a controller for book-related
+actions:
+
+    $ script/myapp_create.pl controller Books
+     exists "/home/me/MyApp/script/../lib/MyApp/Controller"
+     exists "/home/me/MyApp/script/../t"
+    created "/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm"
+    created "/home/me/MyApp/script/../t/controller_Books.t"
+
+Then edit C<lib/MyApp/Controller/Books.pm> (as discussed in Chapter 2 of
+the Tutorial, Catalyst has a separate directory under C<lib/MyApp> for
+each of the three parts of MVC: C<Model>, C<View>, and C<Controller>)
+and add the following method to the controller:
+
+    =head2 list
+    
+    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
+    
+    =cut
+    
+    sub list : Local {
+        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
+        # 'Context' that's used to 'glue together' the various components
+        # that make up the application
+        my ($self, $c) = @_;
+    
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template
+        # $c->stash->{books} = [$c->model('DB::Book')->all];
+        # But, for now, use this code until we create the model later
+        $c->stash->{books} = '';
+    
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods (action methods respond to user input in
+        # your controllers).
+        $c->stash->{template} = 'books/list.tt2';
+    }
+
+B<TIP>: See Appendix 1 for tips on removing the leading spaces when
+cutting and pasting example code from POD-based documents.
+
+Programmers experienced with object-oriented Perl should recognize 
+C<$self> as a reference to the object where this method was called. 
+On the other hand, C<$c> will be new to many Perl programmers who have 
+not used Catalyst before (it's sometimes written as C<$context>).  The 
+Context object is automatically passed to all Catalyst components.  It 
+is used to pass information between components and provide access to 
+Catalyst and plugin functionality.
+
+Catalyst actions are regular Perl methods, but they make use of 
+attributes (the "C<: Local>" next to the "C<sub list>" in the code 
+above) to provide additional information to the Catalyst dispatcher 
+logic (note that the space between the colon and the attribute name is 
+optional; you will see attributes written both ways).  Most Catalyst 
+Controllers use one of five action types:
+
+=over 4
+
+=item *
+
+B<:Private> -- Use C<:Private> for methods that you want to make into 
+an action, but you do not want Catalyst to directly expose  
+to your users.  Catalyst will not map C<:Private> methods to a URI. 
+Use them for various sorts of "special" methods (the C<begin>, 
+C<auto>, etc. discussed below) or for methods you want to be able to 
+C<forward> or C<detach> to.  (If the method is a plain old "helper 
+method" that you don't want to be an action at all, then just define 
+the method without any attribute -- you can call it in your code, but 
+the Catalyst dispatcher will ignore it.)
+
+There are five types of "special" build-in C<:Private> actions: 
+C<begin>, C<end>, C<default>, C<index>, and C<auto>.
+
+=over 4
+
+=item *
+
+With C<begin>, C<end>, C<default>, C<index> private actions, only the
+most specific action of each type will be called.  For example, if you
+define a C<begin> action in your controller it will I<override> a
+C<begin> action in your application/root controller -- I<only> the
+action in your controller will be called.
+
+=item *
+
+Unlike the other actions where only a single method is called for each
+request, I<every> auto action along the chain of namespaces will be
+called.  Each C<auto> action will be called I<from the application/root
+controller down through the most specific class>.
+
+=back
+
+=item *
+
+B<:Path> -- C<:Path> actions let you map a method to an explicit URI 
+path.  For example, "C<:Path('list')>" in 
+C<lib/MyApp/Controller/Books.pm> would match on the URL 
+C<http://localhost:3000/books/list> but "C<:Path('/list')>" would match 
+on C<http://localhost:3000/list>.  You can use C<:Args()> to specify 
+how many arguments an action should accept.  See 
+L<Catalyst::Manual::Intro/Action_types> for more information and a few 
+examples.
+
+=item *
+
+B<:Local> -- C<:Local> is merely a shorthand for 
+"C<:Path('_name_of_method_')>".  For example, these are equivalent:
+"C<sub create_book :Local {...}>" and 
+"C<sub create_book :Path('create_book') {...}>".
+
+=item *
+
+B<:Global> -- C<:Global> is merely a shorthand for 
+"C<:Path('/_name_of_method_')>".  For example, these are equivalent:
+"C<sub create_book :Global {...}>" and 
+"C<sub create_book :Path('/create_book') {...}>".
+
+=item *
+
+B<:Chained> -- Newer Catalyst applications tend to use the Chained 
+dispatch form of action types because of its power and flexibility.  
+It allows a series of controller methods to be automatically dispatched
+to service a single user request.  See 
+L<Catalyst::Manual::Tutorial::04_BasicCRUD|Catalyst::Manual::Tutorial::04_BasicCRUD> 
+and L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained> 
+for more information on chained actions.
+
+=back
+
+You should refer to L<Catalyst::Manual::Intro/Action_types> for 
+additional information and for coverage of some lesser-used action 
+types not discussed here (C<Regex> and C<LocalRegex>).
+
+
+=head1 CATALYST VIEWS
+
+As mentioned in Chapter 2 of the tutorial, views are where you render
+output, typically for display in the user's web browser (but also
+possibly using into output-generation systems, such as PDF or JSON).
+The code in C<lib/MyApp/View> selects the I<type> of view to use, with
+the actual rendering template found in the C<root> directory.  As with
+virtually every aspect of Catalyst, options abound when it comes to the
+specific view technology you adopt inside your application. However,
+most Catalyst applications use the Template Toolkit, known as TT (for
+more information on TT, see L<http://www.template-toolkit.org>). Other
+somewhat popular view technologies include Mason
+(L<http://www.masonhq.com> and L<http://www.masonbook.com>) and
+L<HTML::Template> (L<http://html-template.sourceforge.net>).
+
+
+=head2 Create a Catalyst View
+
+When using TT for the Catalyst view, there are two main helper scripts:
+
+=over 4
+
+=item *
+
+L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
+
+=item *
+
+L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
+
+=back
+
+Both helpers are similar. C<TT> creates the C<lib/MyApp/View/TT.pm>
+file and leaves the creation of any hierarchical template organization
+entirely up to you. (It also creates a C<t/view_TT.t> file for testing;
+test cases will be discussed in Chapter 8.) C<TTSite>, on the other hand, 
+creates a modular and hierarchical view layout with
+separate Template Toolkit (TT) files for common header and footer
+information, configuration values, a CSS stylesheet, and more.
+
+While C<TTSite> was useful to bootstrap a project, its use is now
+deprecated and it should be considered historical.  For most Catalyst
+applications it adds redundant functionality and structure; many in the
+Catalyst community recommend that it's easier to learn both Catalyst and
+Template Toolkit if you use the more basic C<TT> approach.
+Consequently, this tutorial will use "plain old TT."
+
+Enter the following command to enable the C<TT> style of view
+rendering for this tutorial:
+
+    $ script/myapp_create.pl view TT TT
+     exists "/home/me/MyApp/script/../lib/MyApp/View"
+     exists "/home/me/MyApp/script/../t"
+     created "/home/me/MyApp/script/../lib/MyApp/View/TT.pm"
+     created "/home/me/MyApp/script/../t/view_TT.t"
+
+This simply creates a view called C<TT> (the second 'TT' argument) in 
+a file called C<TT.pm> (the first 'TT' argument). It is now up to you 
+to decide how you want to structure your view layout.  For the 
+tutorial, we will start with a very simple TT template to initially 
+demonstrate the concepts, but quickly migrate to a more typical 
+"wrapper page" type of configuration (where the "wrapper" controls the 
+overall "look and feel" of your site from a single file or set of 
+files).
+
+Edit C<lib/MyApp/View/TT.pm> and you should see that the default
+contents contains something similar to the following:
+
+    __PACKAGE__->config(TEMPLATE_EXTENSION => '.tt');
+
+And update it to match:
+
+    __PACKAGE__->config(
+        # Change default TT extension
+        TEMPLATE_EXTENSION => '.tt2',
+        # Set the location for TT files
+        INCLUDE_PATH => [
+                MyApp->path_to( 'root', 'src' ),
+            ],
+    );
+
+B<NOTE:> Make sure to add a comma after '.tt2' outside the single
+quote.
+
+This changes the default extension for Template Toolkit from '.tt' to
+'.tt2' and changes the base directory for your template files from
+C<root> to C<root/src>.  These changes from the default are done mostly
+to facilitate the application we're developing in this tutorial; as with
+most things Perl, there's more than one way to do it...
+
+B<Note:> We will use C<root/src> as the base directory for our 
+template files, which a full naming convention of 
+C<root/src/_controller_name_/_action_name_.tt2>.  Another popular option is to
+use C<root/> as the base (with a full filename pattern of 
+C<root/_controller_name_/_action_name_.tt2>).
+
+
+=head2 Create a TT Template Page
+
+First create a directory for book-related TT templates:
+
+    $ mkdir -p root/src/books
+
+Then create C<root/src/books/list.tt2> in your editor and enter:
+
+    [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
+    [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
+    [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
+    [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
+    
+    [% # Provide a title -%]
+    [% META title = 'Book List' -%]
+    
+    <table>
+    <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
+    [% # Display each book in a table row %]
+    [% FOREACH book IN books -%]
+      <tr>
+        <td>[% book.title %]</td>
+        <td>[% book.rating %]</td>
+        <td></td>
+      </tr>
+    [% END -%]
+    </table>
+
+As indicated by the inline comments above, the C<META title> line uses
+TT's META feature to provide a title to the "wrapper" that we will
+create later. Meanwhile, the C<FOREACH> loop iterates through each
+C<book> model object and prints the C<title> and C<rating> fields.
+
+The C<[%> and C<%]> tags are used to delimit Template Toolkit code.  TT
+supports a wide variety of directives for "calling" other files,
+looping, conditional logic, etc.  In general, TT simplifies the usual
+range of Perl operators down to the single dot (C<.>) operator.  This
+applies to operations as diverse as method calls, hash lookups, and list
+index values (see
+L<http://search.cpan.org/perldoc?Template::Manual::Variables> for
+details and examples).  In addition to the usual C<Template> module Pod
+documentation, you can access the TT manual at
+L<http://search.cpan.org/perldoc?Template::Manual>.
+
+B<TIP:> While you can build all sorts of complex logic into your TT
+templates, you should in general keep the "code" part of your templates
+as simple as possible.  If you need more complex logic, create helper
+methods in your model that abstract out a set of code into a single call
+from your TT template.  (Note that the same is true of your controller
+logic as well -- complex sections of code in your controllers should
+often be pulled out and placed into your model objects.)
+
+
+=head2 Test Run The Application
+
+To test your work so far, first start the development server:
+
+    $ script/myapp_server.pl
+
+Then point your browser to L<http://localhost:3000> and you should
+still get the Catalyst welcome page.  Next, change the URL in your
+browser to L<http://localhost:3000/books/list>.  If you have
+everything working so far, you should see a web page that displays
+nothing other than our column headers for "Title", "Rating", and
+"Author(s)" -- we will not see any books until we get the database and
+model working below.
+
+If you run into problems getting your application to run correctly, it
+might be helpful to refer to some of the debugging techniques covered in
+the L<Debugging|Catalyst::Manual::Tutorial::07_Debugging> part of the
+tutorial.
+
+
+=head1 CREATE A SQLITE DATABASE
+
+In this step, we make a text file with the required SQL commands to
+create a database table and load some sample data.  We will use SQLite,
+a popular database that is lightweight and easy to use.  Open
+C<myapp01.sql> in your editor and enter:
+
+    --
+    -- Create a very simple database to hold book and author information
+    --
+    CREATE TABLE book (
+            id          INTEGER PRIMARY KEY,
+            title       TEXT ,
+            rating      INTEGER
+    );
+    -- 'book_author' is a many-to-many join table between books & authors
+    CREATE TABLE book_author (
+            book_id     INTEGER,
+            author_id   INTEGER,
+            PRIMARY KEY (book_id, author_id)
+    );
+    CREATE TABLE author (
+            id          INTEGER PRIMARY KEY,
+            first_name  TEXT,
+            last_name   TEXT
+    );
+    ---
+    --- Load some sample data
+    ---
+    INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
+    INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
+    INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
+    INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
+    INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
+    INSERT INTO author VALUES (1, 'Greg', 'Bastien');
+    INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
+    INSERT INTO author VALUES (3, 'Christian', 'Degu');
+    INSERT INTO author VALUES (4, 'Richard', 'Stevens');
+    INSERT INTO author VALUES (5, 'Douglas', 'Comer');
+    INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
+    INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
+    INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
+    INSERT INTO book_author VALUES (1, 1);
+    INSERT INTO book_author VALUES (1, 2);
+    INSERT INTO book_author VALUES (1, 3);
+    INSERT INTO book_author VALUES (2, 4);
+    INSERT INTO book_author VALUES (3, 5);
+    INSERT INTO book_author VALUES (4, 6);
+    INSERT INTO book_author VALUES (4, 7);
+    INSERT INTO book_author VALUES (5, 8);
+
+Then use the following command to build a C<myapp.db> SQLite database:
+
+    $ sqlite3 myapp.db < myapp01.sql
+
+If you need to create the database more than once, you probably want to
+issue the C<rm myapp.db> command to delete the database before you use
+the C<sqlite3 myapp.db E<lt> myapp01.sql> command.
+
+Once the C<myapp.db> database file has been created and initialized, you
+can use the SQLite command line environment to do a quick dump of the
+database contents:
+
+    $ sqlite3 myapp.db
+    SQLite version 3.5.9
+    Enter ".help" for instructions
+    sqlite> select * from book;
+    1|CCSP SNRS Exam Certification Guide|5
+    2|TCP/IP Illustrated, Volume 1|5
+    3|Internetworking with TCP/IP Vol.1|4
+    4|Perl Cookbook|5
+    5|Designing with Web Standards|5
+    sqlite> .q
+    $
+
+Or:
+
+    $ sqlite3 myapp.db "select * from book"
+    1|CCSP SNRS Exam Certification Guide|5
+    2|TCP/IP Illustrated, Volume 1|5
+    3|Internetworking with TCP/IP Vol.1|4
+    4|Perl Cookbook|5
+    5|Designing with Web Standards|5
+
+As with most other SQL tools, if you are using the full "interactive"
+environment you need to terminate your SQL commands with a ";" (it's not
+required if you do a single SQL statement on the command line).  Use
+".q" to exit from SQLite from the SQLite interactive mode and return to
+your OS command prompt.
+
+Please note that here we have chosen to use 'singular' table names. This
+is because the default inflection code for L<DBIx::Class:Schema::Loader>
+does NOT handle plurals. There has been much philosophical discussion
+on whether table names should be plural or singular. There is no one
+correct answer, as long as one makes a choice and remains consistent
+with it. If you prefer plural table names (e.g. they are easier and
+more natural to read) then you will need to pass it an inflect_map 
+option. See L<DBIx::Class:Schema::Loader> for more information.
+
+For using other databases, such as PostgreSQL or MySQL, see 
+L<Appendix 2|Catalyst::Manual::Tutorial::10_Appendices>.
+
+
+=head1 DATABASE ACCESS WITH DBIx::Class
+
+Catalyst can be used with virtually any form of datastore available 
+via Perl.  For example, L<Catalyst::Model::DBI|Catalyst::Model::DBI> 
+can be used to access databases through the traditional Perl C<DBI> 
+interface or you can use a model to access files of any type on the 
+filesystem.  However, most Catalyst applications use some form of 
+object-relational mapping (ORM) technology to create objects 
+associated with tables in a relational database.  Matt Trout's 
+L<DBIx::Class|DBIx::Class> (abbreviated as "DBIC") has rapidly emerged 
+as the Perl-based ORM technology of choice. Most new Catalyst 
+applications rely on DBIx::Class, as will this tutorial.
+
+Although DBIx::Class has included support for a C<create=dynamic> mode 
+to automatically read the database structure every time the 
+application starts, it's use is no longer recommended.  While it can 
+make for "flashy" demos, the use of the C<create=static> mode we use 
+below can be implemented just as quickly and provides many advantages 
+(such as the ability to add your own methods to the overall DBIC 
+framework, a technique that we see in Chapter 4).
+
+
+=head2 Make Sure You Have a Recent Version of the DBIx::Class Model
+
+First, let's be sure we have a recent version of the DBIC helper,
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, by
+running this command:
+
+    $ perl -MCatalyst::Model::DBIC::Schema -e \
+        'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
+    0.23
+
+(please note that the '\' above is a line continuation marker and
+should NOT be included as part of the command)
+
+If you don't have version 0.23 or higher, please run this command
+to install it directly from CPAN:
+
+    $ sudo cpan Catalyst::Model::DBIC::Schema
+
+And re-run the version print command to verify that you are now at 
+0.23 or higher.
+
+
+=head2 Create Static DBIx::Class Schema Files
+
+Before you continue, make sure your C<myapp.db> database file is in 
+the application's topmost directory. Now use the model helper with 
+the C<create=static> option to read the database with 
+L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> and 
+automatically build the required files for us:
+
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp dbi:SQLite:myapp.db
+     exists "/home/me/MyApp/script/../lib/MyApp/Model"
+     exists "/home/me/MyApp/script/../t"
+    Dumping manual schema for MyApp::Schema to directory /home/me/MyApp/script/../lib ...
+    Schema dump completed.
+    created "/home/me/MyApp/script/../lib/MyApp/Model/DB.pm"
+    created "/home/me/MyApp/script/../t/model_DB.t"
+
+(please note that the '\' above is a line continuation marker and
+should NOT be included as part of the command)
+
+The C<script/myapp_create.pl> command breaks down like this:
+
+=over 4
+
+=item *
+
+C<DB> is the name of the model class to be created by the helper in 
+C<lib/MyApp/Model>.
+
+=item *
+
+C<DBIC::Schema> is the type of the model to create.
+
+=item *
+
+C<MyApp::Schema> is the name of the DBIC schema file written to
+C<lib/MyApp/Schema.pm>.
+
+=item *
+
+C<create=static> causes 
+L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> to 
+load the schema as it runs and then write that information out
+into files.
+
+=item *
+
+C<components=TimeStamp> causes the help to include the 
+L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp> DBIC component.
+
+=item *
+
+And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect string 
+for use with SQLite.
+
+=back
+
+If you look in the C<lib/MyApp/Schema.pm> file, you will find that it 
+only contains a call to the C<load_namespaces> method.  You will also 
+find that C<lib/MyApp> contains a C<Schema> subdirectory, which then 
+has a subdirectory called "Result".  This "Result" subdirectory then 
+has files named according to each of the tables in our simple database 
+(C<Author.pm>, C<BookAuthor.pm>, and C<Book.pm>).  These three 
+files are called "Result Classes" in DBIx::Class nomenclature. Although the 
+Result Class files are named after tables in our database, the classes 
+correspond to the I<row-level data> that is returned by DBIC (more on 
+this later, especially in 
+L<Catalyst::Manual::Tutorial::04_BasicCRUD/EXPLORING THE POWER OF DBIC>).
+
+The idea with the Result Source files created under 
+C<lib/MyApp/Schema/Result> by the C<create=static> option is to only 
+edit the files below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> 
+warning. If you place all of your changes below that point in the 
+file, you can regenerate the automatically created information at the 
+top of each file should your database structure get updated.
+
+Also note the "flow" of the model information across the various files 
+and directories.  Catalyst will initially load the model from 
+C<lib/MyApp/Model/DB.pm>.  This file contains a reference to 
+C<lib/MyApp/Schema.pm>, so that file is loaded next.  Finally, the 
+call to C<load_namespaces> in C<Schema.pm> will load each of the 
+"Result Class" files from the C<lib/MyApp/Schema/Result> subdirectory. 
+The final outcome is that Catalyst will dynamically create three 
+table-specific Catalyst models every time the application starts (you 
+can see these three model files listed in the debug output generated 
+when you launch the application).
+
+B<NOTE:> Older versions of 
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> use the 
+deprecated DBIx::Class C<load_classes> technique instead of the newer 
+C<load_namspaces>.  For new applications, please try to use 
+C<load_namespaces> since it more easily supports a very useful DBIC 
+technique called "ResultSet Classes."  If you need to convert an 
+existing application from "load_classes" to "load_namespaces," you can 
+use this process to automate the migration (but first make sure you 
+have v0.23 C<Catalyst::Model::DBIC::Schema> as discussed above):
+
+    $ # First delete the existing schema file to disable "compatibility" mode
+    $ rm lib/MyApp/Schema.pm
+    $
+    $ # Then re-run the helper to build the files for "load_namespaces"
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp dbi:SQLite:myapp.db
+    $
+    $ # Note that the '\' above is a line continuation marker and
+    $ # should NOT be included as part of the command
+
+    $
+    $ # Now convert the existing files over
+    $ cd lib/MyApp/Schema
+    $ perl -MIO::All -e 'for (@ARGV) { my $s < io($_); $s =~ s/.*\n\# You can replace.*?\n//s;
+          $s =~ s/'MyApp::Schema::/'MyApp::Schema::Result::/g; my $d < io("Result/$_");
+          $d =~ s/1;\n?//; "$d$s" > io("Result/$_"); }' *.pm
+    $ cd ../../..
+    $
+    $ # And finally delete the old files
+    $ rm lib/MyApp/Schema/*.pm
+
+The "C<perl -MIO::ALL ...>" script will copy all the customized 
+relationship (and other) information below "C<# DO NOT MODIFY>" line 
+from the old files in C<lib/MyApp/Schema> to the new files in 
+C<lib/MyApp/Schema/Result> (we will be starting to add some 
+"customized relationship information in the section below).
+
+
+=head1 ENABLE THE MODEL IN THE CONTROLLER
+
+Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we 
+left disabled earlier so that your version matches the following (un-
+comment the line containing C<[$c-E<gt>model('DB::Book')-E<gt>all]> 
+and delete the next 2 lines):
+
+    =head2 list
+    
+    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
+    
+    =cut
+    
+    sub list : Local {
+        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
+        # 'Context' that's used to 'glue together' the various components
+        # that make up the application
+        my ($self, $c) = @_;
+    
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template
+        $c->stash->{books} = [$c->model('DB::Book')->all];
+    
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods (action methods respond to user input in
+        # your controllers).
+        $c->stash->{template} = 'books/list.tt2';
+    }
+
+B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented 
+above written as C<$c-E<gt>model('DB')-E<gt>resultset('Book')>.  The 
+two are equivalent.  Either way, C<$c-E<gt>model> returns a 
+L<DBIx::Class::ResultSet|DBIx::Class::ResultSet> which handles queries 
+against the database and iterating over the set of results that is 
+returned.
+
+We are using the C<-E<gt>all> to fetch all of the books.  DBIC 
+supports a wide variety of more advanced operations to easily do 
+things like filtering and sorting the results.  For example, the 
+following could be used to sort the results by descending title:
+
+    $c->model('DB::Book')->search({}, {order_by => 'title DESC'});
+
+Some other examples are provided in 
+L<DBIx::Class::Manual::Cookbook/Complex WHERE clauses>, with 
+additional information found at L<DBIx::Class::ResultSet/search>, 
+L<DBIx::Class::Manual::FAQ/Searching>, 
+L<DBIx::Class::Manual::Intro|DBIx::Class::Manual::Intro> 
+and L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>.
+
+
+=head2 Test Run The Application
+
+First, let's enable an environment variable that causes DBIx::Class to 
+dump the SQL statements used to access the database.  This is a 
+helpful trick when you are trying to debug your database-oriented 
+code:
+
+    $ export DBIC_TRACE=1
+
+This assumes you are using bash as your shell -- adjust accordingly if
+you are using a different shell (for example, under tcsh, use
+C<setenv DBIC_TRACE 1>).
+
+B<NOTE:> You can also set this in your code using
+C<$class-E<gt>storage-E<gt>debug(1);>.  See
+L<DBIx::Class::Manual::Troubleshooting> for details (including options
+to log to a file instead of displaying to the Catalyst development server
+log).
+
+Then launch the Catalyst development server.  The log output should
+display something like:
+
+    $ script/myapp_server.pl
+    [debug] Debug messages enabled
+    [debug] Statistics enabled
+    [debug] Loaded plugins:
+    .----------------------------------------------------------------------------.
+    | Catalyst::Plugin::ConfigLoader  0.23                                       |
+    | Catalyst::Plugin::StackTrace  0.10                                         |
+    | Catalyst::Plugin::Static::Simple  0.21                                     |
+    '----------------------------------------------------------------------------'
+    
+    [debug] Loaded dispatcher "Catalyst::Dispatcher"
+    [debug] Loaded engine "Catalyst::Engine::HTTP"
+    [debug] Found home "/home/me/MyApp"
+    [debug] Loaded Config "/home/me/MyApp/myapp.conf"
+    [debug] Loaded components:
+    .-----------------------------------------------------------------+----------.
+    | Class                                                           | Type     |
+    +-----------------------------------------------------------------+----------+
+    | MyApp::Controller::Books                                        | instance |
+    | MyApp::Controller::Root                                         | instance |
+    | MyApp::Model::DB                                                | instance |
+    | MyApp::Model::DB::Author                                        | class    |
+    | MyApp::Model::DB::Book                                          | class    |
+    | MyApp::Model::DB::BookAuthor                                    | class    |
+    | MyApp::View::TT                                                 | instance |
+    '-----------------------------------------------------------------+----------'
+    
+    [debug] Loaded Private actions:
+    .----------------------+--------------------------------------+--------------.
+    | Private              | Class                                | Method       |
+    +----------------------+--------------------------------------+--------------+
+    | /default             | MyApp::Controller::Root              | default      |
+    | /end                 | MyApp::Controller::Root              | end          |
+    | /index               | MyApp::Controller::Root              | index        |
+    | /books/index         | MyApp::Controller::Books             | index        |
+    | /books/list          | MyApp::Controller::Books             | list         |
+    '----------------------+--------------------------------------+--------------'
+    
+    [debug] Loaded Path actions:
+    .-------------------------------------+--------------------------------------.
+    | Path                                | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /                                   | /default                             |
+    | /                                   | /index                               |
+    | /books                              | /books/index                         |
+    | /books/list                         | /books/list                          |
+    '-------------------------------------+--------------------------------------'
+    
+    [info] MyApp powered by Catalyst 5.80003
+    You can connect to your server at http://debian:3000
+
+B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
+the 'base' directory of your application, not inside the C<script>
+directory itself or it will not be able to locate the C<myapp.db>
+database file.  You can use a fully qualified or a relative path to
+locate the database file, but we did not specify that when we ran the
+model helper earlier.
+
+Some things you should note in the output above:
+
+=over 4
+
+=item *
+
+Catalyst::Model::DBIC::Schema dynamically created three model classes,
+one to represent each of the three tables in our database
+(C<MyApp::Model::DB::Author>, C<MyApp::Model::DB::BookAuthor>,
+and C<MyApp::Model::DB::Book>).
+
+=item *
+
+The "list" action in our Books controller showed up with a path of
+C</books/list>.
+
+=back
+
+Point your browser to L<http://localhost:3000> and you should still get
+the Catalyst welcome page.
+
+Next, to view the book list, change the URL in your browser to
+L<http://localhost:3000/books/list>. You should get a list of the five
+books loaded by the C<myapp01.sql> script above without any formatting.
+The rating for each book should appear on each row, but the "Author(s)"
+column will still be blank (we will fill that in later).
+
+Also notice in the output of the C<script/myapp_server.pl> that 
+DBIx::Class used the following SQL to retrieve the data:
+
+    SELECT me.id, me.title, me.rating FROM books me
+
+because we enabled DBIC_TRACE.
+
+You now have the beginnings of a simple but workable web application.
+Continue on to future sections and we will develop the application
+more fully.
+
+
+=head1 CREATE A WRAPPER FOR THE VIEW
+
+When using TT, you can (and should) create a wrapper that will
+literally wrap content around each of your templates.  This is
+certainly useful as you have one main source for changing things that
+will appear across your entire site/application instead of having to
+edit many individual files.
+
+
+=head2 Configure TT.pm For The Wrapper
+
+In order to create a wrapper, you must first edit your TT view and
+tell it where to find your wrapper file. Your TT view is located in
+C<lib/MyApp/View/TT.pm>.
+
+Edit C<lib/MyApp/View/TT.pm> and change it to match the following:
+
+    __PACKAGE__->config(
+        # Change default TT extension
+        TEMPLATE_EXTENSION => '.tt2',
+        # Set the location for TT files
+        INCLUDE_PATH => [
+                MyApp->path_to( 'root', 'src' ),
+            ],
+        # Set to 1 for detailed timer stats in your HTML as comments
+        TIMER              => 0,
+        # This is your wrapper template located in the 'root/src'
+        WRAPPER => 'wrapper.tt2',
+    );
+
+
+=head2 Create the Wrapper Template File and Stylesheet
+
+Next you need to set up your wrapper template.  Basically, you'll want
+to take the overall layout of your site and put it into this file.
+For the tutorial, open C<root/src/wrapper.tt2> and input the following:
+
+    <?xml version="1.0" encoding="UTF-8"?>
+    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+    <head>
+    <title>[% template.title or "My Catalyst App!" %]</title>
+    <link rel="stylesheet" href="[% c.uri_for('/static/css/main.css') %]" />
+    </head>
+    
+    <body>
+    <div id="outer">
+    <div id="header">
+        [%# Your logo could go here -%]
+        <img src="[% c.uri_for('/static/images/btn_88x31_powered.png') %]" />
+        [%# Insert the page title -%]
+        <h1>[% template.title or site.title %]</h1>
+    </div>
+    
+    <div id="bodyblock">
+    <div id="menu">
+        Navigation:
+        <ul>
+            <li><a href="[% c.uri_for('/books/list') %]">Home</a></li>
+            <li><a href="[% c.uri_for('/') %]" title="Catalyst Welcome Page">Welcome</a></li>
+        </ul>
+    </div><!-- end menu -->
+    
+    <div id="content">
+        [%# Status and error messages %]
+        <span class="message">[% status_msg %]</span>
+        <span class="error">[% error_msg %]</span>
+        [%# This is where TT will stick all of your template's contents. -%]
+        [% content %]
+    </div><!-- end content -->
+    </div><!-- end bodyblock -->
+    
+    <div id="footer">Copyright (c) your name goes here</div>
+    </div><!-- end outer -->
+    
+    </body>
+    </html>
+
+Notice the status and error message sections in the code above:
+
+    <span class="status">[% status_msg %]</span>
+    <span class="error">[% error_msg %]</span>
+
+If we set either message in the Catalyst stash (e.g.,
+C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it
+will be displayed whenever any view used by that request is rendered.
+The C<message> and C<error> CSS styles can be customized to suit your
+needs in the C<root/static/css/main.css> file we create below.
+
+B<Notes:> 
+
+=over 4
+
+=item *
+
+The Catalyst stash only lasts for a single HTTP request.  If
+you need to retain information across requests you can use
+L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
+Catalyst sessions in the Authentication chapter of the tutorial).
+
+=item *
+
+Although it is beyond the scope of this tutorial, you may wish to use
+a JavaScript or AJAX tool such as jQuery (L<http://www.jquery.com>) or
+Dojo (L<http://www.dojotoolkit.org>).
+
+=back
+
+
+=head3 Create A Basic Stylesheet
+
+First create a central location for stylesheets under the static
+directory:
+
+    $ mkdir root/static/css
+
+Then open the file C<root/static/css/main.css> (the file referenced in
+the stylesheet href link of our wrapper above) and add the following
+content:
+
+    #header {
+        text-align: center;
+    }
+    #header h1 {
+        margin: 0;
+    }
+    #header img {
+        float: right;
+    }
+    #footer {
+        text-align: center;
+        font-style: italic;
+        padding-top: 20px;
+    }
+    #menu {
+        font-weight: bold;
+        background-color: #ddd;
+    }
+    #menu ul {
+        list-style: none;
+        float: left;
+        margin: 0;
+        padding: 0 0 50% 5px;
+        font-weight: normal;
+        background-color: #ddd;
+        width: 100px;
+    }
+    #content {
+        margin-left: 120px;
+    }
+    .message {
+        color: #390;
+    }
+    .error {
+        color: #f00;
+    }
+
+You may wish to check out a "CSS Framework" like Emastic
+(L<http://code.google.com/p/emastic/>) as a way to quickly
+provide lots of high-quality CSS functionality.
+
+
+=head2 Test Run The Application
+
+Restart the development server and hit "Reload" in your web browser
+and you should now see a formatted version of our basic book list.
+Although our wrapper and stylesheet are obviously very simple, you
+should see how it allows us to control the overall look of an entire
+website from two central files.  To add new pages to the site, just
+provide a template that fills in the C<content> section of our wrapper
+template -- the wrapper will provide the overall feel of the page.
+
+
+=head2 Updating the Generated DBIx::Class Result Class Files
+
+Let's manually add some relationship information to the auto-generated 
+Result Class files. (Note: if you are using a database other than 
+SQLite, such as PostgreSQL, then the relationship could have been 
+automatically placed in the Result Class files.  If so, you can skip 
+this step.)  First edit C<lib/MyApp/Schema/Result/Book.pm> and add the 
+following text below the C<# You can replace this text...> comment:
+
+    #
+    # Set relationships:
+    #
+    
+    # has_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *foreign* table (aka, foreign key in peer table)
+    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'book_id');
+    
+    # many_to_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of has_many() relationship this many_to_many() is shortcut for
+    #     3) Name of belongs_to() relationship in model class of has_many() above
+    #   You must already have the has_many() defined to use a many_to_many().
+    __PACKAGE__->many_to_many(author => 'book_author', 'author');
+
+
+B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
+file.  As with any Perl package, we need to end the last line with
+a statement that evaluates to C<true>.  This is customarily done with
+C<1;> on a line by itself.
+
+This code defines both a C<has_many> and a C<many_to_many> 
+relationship. The C<many_to_many> relationship is optional, but it 
+makes it easier to map a book to its collection of authors.  Without 
+it, we would have to "walk" though the C<book_author> table as in 
+C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we 
+will see examples on how to use DBIx::Class objects in your code soon, 
+but note that because C<$book-E<gt>book_author> can return multiple 
+authors, we have to use C<first> to display a single author). 
+C<many_to_many> allows us to use the shorter C<$book-E<gt>author-
+E<gt>first-E<gt>last_name>. Note that you cannot define a 
+C<many_to_many> relationship without also having the C<has_many> 
+relationship in place.
+
+Then edit C<lib/MyApp/Schema/Result/Author.pm> and add relationship
+information as follows (again, be careful to put in above the C<1;> but
+below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
+
+    #
+    # Set relationships:
+    #
+    
+    # has_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create an accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *foreign* table (aka, foreign key in peer table)
+    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'author_id');
+    
+    # many_to_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of has_many() relationship this many_to_many() is shortcut for
+    #     3) Name of belongs_to() relationship in model class of has_many() above
+    #   You must already have the has_many() defined to use a many_to_many().
+    __PACKAGE__->many_to_many(book => 'book_author', 'book');
+
+Finally, do the same for the "join table,"
+C<lib/MyApp/Schema/Result/BookAuthor.pm>:
+
+    #
+    # Set relationships:
+    #
+    
+    # belongs_to():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *this* table
+    __PACKAGE__->belongs_to(book => 'MyApp::Schema::Result::Book', 'book_id');
+    
+    # belongs_to():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *this* table
+    __PACKAGE__->belongs_to(author => 'MyApp::Schema::Result::Author', 'author_id');
+
+
+=head2 Run The Application
+
+Run the Catalyst development server script with the C<DBIC_TRACE> option
+(it might still be enabled from earlier in the tutorial, but here is an
+alternate way to specify the option just in case):
+
+    $ DBIC_TRACE=1 script/myapp_server.pl
+
+Make sure that the application loads correctly and that you see the
+three dynamically created model class (one for each of the
+Result Classes we created).
+
+Then hit the URL L<http://localhost:3000/books/list> with your browser 
+and be sure that the book list is displayed via the relationships 
+established above. You can leave the development server running for 
+the next step if you wish.
+
+B<Note:> You will not see the authors yet because the view does not yet 
+use the new relations. Read on to the next section where we update the 
+template to do that.
+
+
+=head1 UPDATING THE VIEW
+
+Let's add a new column to our book list page that takes advantage of 
+the relationship information we manually added to our schema files in 
+the previous section.  Edit C<root/src/books/list.tt2> and replace
+the "empty" table cell "<td></td>" with the following:
+
+    ...
+    <td>
+      [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
+      [% # loop in 'side effect notation' to load just the last names of the     -%]
+      [% # authors into the list. Note that the 'push' TT vmethod does not print -%]
+      [% # a value, so nothing will be printed here.  But, if you have something -%]
+      [% # in TT that does return a method and you don't want it printed, you    -%]
+      [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to     -%]
+      [% # call it and discard the return value.                                 -%]
+      [% tt_authors = [ ];
+         tt_authors.push(author.last_name) FOREACH author = book.authors %]
+      [% # Now use a TT 'virtual method' to display the author count in parens   -%]
+      [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
+      ([% tt_authors.size | html %])
+      [% # Use another TT vmethod to join & print the names & comma separators   -%]
+      [% tt_authors.join(', ') | html %]
+    </td>
+    ...
+
+Then hit "Reload" in your browser (note that you don't need to reload 
+the development server or use the C<-r> option when updating TT 
+templates) and you should now see the number of authors each book has 
+along with a comma-separated list of the authors' last names.  (If you 
+didn't leave the development server running from the previous step, 
+you will obviously need to start it before you can refresh your 
+browser window.)
+
+If you are still running the development server with C<DBIC_TRACE>
+enabled, you should also now see five more C<SELECT> statements in the
+debug output (one for each book as the authors are being retrieved by
+DBIx::Class):
+
+    SELECT me.id, me.title, me.rating FROM books me:
+    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '1'
+    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '2'
+    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '3'
+    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '4'
+    SELECT author.id, author.first_name, author.last_name FROM book_author me  
+    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '5'
+
+Also note in C<root/src/books/list.tt2> that we are using "| html", a 
+type of TT filter, to escape characters such as E<lt> and E<gt> to &lt; 
+and &gt; and avoid various types of dangerous hacks against your 
+application.  In a real application, you would probably want to put 
+"| html" at the end of every field where a user has control over the 
+information that can appear in that field (and can therefore inject 
+markup or code if you don't "neutralize" those fields).  In addition to 
+"| html", Template Toolkit has a variety of other useful filters that 
+can found in the documentation for 
+L<Template::Filters|Template::Filters>.
+
+
+=head1 RUNNING THE APPLICATION FROM THE COMMAND LINE
+
+In some situations, it can be useful to run your application and
+display a page without using a browser.  Catalyst lets you do this
+using the C<scripts/myapp_test.pl> script.  Just supply the URL you
+wish to display and it will run that request through the normal
+controller dispatch logic and use the appropriate view to render the
+output (obviously, complex pages may dump a lot of text to your
+terminal window).  For example, if you type:
+
+    $ script/myapp_test.pl "/books/list"
+
+You should get the same text as if you visited
+L<http://localhost:3000/books/list> with the normal development server
+and asked your browser to view the page source.
+
+
+=head1 OPTIONAL INFORMATION
+
+B<NOTE: The rest of this chapter of the tutorial is optional.  You can
+skip to Chapter 4, L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>,
+if you wish.>
+
+
+=head2 Using 'RenderView' for the Default View
+
+Once your controller logic has processed the request from a user, it
+forwards processing to your view in order to generate the appropriate
+response output.  Catalyst uses
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> by
+default to automatically perform this operation.  If you look in
+C<lib/MyApp/Controller/Root.pm>, you should see the empty
+definition for the C<sub end> method:
+
+    sub end : ActionClass('RenderView') {}
+
+The following bullet points provide a quick overview of the
+C<RenderView> process:
+
+=over 4
+
+=item *
+
+C<Root.pm> is designed to hold application-wide logic.
+
+=item *
+
+At the end of a given user request, Catalyst will call the most specific
+C<end> method that's appropriate.  For example, if the controller for a
+request has an C<end> method defined, it will be called.  However, if
+the controller does not define a controller-specific C<end> method, the
+"global" C<end> method in C<Root.pm> will be called.
+
+=item *
+
+Because the definition includes an C<ActionClass> attribute, the
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
+will be executed B<after> any code inside the definition of C<sub end>
+is run.  See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
+for more information on C<ActionClass>.
+
+=item *
+
+Because C<sub end> is empty, this effectively just runs the default
+logic in C<RenderView>.  However, you can easily extend the
+C<RenderView> logic by adding your own code inside the empty method body
+(C<{}>) created by the Catalyst Helpers when we first ran the
+C<catalyst.pl> to initialize our application.  See
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more
+detailed information on how to extend C<RenderView> in C<sub end>.
+
+=back
+
+
+=head2 Using The Default Template Name
+
+By default, C<Catalyst::View::TT> will look for a template that uses the
+same name as your controller action, allowing you to save the step of
+manually specifying the template name in each action.  For example, this
+would allow us to remove the
+C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our
+C<list> action in the Books controller.  Open
+C<lib/MyApp/Controller/Books.pm> in your editor and comment out this line
+to match the following (only the C<$c-E<gt>stash-E<gt>{template}> line
+has changed):
+
+    =head2 list
+    
+    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
+    
+    =cut
+    
+    sub list : Local {
+        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
+        # 'Context' that's used to 'glue together' the various components
+        # that make up the application
+        my ($self, $c) = @_;
+    
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template
+        $c->stash->{books} = [$c->model('DB::Book')->all];
+    
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods (actions methods respond to user input in
+        # your controllers).
+        #$c->stash->{template} = 'books/list.tt2';
+    }
+
+
+You should now be able to restart the development server as per the
+previous section and access the L<http://localhost:3000/books/list>
+as before.
+
+B<NOTE:> Please note that if you use the default template technique,
+you will B<not> be able to use either the C<$c-E<gt>forward> or
+the C<$c-E<gt>detach> mechanisms (these are discussed in Chapter 2 and
+Chapter 9 of the Tutorial).
+
+B<IMPORTANT:> Make sure that you do NOT skip the following section
+before continuing to the next chapter 4 Basic CRUD.
+
+=head2 Return To A Manually Specified Template
+
+In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
+later in the tutorial, you should remove the comment from the
+statement in C<sub list> in C<lib/MyApp/Controller/Books.pm>:
+
+    $c->stash->{template} = 'books/list.tt2';
+
+Then delete the C<TEMPLATE_EXTENSION> line in
+C<lib/MyApp/View/TT.pm>.
+
+You should then be able to restart the development server and
+access L<http://localhost:3000/books/list> in the same manner as
+with earlier sections.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/04_BasicCRUD.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/04_BasicCRUD.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/04_BasicCRUD.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,1302 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::04_BasicCRUD - Catalyst Tutorial - Chapter 4: Basic CRUD
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 4 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+B<04_Basic CRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This chapter of the tutorial builds on the fairly primitive 
+application created in Chapter 3 to add basic support for Create, 
+Read, Update, and Delete (CRUD) of C<Book> objects.  Note that the 
+'list' function in Chapter 2 already implements the Read portion of 
+CRUD (although Read normally refers to reading a single object; you 
+could implement full Read functionality using the techniques 
+introduced below).  This section will focus on the Create and Delete 
+aspects of CRUD.  More advanced capabilities, including full Update 
+functionality, will be addressed in Chapter 9.
+
+Although this chapter of the tutorial will show you how to build CRUD 
+functionality yourself, another option is to use a "CRUD builder" type 
+of tool to automate the process.  You get less control, but it's quick 
+and easy.  For example, see 
+L<CatalystX::ListFramework::Builder|CatalystX::ListFramework::Builder>, 
+L<CatalystX::CRUD|CatalystX::CRUD>, and 
+L<CatalystX::CRUD::YUI|CatalystX::CRUD::YUI>.
+
+You can check out the source code for this example from the Catalyst
+Subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+
+
+=head1 FORMLESS SUBMISSION
+
+Our initial attempt at object creation will utilize the "URL
+arguments" feature of Catalyst (we will employ the more common form-
+based submission in the sections that follow).
+
+
+=head2 Include a Create Action in the Books Controller
+
+Edit C<lib/MyApp/Controller/Books.pm> and enter the following method:
+
+    =head2 url_create
+
+    Create a book with the supplied title, rating, and author
+
+    =cut
+
+    sub url_create : Local {
+        # In addition to self & context, get the title, rating, &
+        # author_id args from the URL.  Note that Catalyst automatically
+        # puts extra information after the "/<controller_name>/<action_name/"
+        # into @_
+        my ($self, $c, $title, $rating, $author_id) = @_;
+
+        # Call create() on the book model object. Pass the table
+        # columns/field values we want to set as hash values
+        my $book = $c->model('DB::Book')->create({
+                title  => $title,
+                rating => $rating
+            });
+
+        # Add a record to the join table for this book, mapping to
+        # appropriate author
+        $book->add_to_book_author({author_id => $author_id});
+        # Note: Above is a shortcut for this:
+        # $book->create_related('book_author', {author_id => $author_id});
+
+        # Assign the Book object to the stash for display in the view
+        $c->stash->{book} = $book;
+
+        # Set the TT template to use
+        $c->stash->{template} = 'books/create_done.tt2';
+    }
+
+Notice that Catalyst takes "extra slash-separated information" from the
+URL and passes it as arguments in C<@_>.  The C<url_create> action then
+uses a simple call to the DBIC C<create> method to add the requested
+information to the database (with a separate call to
+C<add_to_book_author> to update the join table).  As do virtually all
+controller methods (at least the ones that directly handle user input),
+it then sets the template that should handle this request.
+
+
+=head2 Include a Template for the 'url_create' Action:
+
+Edit C<root/src/books/create_done.tt2> and then enter:
+
+    [% # Use the TT Dumper plugin to Data::Dumper variables to the browser   -%]
+    [% # Not a good idea for production use, though. :-)  'Indent=1' is      -%]
+    [% # optional, but prevents "massive indenting" of deeply nested objects -%]
+    [% USE Dumper(Indent=1) -%]
+
+    [% # Set the page title.  META can 'go back' and set values in templates -%]
+    [% # that have been processed 'before' this template (here it's for      -%]
+    [% # root/lib/site/html and root/lib/site/header).  Note that META only  -%]
+    [% # works on simple/static strings (i.e. there is no variable           -%]
+    [% # interpolation).                                                     -%]
+    [% META title = 'Book Created' %]
+
+    [% # Output information about the record that was added.  First title.       -%]
+    <p>Added book '[% book.title %]'
+
+    [% # Output the last name of the first author.  This is complicated by an    -%]
+    [% # issue in TT 2.15 where blessed hash objects are not handled right.      -%]
+    [% # First, fetch 'book.author' from the DB once.                           -%]
+    [% authors = book.author %]
+    [% # Now use IF statements to test if 'authors.first' is "working". If so,   -%]
+    [% # we use it.  Otherwise we use a hack that seems to keep TT 2.15 happy.   -%]
+    by '[% authors.first.last_name IF authors.first;
+           authors.list.first.value.last_name IF ! authors.first %]'
+
+    [% # Output the rating for the book that was added -%]
+    with a rating of [% book.rating %].</p>
+
+    [% # Provide a link back to the list page                                    -%]
+    [% # 'uri_for()' builds a full URI; e.g., 'http://localhost:3000/books/list' -%]
+    <p><a href="[% c.uri_for('/books/list') %]">Return to list</a></p>
+
+    [% # Try out the TT Dumper (for development only!) -%]
+    <pre>
+    Dump of the 'book' variable:
+    [% Dumper.dump(book) %]
+    </pre>
+
+The TT C<USE> directive allows access to a variety of plugin modules
+(TT plugins, that is, not Catalyst plugins) to add extra functionality
+to the base TT capabilities.  Here, the plugin allows
+L<Data::Dumper|Data::Dumper> "pretty printing" of objects and
+variables.  Other than that, the rest of the code should be familiar
+from the examples in Chapter 3.
+
+
+=head2 Try the 'url_create' Feature
+
+If the application is still running from before, use C<Ctrl-C> to kill
+it. Then restart the server:
+
+    $ DBIC_TRACE=1 script/myapp_server.pl
+
+Note that new path for C</books/url_create> appears in the startup debug
+output.
+
+B<TIP>: You can use C<script/myapp_server.pl -r> to have the development
+server auto-detect changed files and reload itself (if your browser acts
+odd, you should also try throwing in a C<-k>).  If you make changes to
+the TT templates only, you do not need to reload the development server
+(only changes to "compiled code" such as Controller and Model C<.pm>
+files require a reload).
+
+Next, use your browser to enter the following URL:
+
+    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
+
+Your browser should display "Added book 'TCPIP_Illustrated_Vol-2' by
+'Stevens' with a rating of 5." along with a dump of the new book model
+object as it was returned by DBIC.  You should also see the following
+DBIC debug messages displayed in the development server log messages
+if you have DBIC_TRACE set:
+
+    INSERT INTO book (rating, title) VALUES (?, ?): `5', `TCPIP_Illustrated_Vol-2'
+    INSERT INTO book_author (author_id, book_id) VALUES (?, ?): `4', `6'
+
+The C<INSERT> statements are obviously adding the book and linking it to
+the existing record for Richard Stevens.  The C<SELECT> statement results
+from DBIC automatically fetching the book for the C<Dumper.dump(book)>.
+
+If you then click the "Return to list" link, you should find that
+there are now six books shown (if necessary, Shift+Reload or
+Ctrl+Reload your browser at the C</books/list> page).  You should now see
+the following six DBIC debug messages displayed for N=1-6:
+
+    SELECT author.id, author.first_name, author.last_name \
+        FROM book_author me  JOIN author author \
+        ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): 'N'
+
+
+=head1 CONVERT TO A CHAINED ACTION
+
+Although the example above uses the same C<Local> action type for the
+method that we saw in the previous chapter of the tutorial, there is an
+alternate approach that allows us to be more specific while also
+paving the way for more advanced capabilities.  Change the method
+declaration for C<url_create> in C<lib/MyApp/Controller/Books.pm> you
+entered above to match the following:
+
+    sub url_create :Chained('/') :PathPart('books/url_create') :Args(3) {
+
+This converts the method to take advantage of the Chained
+action/dispatch type. Chaining lets you have a single URL
+automatically dispatch to several controller methods, each of which
+can have precise control over the number of arguments that it will
+receive.  A chain can essentially be thought of having three parts --
+a beginning, a middle, and an end.  The bullets below summarize the key
+points behind each of these parts of a chain:
+
+
+=over 4
+
+
+=item *
+
+Beginning
+
+=over 4
+
+=item *
+
+B<Use "C<:Chained('/')>" to start a chain>
+
+=item *
+
+Get arguments through C<CaptureArgs()>
+
+=item *
+
+Specify the path to match with C<PathPart()>
+
+=back
+
+
+=item *
+
+Middle
+
+=over 4
+
+=item *
+
+Link to previous part of the chain with C<:Chained('_name_')>
+
+=item *
+
+Get arguments through C<CaptureArgs()>
+
+=item *
+
+Specify the path to match with C<PathPart()>
+
+=back
+
+
+=item *
+
+End
+
+=over 4
+
+=item *
+
+Link to previous part of the chain with C<:Chained('_name_')>
+
+=item *
+
+B<Do NOT get arguments through "C<CaptureArgs()>," use "C<Args()>" instead to end a chain>
+
+=item *
+
+Specify the path to match with C<PathPart()>
+
+=back
+
+
+=back
+
+In our C<url_create> method above, we have combined all three parts into
+a single method: C<:Chained('/')> to start the chain,
+C<:PathPart('books/url_create')> to specify the base URL to match, and
+C<:Args(3)> to capture exactly three arguments and to end the chain.
+
+As we will see shortly, a chain can consist of as many "links" as you
+wish, with each part capturing some arguments and doing some work
+along the way.  We will continue to use the Chained action type in this
+chapter of the tutorial and explore slightly more advanced capabilities
+with the base method and delete feature below.  But Chained dispatch
+is capable of far more.  For additional information, see
+L<Catalyst::Manual::Intro/Action types>,
+L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained>,
+and the 2006 Advent calendar entry on the subject:
+L<http://www.catalystframework.org/calendar/2006/10>.
+
+
+=head2 Try the Chained Action
+
+If you look back at the development server startup logs from your
+initial version of the C<url_create> method (the one using the
+C<:Local> attribute), you will notice that it produced output similar
+to the following:
+
+    [debug] Loaded Path actions:
+    .-------------------------------------+--------------------------------------.
+    | Path                                | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /                                   | /default                             |
+    | /                                   | /index                               |
+    | /books                              | /books/index                         |
+    | /books/list                         | /books/list                          |
+    | /books/url_create                   | /books/url_create                    |
+    '-------------------------------------+--------------------------------------'
+
+Now start the development server with our basic chained method in
+place and the startup debug output should change to something along
+the lines of the following:
+
+    [debug] Loaded Path actions:
+    .-------------------------------------+--------------------------------------.
+    | Path                                | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /                                   | /default                             |
+    | /                                   | /index                               |
+    | /books                              | /books/index                         |
+    | /books/list                         | /books/list                          |
+    '-------------------------------------+--------------------------------------'
+
+    [debug] Loaded Chained actions:
+    .-------------------------------------+--------------------------------------.
+    | Path Spec                           | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /books/url_create/*/*/*             | /books/url_create                    |
+    '-------------------------------------+--------------------------------------'
+
+C<url_create> has disappeared form the "Loaded Path actions" section
+but it now shows up under the newly created "Loaded Chained actions"
+section.  And the "/*/*/*" portion clearly shows our requirement for
+three arguments.
+
+As with our non-chained version of C<url_create>, use your browser to
+enter the following URL:
+
+    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
+
+You should see the same "Added book 'TCPIP_Illustrated_Vol-2' by
+'Stevens' with a rating of 5." along with a dump of the new book model
+object.  Click the "Return to list" link, and you should find that there
+are now seven books shown (two copies of I<TCPIP_Illustrated_Vol-2>).
+
+
+=head2 Refactor to Use a 'base' Method to Start the Chains
+
+Let's make a quick update to our initial Chained action to show a
+little more of the power of chaining.  First, open
+C<lib/MyApp/Controller/Books.pm> in your editor and add the following
+method:
+
+    =head2 base
+
+    Can place common logic to start chained dispatch here
+
+    =cut
+
+    sub base :Chained('/') :PathPart('books') :CaptureArgs(0) {
+        my ($self, $c) = @_;
+
+        # Store the ResultSet in stash so it's available for other methods
+        $c->stash->{resultset} = $c->model('DB::Book');
+
+        # Print a message to the debug log
+        $c->log->debug('*** INSIDE BASE METHOD ***');
+    }
+
+Here we print a log message and store the DBIC ResultSet in
+C<$c-E<gt>stash-E<gt>{resultset}> so that it's automatically available
+for other actions that chain off C<base>.  If your controller always
+needs a book ID as its first argument, you could have the base method
+capture that argument (with C<:CaptureArgs(1)>) and use it to pull the
+book object with C<-E<gt>find($id)> and leave it in the stash for
+later parts of your chains to then act upon. Because we have several
+actions that don't need to retrieve a book (such as the C<url_create>
+we are working with now), we will instead add that functionality
+to a common C<object> action shortly.
+
+As for C<url_create>, let's modify it to first dispatch to C<base>.
+Open up C<lib/MyApp/Controller/Books.pm> and edit the declaration for
+C<url_create> to match the following:
+
+    sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
+
+Next, try out the refactored chain by restarting the development
+server.  Notice that our "Loaded Chained actions" section has changed
+slightly:
+
+    [debug] Loaded Chained actions:
+    .-------------------------------------+--------------------------------------.
+    | Path Spec                           | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /books/url_create/*/*/*             | /books/base (0)                      |
+    |                                     | => /books/url_create                 |
+    '-------------------------------------+--------------------------------------'
+
+The "Path Spec" is the same, but now it maps to two Private actions as
+we would expect.
+
+Once again, enter the following URL into your browser:
+
+    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
+
+The same "Added book 'TCPIP_Illustrated_Vol-2' by 'Stevens' with a
+rating of 5." message and a dump of the new book object should appear.
+Also notice the extra debug message in the development server output
+from the C<base> method.  Click the "Return to list" link, and you
+should find that there are now eight books shown.
+
+
+=head1 MANUALLY BUILDING A CREATE FORM
+
+Although the C<url_create> action in the previous step does begin to
+reveal the power and flexibility of both Catalyst and DBIC, it's
+obviously not a very realistic example of how users should be expected
+to enter data.  This section begins to address that concern.
+
+
+=head2 Add Method to Display The Form
+
+Edit C<lib/MyApp/Controller/Books.pm> and add the following method:
+
+    =head2 form_create
+
+    Display form to collect information for book to create
+
+    =cut
+
+    sub form_create :Chained('base') :PathPart('form_create') :Args(0) {
+        my ($self, $c) = @_;
+
+        # Set the TT template to use
+        $c->stash->{template} = 'books/form_create.tt2';
+    }
+
+This action simply invokes a view containing a form to create a book.
+
+
+=head2 Add a Template for the Form
+
+Open C<root/src/books/form_create.tt2> in your editor and enter:
+
+    [% META title = 'Manual Form Book Create' -%]
+
+    <form method="post" action="[% c.uri_for('form_create_do') %]">
+    <table>
+      <tr><td>Title:</td><td><input type="text" name="title"></td></tr>
+      <tr><td>Rating:</td><td><input type="text" name="rating"></td></tr>
+      <tr><td>Author ID:</td><td><input type="text" name="author_id"></td></tr>
+    </table>
+    <input type="submit" name="Submit" value="Submit">
+    </form>
+
+Note that we have specified the target of the form data as
+C<form_create_do>, the method created in the section that follows.
+
+
+=head2 Add a Method to Process Form Values and Update Database
+
+Edit C<lib/MyApp/Controller/Books.pm> and add the following method to
+save the form information to the database:
+
+    =head2 form_create_do
+
+    Take information from form and add to database
+
+    =cut
+
+    sub form_create_do :Chained('base') :PathPart('form_create_do') :Args(0) {
+        my ($self, $c) = @_;
+
+        # Retrieve the values from the form
+        my $title     = $c->request->params->{title}     || 'N/A';
+        my $rating    = $c->request->params->{rating}    || 'N/A';
+        my $author_id = $c->request->params->{author_id} || '1';
+
+        # Create the book
+        my $book = $c->model('DB::Book')->create({
+                title   => $title,
+                rating  => $rating,
+            });
+        # Handle relationship with author
+        $book->add_to_book_author({author_id => $author_id});
+
+        # Store new model object in stash
+        $c->stash->{book} = $book;
+
+        # Avoid Data::Dumper issue mentioned earlier
+        # You can probably omit this
+        $Data::Dumper::Useperl = 1;
+
+        # Set the TT template to use
+        $c->stash->{template} = 'books/create_done.tt2';
+    }
+
+
+=head2 Test Out The Form
+
+If the application is still running from before, use C<Ctrl-C> to kill
+it.  Then restart the server:
+
+    $ script/myapp_server.pl
+
+Notice that the server startup log reflects the two new chained
+methods that we added:
+
+    [debug] Loaded Chained actions:
+    .-------------------------------------+--------------------------------------.
+    | Path Spec                           | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /books/form_create                  | /books/base (0)                      |
+    |                                     | => /books/form_create                |
+    | /books/form_create_do               | /books/base (0)                      |
+    |                                     | => /books/form_create_do             |
+    | /books/url_create/*/*/*             | /books/base (0)                      |
+    |                                     | => /books/url_create                 |
+    '-------------------------------------+--------------------------------------'
+
+Point your browser to L<http://localhost:3000/books/form_create> and
+enter "TCP/IP Illustrated, Vol 3" for the title, a rating of 5, and an
+author ID of 4.  You should then see the output of the same
+C<create_done.tt2> template seen in earlier examples.  Finally, click
+"Return to list" to view the full list of books.
+
+B<Note:> Having the user enter the primary key ID for the author is
+obviously crude; we will address this concern with a drop-down list in
+Chapter 9.
+
+
+=head1 A SIMPLE DELETE FEATURE
+
+Turning our attention to the Delete portion of CRUD, this section
+illustrates some basic techniques that can be used to remove information
+from the database.
+
+
+=head2 Include a Delete Link in the List
+
+Edit C<root/src/books/list.tt2> and update it to match the following (two
+sections have changed: 1) the additional '<th>Links</th>' table header,
+and 2) the four lines for the Delete link near the bottom):
+
+    [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
+    [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
+    [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
+    [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
+
+    [% # Provide a title -%]
+    [% META title = 'Book List' -%]
+
+    <table>
+    <tr><th>Title</th><th>Rating</th><th>Author(s)</th><th>Links</th></tr>
+    [% # Display each book in a table row %]
+    [% FOREACH book IN books -%]
+      <tr>
+        <td>[% book.title %]</td>
+        <td>[% book.rating %]</td>
+        <td>
+          [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
+          [% # loop in 'side effect notation' to load just the last names of the     -%]
+          [% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
+          [% # a value, so nothing will be printed here.  But, if you have something -%]
+          [% # in TT that does return a value and you don't want it printed, you can -%]
+          [% # 1) assign it to a bogus value, or # 2) use the CALL keyword to        -%]
+          [% # call it and discard the return value.                                 -%]
+          [% tt_authors = [ ];
+             tt_authors.push(author.last_name) FOREACH author = book.author %]
+          [% # Now use a TT 'virtual method' to display the author count in parens   -%]
+          [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
+          ([% tt_authors.size | html %])
+          [% # Use another TT vmethod to join & print the names & comma separators   -%]
+          [% tt_authors.join(', ') | html %]
+        </td>
+        <td>
+          [% # Add a link to delete a book %]
+          <a href="[% c.uri_for(c.controller.action_for('delete'), [book.id]) %]">Delete</a>
+        </td>
+      </tr>
+    [% END -%]
+    </table>
+
+The additional code is obviously designed to add a new column to the
+right side of the table with a C<Delete> "button" (for simplicity, links
+will be used instead of full HTML buttons; in practice, anything that
+modifies data should be handled with a form sending a PUT request).
+
+Also notice that we are using a more advanced form of C<uri_for> than
+we have seen before.  Here we use
+C<$c-E<gt>controller-E<gt>action_for> to automatically generate a URI
+appropriate for that action based on the method we want to link to
+while inserting the C<book.id> value into the appropriate place.  Now,
+if you ever change C<:PathPart('delete')> in your controller method to
+C<:PathPart('kill')>, then your links will automatically update
+without any changes to your .tt2 template file.  As long as the name
+of your method does not change (here, "delete"), then your links will
+still be correct.  There are a few shortcuts and options when using
+C<action_for()>:
+
+=over 4
+
+=item *
+
+If you are referring to a method in the current controller, you can
+use C<$self-E<gt>action_for('_method_name_')>.
+
+=item *
+
+If you are referring to a method in a different controller, you need
+to include that controller's name as an argument to C<controller()>, as in
+C<$c-E<gt>controller('_controller_name_')-E<gt>action_for('_method_name_')>.
+
+=back
+
+B<Note:> In practice you should B<never> use a GET request to delete a
+record -- always use POST for actions that will modify data.  We are
+doing it here for illustrative and simplicity purposes only.
+
+
+=head2 Add a Common Method to Retrieve a Book for the Chain
+
+As mentioned earlier, since we have a mixture of actions that operate
+on a single book ID and others that do not, we should not have C<base>
+capture the book ID, find the corresponding book in the database and
+save it in the stash for later links in the chain.  However, just
+because that logic does not belong in C<base> doesn't mean that we
+can't create another location to centralize the book lookup code.  In
+our case, we will create a method called C<object> that will store the
+specific book in the stash.  Chains that always operate on a single
+existing book can chain off this method, but methods such as
+C<url_create> that don't operate on an existing book can chain
+directly off base.
+
+To add the C<object> method, edit C<lib/MyApp/Controller/Books.pm>
+and add the following code:
+
+    =head2 object
+
+    Fetch the specified book object based on the book ID and store
+    it in the stash
+
+    =cut
+
+    sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
+        # $id = primary key of book to delete
+        my ($self, $c, $id) = @_;
+
+        # Find the book object and store it in the stash
+        $c->stash(object => $c->stash->{resultset}->find($id));
+
+        # Make sure the lookup was successful.  You would probably
+        # want to do something like this in a real app:
+        #   $c->detach('/error_404') if !$c->stash->{object};
+        die "Book $id not found!" if !$c->stash->{object};
+    }
+
+Now, any other method that chains off C<object> will automatically
+have the appropriate book waiting for it in
+C<$c-E<gt>stash-E<gt>{object}>.
+
+Also note that we are using a different technique for setting
+C<$c-E<gt>stash>.  The advantage of this style is that it lets you set
+multiple stash variables at a time.  For example:
+
+    $c->stash(object => $c->stash->{resultset}->find($id),
+              another_thing => 1);
+
+or as a hashref:
+
+    $c->stash({object => $c->stash->{resultset}->find($id),
+              another_thing => 1});
+
+Either format works, but the C<$c-E<gt>stash(name =E<gt> value);>
+style is growing in popularity -- you may wish to use it all
+the time (even when you are only setting a single value).
+
+
+=head2 Add a Delete Action to the Controller
+
+Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
+following method:
+
+    =head2 delete
+
+    Delete a book
+
+    =cut
+
+    sub delete :Chained('object') :PathPart('delete') :Args(0) {
+        my ($self, $c) = @_;
+
+        # Use the book object saved by 'object' and delete it along
+        # with related 'book_author' entries
+        $c->stash->{object}->delete;
+
+        # Set a status message to be displayed at the top of the view
+        $c->stash->{status_msg} = "Book deleted.";
+
+        # Forward to the list action/method in this controller
+        $c->forward('list');
+    }
+
+This method first deletes the book object saved by the C<object> method.
+However, it also removes the corresponding entry from the
+C<book_author> table with a cascading delete.
+
+Then, rather than forwarding to a "delete done" page as we did with the
+earlier create example, it simply sets the C<status_msg> to display a
+notification to the user as the normal list view is rendered.
+
+The C<delete> action uses the context C<forward> method to return the
+user to the book list.  The C<detach> method could have also been used.
+Whereas C<forward> I<returns> to the original action once it is
+completed, C<detach> does I<not> return.  Other than that, the two are
+equivalent.
+
+
+=head2 Try the Delete Feature
+
+If the application is still running from before, use C<Ctrl-C> to kill
+it.  Then restart the server:
+
+    $ DBIC_TRACE=1 script/myapp_server.pl
+
+The C<delete> method now appears in the "Loaded Chained actions" section
+of the startup debug output:
+
+    [debug] Loaded Chained actions:
+    .-------------------------------------+--------------------------------------.
+    | Path Spec                           | Private                              |
+    +-------------------------------------+--------------------------------------+
+    | /books/id/*/delete                  | /books/base (0)                      |
+    |                                     | -> /books/object (1)                 |
+    |                                     | => /books/delete                     |
+    | /books/form_create                  | /books/base (0)                      |
+    |                                     | => /books/form_create                |
+    | /books/form_create_do               | /books/base (0)                      |
+    |                                     | => /books/form_create_do             |
+    | /books/url_create/*/*/*             | /books/base (0)                      |
+    |                                     | => /books/url_create                 |
+    '-------------------------------------+--------------------------------------'
+
+Then point your browser to L<http://localhost:3000/books/list> and click
+the "Delete" link next to the first "TCPIP_Illustrated_Vol-2".  A green
+"Book deleted" status message should display at the top of the page,
+along with a list of the eight remaining books.  You will also see the
+cascading delete operation via the DBIC_TRACE output:
+
+    SELECT me.id, me.title, me.rating FROM book me WHERE ( ( me.id = ? ) ): '6'
+    DELETE FROM book WHERE ( id = ? ): '6'
+    SELECT me.book_id, me.author_id FROM book_author me WHERE ( me.book_id = ? ): '6'
+    DELETE FROM book_author WHERE ( author_id = ? AND book_id = ? ): '4', '6'
+
+
+=head2 Fixing a Dangerous URL
+
+Note the URL in your browser once you have performed the deletion in the
+prior step -- it is still referencing the delete action:
+
+    http://localhost:3000/books/id/6/delete
+
+What if the user were to press reload with this URL still active?  In
+this case the redundant delete is harmless (although it does generate
+an exception screen, it doesn't perform any undesirable actions on the
+application or database), but in other cases this could clearly be
+extremely dangerous.
+
+We can improve the logic by converting to a redirect.  Unlike
+C<$c-E<gt>forward('list'))> or C<$c-E<gt>detach('list'))> that perform
+a server-side alteration in the flow of processing, a redirect is a
+client-side mechanism that causes the browser to issue an entirely
+new request.  As a result, the URL in the browser is updated to match
+the destination of the redirection URL.
+
+To convert the forward used in the previous section to a redirect,
+open C<lib/MyApp/Controller/Books.pm> and edit the existing
+C<sub delete> method to match:
+
+    =head2 delete
+
+    Delete a book
+
+    =cut
+
+    sub delete :Chained('object') :PathPart('delete') :Args(0) {
+        my ($self, $c) = @_;
+
+        # Use the book object saved by 'object' and delete it along
+        # with related 'book_author' entries
+        $c->stash->{object}->delete;
+
+        # Set a status message to be displayed at the top of the view
+        $c->stash->{status_msg} = "Book deleted.";
+
+        # Redirect the user back to the list page.  Note the use
+        # of $self->action_for as earlier in this section (BasicCRUD)
+        $c->response->redirect($c->uri_for($self->action_for('list')));
+    }
+
+
+=head2 Try the Delete and Redirect Logic
+
+Restart the development server and point your browser to
+L<http://localhost:3000/books/list> (don't just hit "Refresh" in your
+browser since we left the URL in an invalid state in the previous
+section!) and delete the first copy of the remaining two
+"TCPIP_Illustrated_Vol-2" books.  The URL in your browser should return
+to the L<http://localhost:3000/books/list> URL, so that is an
+improvement, but notice that I<no green "Book deleted" status message is
+displayed>.  Because the stash is reset on every request (and a redirect
+involves a second request), the C<status_msg> is cleared before it can
+be displayed.
+
+
+=head2 Using 'uri_for' to Pass Query Parameters
+
+There are several ways to pass information across a redirect. One 
+option is to use the C<flash> technique that we will see in Chapter 5 
+of this tutorial; however, here we will pass the information via query 
+parameters on the redirect itself.  Open 
+C<lib/MyApp/Controller/Books.pm> and update the existing C<sub delete> 
+method to match the following:
+
+    =head2 delete
+
+    Delete a book
+
+    =cut
+
+    sub delete :Chained('object') :PathPart('delete') :Args(0) {
+        my ($self, $c) = @_;
+
+        # Use the book object saved by 'object' and delete it along
+        # with related 'book_author' entries
+        $c->stash->{object}->delete;
+
+        # Redirect the user back to the list page with status msg as an arg
+        $c->response->redirect($c->uri_for($self->action_for('list'),
+            {status_msg => "Book deleted."}));
+    }
+
+This modification simply leverages the ability of C<uri_for> to include
+an arbitrary number of name/value pairs in a hash reference.  Next, we
+need to update C<root/src/wrapper.tt2> to handle C<status_msg> as a
+query parameter:
+
+    ...
+    <div id="content">
+        [%# Status and error messages %]
+        <span class="message">[% status_msg || c.request.params.status_msg %]</span>
+        <span class="error">[% error_msg %]</span>
+        [%# This is where TT will stick all of your template's contents. -%]
+        [% content %]
+    </div><!-- end content -->
+    ...
+
+Although the sample above only shows the C<content> div, leave the
+rest of the file intact -- the only change we made to the C<wrapper.tt2>
+was to add "C<|| c.request.params.status_msg>" to the
+C<E<lt>span class="message"E<gt>> line.
+
+
+=head2 Try the Delete and Redirect With Query Param Logic
+
+Restart the development server and point your browser to
+L<http://localhost:3000/books/list> (you should now be able to safely
+hit "refresh" in your browser).  Then delete the remaining copy of
+"TCPIP_Illustrated_Vol-2".  The green "Book deleted" status message
+should return.
+
+B<NOTE:> Another popular method for maintaining server-side
+information across a redirect is to use the C<flash> technique we
+discuss in the next chapter of the tutorial,
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>. While
+C<flash> is a "slicker" mechanism in that it's all handled by the
+server and doesn't "pollute" your URLs, B<it is important to note that
+C<flash> can lead to situations where the wrong information shows up
+in the wrong browser window if the user has multiple windows or
+browser tabs open>.  For example, Window A causes something to be
+placed in the stash, but before that window performs a redirect,
+Window B makes a request to the server and gets the status information
+that should really go to Window A.  For this reason, you may wish
+to use the "query param" technique shown here in your applications.
+
+
+=head1 EXPLORING THE POWER OF DBIC
+
+In this section we will explore some additional capabilities offered
+by DBIx::Class.  Although these features have relatively little to do
+with Catalyst per se, you will almost certainly want to take advantage
+of them in your applications.
+
+
+=head2 Add Datetime Columns to Our Existing Books Table
+
+Let's add two columns to our existing C<books> table to track when
+each book was added and when each book is updated:
+
+    $ sqlite3 myapp.db
+    sqlite> ALTER TABLE book ADD created INTEGER;
+    sqlite> ALTER TABLE book ADD updated INTEGER;
+    sqlite> UPDATE book SET created = DATETIME('NOW'), updated = DATETIME('NOW');
+    sqlite> SELECT * FROM book;
+    1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
+    4|Perl Cookbook|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    5|Designing with Web Standards|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    9|TCP/IP Illustrated, Vol 3|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    sqlite> .quit
+    $
+
+This will modify the C<books> table to include the two new fields
+and populate those fields with the current time.
+
+
+=head2 Update DBIx::Class to Automatically Handle the Datetime Columns
+
+Next, we should re-run the DBIC helper to update the Result Classes
+with the new fields:
+
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp dbi:SQLite:myapp.db
+     exists "/root/dev/MyApp/script/../lib/MyApp/Model"
+     exists "/root/dev/MyApp/script/../t"
+    Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
+    Schema dump completed.
+     exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
+
+Notice that we modified our use of the helper slightly: we told
+it to include the L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp>
+in the C<load_components> line of the Result Classes.
+
+If you open C<lib/MyApp/Schema/Result/Book.pm> in your editor you
+should see that the C<created> and C<updated> fields are now included
+in the call to C<add_columns()>, but our relationship information below
+the "C<# DO NOT MODIFY...>" line was automatically preserved.
+
+While we have this file open, let's update it with some additional
+information to have DBIC automatically handle the updating of these
+two fields for us.  Insert the following code at the bottom of the
+file (it B<must> be B<below> the "C<# DO NOT MODIFY...>" line and
+B<above> the C<1;> on the last line):
+
+    #
+    # Enable automatic date handling
+    #
+    __PACKAGE__->add_columns(
+        "created",
+        { data_type => 'datetime', set_on_create => 1 },
+        "updated",
+        { data_type => 'datetime', set_on_create => 1, set_on_update => 1 },
+    );
+
+This will override the definition for these fields that Schema::Loader 
+placed at the top of the file.  The C<set_on_create> and 
+C<set_on_update> options will cause DBIx::Class to automatically 
+update the timestamps in these columns whenever a row is created or 
+modified.
+
+To test this out, restart the development server using the
+C<DBIC_TRACE=1> option:
+
+    DBIC_TRACE=1 script/myapp_server.pl
+
+Then enter the following URL into your web browser:
+
+    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
+
+You should get the same "Book Created" screen we saw above.  However,
+if you now use the sqlite3 command-line tool to dump the C<books> table,
+you will see that the new book we added has an appropriate date and
+time entered for it (see the last line in the listing below):
+
+    sqlite3 myapp.db "select * from book"
+    1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
+    4|Perl Cookbook|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    5|Designing with Web Standards|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    9|TCP/IP Illustrated, Vol 3|5|2009-03-08 16:26:35|2009-03-08 16:26:35
+    10|TCPIP_Illustrated_Vol-2|5|2009-03-08 16:29:08|2009-03-08 16:29:08
+
+Notice in the debug log that the SQL DBIC generated has changed to
+incorporate the datetime logic:
+
+    INSERT INTO book (created, rating, title, updated) VALUES (?, ?, ?, ?):
+    '2009-03-08 16:29:08', '5', 'TCPIP_Illustrated_Vol-2', '2009-03-08 16:29:08'
+    INSERT INTO book_author (author_id, book_id) VALUES (?, ?): '4', '10'
+
+
+=head2 Create a ResultSet Class
+
+An often overlooked but extremely powerful features of DBIC is that it
+allows you to supply your own subclasses of C<DBIx::Class::ResultSet>.
+It allows you to pull complex and unsightly "query code" out of your
+controllers and encapsulate it in a method of your ResultSet Class.
+These "canned queries" in your ResultSet Class can then be invoked
+via a single call, resulting in much cleaner and easier to read
+controller code.
+
+To illustrate the concept with a fairly simple example, let's create a
+method that returns books added in the last 10 minutes.  Start by
+making a directory where DBIx::Class will look for our ResultSet Class:
+
+    mkdir lib/MyApp/Schema/ResultSet
+
+Then open C<lib/MyApp/Schema/ResultSet/Book.pm> and enter the following:
+
+    package MyApp::Schema::ResultSet::Book;
+
+    use strict;
+    use warnings;
+    use base 'DBIx::Class::ResultSet';
+
+    =head2 created_after
+
+    A predefined search for recently added books
+
+    =cut
+
+    sub created_after {
+        my ($self, $datetime) = @_;
+
+        my $date_str = $self->_source_handle->schema->storage
+                              ->datetime_parser->format_datetime($datetime);
+
+        return $self->search({
+            created => { '>' => $date_str }
+        });
+    }
+
+    1;
+
+Then we need to tell the Result Class to to treat this as a ResultSet
+Class.  Open C<lib/MyApp/Schema/Result/Book.pm> and add the following
+above the "C<1;>" at the bottom of the file:
+
+    #
+    # Set ResultSet Class
+    #
+    __PACKAGE__->resultset_class('MyApp::Schema::ResultSet::Book');
+
+Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
+
+    =head2 list_recent
+
+    List recently created books
+
+    =cut
+
+    sub list_recent :Chained('base') :PathPart('list_recent') :Args(1) {
+        my ($self, $c, $mins) = @_;
+
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template, but only
+        # retrieve books created within the last $min number of minutes
+        $c->stash->{books} = [$c->model('DB::Book')
+                                ->created_after(DateTime->now->subtract(minutes => $mins))];
+
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods (action methods respond to user input in
+        # your controllers).
+        $c->stash->{template} = 'books/list.tt2';
+    }
+
+Now start the development server with C<DBIC_TRACE=1> and try
+different values for the minutes argument (the final number value) for
+the URL C<http://localhost:3000/books/list_recent/10>.  For example,
+this would list all books added in the last fifteen minutes:
+
+    http://localhost:3000/books/list_recent/15
+
+Depending on how recently you added books, you might want to
+try a higher or lower value.
+
+
+=head2 Chaining ResultSets
+
+One of the most helpful and powerful features in DBIx::Class is that 
+it allows you to "chain together" a series of queries (note that this 
+has nothing to do with the "Chained Dispatch" for Catalyst that we 
+were discussing above).  Because each ResultSet returns another 
+ResultSet, you can take an initial query and immediately feed that 
+into a second query (and so on for as many queries you need). Note 
+that no matter how many ResultSets you chain together, the database 
+itself will not be hit until you use a method that attempts to access 
+the data. And, because this technique carries over to the ResultSet 
+Class feature we implemented in the previous section for our "canned 
+search", we can combine the two capabilities.  For example, let's add 
+an action to our C<Books> controller that lists books that are both 
+recent I<and> have "TCP" in the title.  Open up 
+C<lib/MyApp/Controller/Books.pm> and add the following method:
+
+    =head2 list_recent_tcp
+
+    List recently created books
+
+    =cut
+
+    sub list_recent_tcp :Chained('base') :PathPart('list_recent_tcp') :Args(1) {
+        my ($self, $c, $mins) = @_;
+
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template, but only
+        # retrieve books created within the last $min number of minutes
+        # AND that have 'TCP' in the title
+        $c->stash->{books} = [$c->model('DB::Book')
+                                ->created_after(DateTime->now->subtract(minutes => $mins))
+                                ->search({title => {'like', '%TCP%'}})
+                             ];
+
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods (action methods respond to user input in
+        # your controllers).
+        $c->stash->{template} = 'books/list.tt2';
+    }
+
+To try this out, restart the development server with:
+
+    DBIC_TRACE=1 script/myapp_server.pl
+
+And enter the following URL into your browser:
+
+    http://localhost:3000/books/list_recent_tcp/100
+
+And you should get a list of books added in the last 100 minutes that
+contain the string "TCP" in the title.  However, if you look at all
+books within the last 100 minutes, you should get a longer list
+(again, you might have to adjust the number of minutes depending on
+how recently you added books to your database):
+
+    http://localhost:3000/books/list_recent/100
+
+Take a look at the DBIC_TRACE output in the development server log for
+the first URL and you should see something similar to the following:
+
+    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me
+    WHERE ( ( ( title LIKE ? ) AND ( created > ? ) ) ): '%TCP%', '2009-03-08 14:52:54'
+
+However, let's not pollute our controller code with this raw "TCP"
+query -- it would be cleaner to encapsulate that code in a method on
+our ResultSet Class.  To do this, open
+C<lib/MyApp/Schema/ResultSet/Book.pm> and add the following method:
+
+    =head2 title_like
+
+    A predefined search for books with a 'LIKE' search in the string
+
+    =cut
+
+    sub title_like {
+        my ($self, $title_str) = @_;
+
+        return $self->search({
+            title => { 'like' => "%$title_str%" }
+        });
+    }
+
+We defined the search string as C<$title_str> to make the method more
+flexible.  Now update the C<list_recent_tcp> method in
+C<lib/MyApp/Controller/Books.pm> to match the following (we have
+replaced the C<-E<gt>search> line with the C<-E<gt>title_like> line
+shown here -- the rest of the method should be the same):
+
+    =head2 list_recent_tcp
+
+    List recently created books
+
+    =cut
+
+    sub list_recent_tcp :Chained('base') :PathPart('list_recent_tcp') :Args(1) {
+        my ($self, $c, $mins) = @_;
+
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template, but only
+        # retrieve books created within the last $min number of minutes
+        # AND that have 'TCP' in the title
+        $c->stash->{books} = [$c->model('DB::Book')
+                                ->created_after(DateTime->now->subtract(minutes => $mins))
+                                ->title_like('TCP')
+                             ];
+
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods (action methods respond to user input in
+        # your controllers).
+        $c->stash->{template} = 'books/list.tt2';
+    }
+
+Then restart the development server and try out the C<list_recent_tcp>
+and C<list_recent> URL as we did above.  It should work just the same,
+but our code is obviously cleaner and more modular, while also being
+more flexible at the same time.
+
+
+=head2 Adding Methods to Result Classes
+
+In the previous two sections we saw a good example of how we could use 
+DBIx::Class ResultSet Classes to clean up our code for an entire query 
+(for example, our "canned searches" that filtered the entire query). 
+We can do a similar improvement when working with individual rows as 
+well.  Whereas the ResultSet construct is used in DBIC to correspond 
+to an entire query, the Result Class construct is used to represent a 
+row. Therefore, we can add row-specific "helper methods" to our Result 
+Classes stored in C<lib/MyApp/Schema/Result/>. For example, open 
+C<lib/MyApp/Schema/Result/Author.pm> and add the following method (as 
+always, it must be above the closing "C<1;>"):
+
+    #
+    # Helper methods
+    #
+    sub full_name {
+        my ($self) = @_;
+
+        return $self->first_name . ' ' . $self->last_name;
+    }
+
+This will allow us to conveniently retrieve both the first and last
+name for an author in one shot.  Now open C<root/src/books/list.tt2>
+and change the definition of C<tt_authors> from this:
+
+    ...
+      [% tt_authors = [ ];
+         tt_authors.push(author.last_name) FOREACH author = book.author %]
+    ...
+
+to:
+
+    ...
+      [% tt_authors = [ ];
+         tt_authors.push(author.full_name) FOREACH author = book.author %]
+    ...
+
+(Only C<author.last_name> was changed to C<author.full_name> -- the
+rest of the file should remain the same.)
+
+Now restart the development server and go to the standard book list
+URL:
+
+    http://localhost:3000/books/list
+
+The "Author(s)" column will now contain both the first and last name.
+And, because the concatenation logic was encapsulated inside our
+Result Class, it keeps the code inside our .tt template nice and clean
+(remember, we want the templates to be as close to pure HTML markup as
+possible). Obviously, this capability becomes even more useful as you
+use to to remove even more complicated row-specific logic from your
+templates!
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/05_Authentication.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/05_Authentication.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/05_Authentication.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,916 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::05_Authentication - Catalyst Tutorial - Chapter 5: Authentication
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 5 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+B<05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+Now that we finally have a simple yet functional application, we can
+focus on providing authentication (with authorization coming next in
+Chapter 6).
+
+This chapter of the tutorial is divided into two main sections: 1) basic,
+cleartext authentication and 2) hash-based authentication.
+
+You can checkout the source code for this example from the catalyst
+subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+
+
+=head1 BASIC AUTHENTICATION
+
+This section explores how to add authentication logic to a Catalyst
+application.
+
+
+=head2 Add Users and Roles to the Database
+
+First, we add both user and role information to the database (we will
+add the role information here although it will not be used until the
+authorization section, Chapter 6).  Create a new SQL script file by opening
+C<myapp02.sql> in your editor and insert:
+
+    --
+    -- Add user and role tables, along with a many-to-many join table
+    --
+    CREATE TABLE user (
+            id            INTEGER PRIMARY KEY,
+            username      TEXT,
+            password      TEXT,
+            email_address TEXT,
+            first_name    TEXT,
+            last_name     TEXT,
+            active        INTEGER
+    );
+    CREATE TABLE role (
+            id   INTEGER PRIMARY KEY,
+            role TEXT
+    );
+    CREATE TABLE user_role (
+            user_id INTEGER,
+            role_id INTEGER,
+            PRIMARY KEY (user_id, role_id)
+    );
+    --
+    -- Load up some initial test data
+    --
+    INSERT INTO user VALUES (1, 'test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
+    INSERT INTO user VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
+    INSERT INTO user VALUES (3, 'test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
+    INSERT INTO role VALUES (1, 'user');
+    INSERT INTO role VALUES (2, 'admin');
+    INSERT INTO user_role VALUES (1, 1);
+    INSERT INTO user_role VALUES (1, 2);
+    INSERT INTO user_role VALUES (2, 1);
+    INSERT INTO user_role VALUES (3, 1);
+
+Then load this into the C<myapp.db> database with the following command:
+
+    $ sqlite3 myapp.db < myapp02.sql
+
+=head2 Add User and Role Information to DBIC Schema
+
+Although we could manually edit the DBIC schema information to include
+the new tables added in the previous step, let's use the C<create=static>
+option on the DBIC model helper to do most of the work for us:
+
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp dbi:SQLite:myapp.db
+     exists "/root/dev/MyApp/script/../lib/MyApp/Model"
+     exists "/root/dev/MyApp/script/../t"
+    Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
+    Schema dump completed.
+     exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
+    $
+    $ ls lib/MyApp/Schema/Result
+    Author.pm  BookAuthor.pm  Book.pm  Role.pm  User.pm  UserRole.pm
+
+Notice how the helper has added three new table-specific result source
+files to the C<lib/MyApp/Schema/Result> directory.  And, more
+importantly, even if there were changes to the existing result source
+files, those changes would have only been written above the C<# DO NOT
+MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited
+enhancements would have been preserved.
+
+Speaking of "hand-editted enhancements," we should now add
+relationship information to the three new result source files.  Edit
+each of these files and add the following information between the C<#
+DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>:
+
+C<lib/MyApp/Schema/Result/User.pm>:
+
+    #
+    # Set relationships:
+    #
+    
+    # has_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *foreign* table (aka, foreign key in peer table)
+    __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRole', 'user_id');
+    
+    # many_to_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of has_many() relationship this many_to_many() is shortcut for
+    #     3) Name of belongs_to() relationship in model class of has_many() above
+    #   You must already have the has_many() defined to use a many_to_many().
+    __PACKAGE__->many_to_many(roles => 'map_user_role', 'role');
+
+
+C<lib/MyApp/Schema/Result/Role.pm>:
+
+    #
+    # Set relationships:
+    #
+    
+    # has_many():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *foreign* table (aka, foreign key in peer table)
+    __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRole', 'role_id');
+
+
+C<lib/MyApp/Schema/Result/UserRole.pm>:
+
+    #
+    # Set relationships:
+    #
+    
+    # belongs_to():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *this* table
+    __PACKAGE__->belongs_to(user => 'MyApp::Schema::Result::User', 'user_id');
+    
+    # belongs_to():
+    #   args:
+    #     1) Name of relationship, DBIC will create accessor with this name
+    #     2) Name of the model class referenced by this relationship
+    #     3) Column name in *this* table
+    __PACKAGE__->belongs_to(role => 'MyApp::Schema::Result::Role', 'role_id');
+
+The code for these three sets of updates is obviously very similar to
+the edits we made to the C<Book>, C<Author>, and C<BookAuthor>
+classes created in Chapter 3.
+
+Note that we do not need to make any change to the
+C<lib/MyApp/Schema.pm> schema file.  It simply tells DBIC to load all
+of the Result Class and ResultSet Class files it finds in below the
+C<lib/MyApp/Schema> directory, so it will automatically pick up our
+new table information.
+
+
+=head2 Sanity-Check Reload of Development Server
+
+We aren't ready to try out the authentication just yet; we only want
+to do a quick check to be sure our model loads correctly.  Press
+C<Ctrl-C> to kill the previous server instance (if it's still running)
+and restart it:
+
+    $ script/myapp_server.pl
+
+Look for the three new model objects in the startup debug output:
+
+    ...
+     .-------------------------------------------------------------------+----------.
+    | Class                                                             | Type     |
+    +-------------------------------------------------------------------+----------+
+    | MyApp::Controller::Books                                          | instance |
+    | MyApp::Controller::Root                                           | instance |
+    | MyApp::Model::DB                                                  | instance |
+    | MyApp::Model::DB::Author                                          | class    |
+    | MyApp::Model::DB::Book                                            | class    |
+    | MyApp::Model::DB::BookAuthor                                      | class    |
+    | MyApp::Model::DB::Role                                            | class    |
+    | MyApp::Model::DB::User                                            | class    |
+    | MyApp::Model::DB::UserRole                                        | class    |
+    | MyApp::View::TT                                                   | instance |
+    '-------------------------------------------------------------------+----------'
+    ...
+
+Again, notice that your "Result Class" classes have been "re-loaded"
+by Catalyst under C<MyApp::Model>.
+
+
+=head2 Include Authentication and Session Plugins
+
+Edit C<lib/MyApp.pm> and update it as follows (everything below
+C<StackTrace> is new):
+
+    # Load plugins
+    use Catalyst qw/-Debug
+                    ConfigLoader
+                    Static::Simple
+    
+                    StackTrace
+    
+                    Authentication
+    
+                    Session
+                    Session::Store::FastMmap
+                    Session::State::Cookie
+                    /;
+
+B<Note:> As discussed in MoreCatalystBasics, different versions of
+C<Catalyst::Devel> have used a variety of methods to load the plugins.
+You can put the plugins in the C<use Catalyst> statement if you prefer.
+
+The C<Authentication> plugin supports Authentication while the
+C<Session> plugins are required to maintain state across multiple HTTP
+requests.
+
+Note that the only required Authentication class is the main one. This
+is a change that occurred in version 0.09999_01 of the
+C<Authentication> plugin. You B<do not need> to specify a particular
+Authentication::Store or Authentication::Credential plugin. Instead,
+indicate the Store and Credential you want to use in your application
+configuration (see below).
+
+Make sure you include the additional plugins as new dependencies in
+the Makefile.PL file something like this:
+
+    requires (
+        'Catalyst::Plugin::Authentication' => '0',
+        'Catalyst::Plugin::Session' => '0',
+        'Catalyst::Plugin::Session::Store::FastMmap' => '0',
+        'Catalyst::Plugin::Session::State::Cookie' => '0',
+    );
+
+Note that there are several options for
+L<Session::Store|Catalyst::Plugin::Session::Store>
+(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap>
+is generally a good choice if you are on Unix; try
+L<Session::Store::File|Catalyst::Plugin::Session::Store::File> if you
+are on Win32) -- consult
+L<Session::Store|Catalyst::Plugin::Session::Store> and its subclasses
+for additional information and options (for example to use a database-
+backed session store).
+
+
+=head2 Configure Authentication
+
+There are a variety of ways to provide configuration information to
+L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>.
+Here we will use 
+L<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
+because it automatically sets a reasonable set of defaults for us. Open 
+C<lib/MyApp.pm> and place the following text above the call to
+C<__PACKAGE__-E<gt>setup();>:
+
+    # Configure SimpleDB Authentication
+    __PACKAGE__->config->{'Plugin::Authentication'} = {
+            default => {
+                class           => 'SimpleDB',
+                user_model      => 'DB::User',
+                password_type   => 'clear',
+            },
+        };
+
+We could have placed this configuration in C<myapp.conf>, but placing 
+it in C<lib/MyApp.pm> is probably a better place since it's not likely 
+something that users of your application will want to change during 
+deployment (or you could use a mixture: leave C<class> and 
+C<user_model> defined in C<lib/MyApp.pm> as we show above, but place 
+C<password_type> in C<myapp.conf> to allow the type of password to be 
+easily modified during deployment).  We will stick with putting 
+all of the authentication-related configuration in C<lib/MyApp.pm> 
+for the tutorial, but if you wish to use C<myapp.conf>, just convert
+to the following code:
+
+    <Plugin::Authentication>
+        use_session 1
+        <default>
+            password_type self_check
+            user_model    DB::User
+            class         SimpleDB
+        </default>
+    </Plugin::Authentication>
+
+B<TIP:> Here is a short script that will dump the contents of 
+C<MyApp->config> to L<Config::General|Config::General> format in
+C<myapp.conf>:
+
+    $ perl -Ilib -e 'use MyApp; use Config::General; 
+        Config::General->new->save_file("myapp.conf", MyApp->config);'
+
+B<NOTE:> Because we are using SimpleDB along with a database layout 
+that complies with its default assumptions, we don't need to specify
+the names of the columns where our username and password information
+is stored (hence, the "Simple" part of "SimpleDB").  That being said,
+SimpleDB lets you specify that type of information if you need to.
+Take a look at 
+C<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
+for details.
+
+
+=head2 Add Login and Logout Controllers
+
+Use the Catalyst create script to create two stub controller files:
+
+    $ script/myapp_create.pl controller Login
+    $ script/myapp_create.pl controller Logout
+
+You could easily use a single controller here.  For example, you could
+have a C<User> controller with both C<login> and C<logout> actions.
+Remember, Catalyst is designed to be very flexible, and leaves such
+matters up to you, the designer and programmer.
+
+Then open C<lib/MyApp/Controller/Login.pm>, locate the
+C<sub index :Path :Args(0)> method (or C<sub index : Private> if you
+are using an older version of Catalyst) that was automatically
+inserted by the helpers when we created the Login controller above,
+and update the definition of C<sub index> to match:
+
+    =head2 index
+    
+    Login logic
+    
+    =cut
+    
+    sub index :Path :Args(0) {
+        my ($self, $c) = @_;
+    
+        # Get the username and password from form
+        my $username = $c->request->params->{username} || "";
+        my $password = $c->request->params->{password} || "";
+    
+        # If the username and password values were found in form
+        if ($username && $password) {
+            # Attempt to log the user in
+            if ($c->authenticate({ username => $username,
+                                   password => $password  } )) {
+                # If successful, then let them use the application
+                $c->response->redirect($c->uri_for(
+                    $c->controller('Books')->action_for('list')));
+                return;
+            } else {
+                # Set an error message
+                $c->stash->{error_msg} = "Bad username or password.";
+            }
+        }
+    
+        # If either of above don't work out, send to the login page
+        $c->stash->{template} = 'login.tt2';
+    }
+
+Be sure to remove the C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Login in Login.');>
+line of the C<sub index>.
+
+This controller fetches the C<username> and C<password> values from the
+login form and attempts to authenticate the user.  If successful, it
+redirects the user to the book list page.  If the login fails, the user
+will stay at the login page and receive an error message.  If the
+C<username> and C<password> values are not present in the form, the
+user will be taken to the empty login form.
+
+Note that we could have used something like "C<sub default :Path>",
+however, it is generally recommended (partly for historical reasons,
+and partly for code clarity) only to use C<default> in
+C<MyApp::Controller::Root>, and then mainly to generate the 404 not
+found page for the application.
+
+Instead, we are using "C<sub somename :Path :Args(0) {...}>" here to
+specifically match the URL C</login>. C<Path> actions (aka, "literal
+actions") create URI matches relative to the namespace of the
+controller where they are defined.  Although C<Path> supports
+arguments that allow relative and absolute paths to be defined, here
+we use an empty C<Path> definition to match on just the name of the
+controller itself.  The method name, C<index>, is arbitrary. We make
+the match even more specific with the C<:Args(0)> action modifier --
+this forces the match on I<only> C</login>, not
+C</login/somethingelse>.
+
+Next, update the corresponding method in
+C<lib/MyApp/Controller/Logout.pm> to match:
+
+    =head2 index
+    
+    Logout logic
+    
+    =cut
+    
+    sub index :Path :Args(0) {
+        my ($self, $c) = @_;
+    
+        # Clear the user's state
+        $c->logout;
+    
+        # Send the user to the starting point
+        $c->response->redirect($c->uri_for('/'));
+    }
+
+As with the login controller, be sure to delete the
+C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Logout in Logout.');>
+line of the C<sub index>.
+
+
+=head2 Add a Login Form TT Template Page
+
+Create a login form by opening C<root/src/login.tt2> and inserting:
+
+    [% META title = 'Login' %]
+    
+    <!-- Login form -->
+    <form method="post" action="[% c.uri_for('/login') %]">
+      <table>
+        <tr>
+          <td>Username:</td>
+          <td><input type="text" name="username" size="40" /></td>
+        </tr>
+        <tr>
+          <td>Password:</td>
+          <td><input type="password" name="password" size="40" /></td>
+        </tr>
+        <tr>
+          <td colspan="2"><input type="submit" name="submit" value="Submit" /></td>
+        </tr>
+      </table>
+    </form>
+
+
+=head2 Add Valid User Check
+
+We need something that provides enforcement for the authentication
+mechanism -- a I<global> mechanism that prevents users who have not
+passed authentication from reaching any pages except the login page.
+This is generally done via an C<auto> action/method (prior to Catalyst
+v5.66, this sort of thing would go in C<MyApp.pm>, but starting in
+v5.66, the preferred location is C<lib/MyApp/Controller/Root.pm>).
+
+Edit the existing C<lib/MyApp/Controller/Root.pm> class file and insert
+the following method:
+
+    =head2 auto
+    
+    Check if there is a user and, if not, forward to login page
+    
+    =cut
+    
+    # Note that 'auto' runs after 'begin' but before your actions and that
+    # 'auto's "chain" (all from application path to most specific class are run)
+    # See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
+    sub auto : Private {
+        my ($self, $c) = @_;
+    
+        # Allow unauthenticated users to reach the login page.  This
+        # allows unauthenticated users to reach any action in the Login
+        # controller.  To lock it down to a single action, we could use:
+        #   if ($c->action eq $c->controller('Login')->action_for('index'))
+        # to only allow unauthenticated access to the 'index' action we
+        # added above.
+        if ($c->controller eq $c->controller('Login')) {
+            return 1;
+        }
+    
+        # If a user doesn't exist, force login
+        if (!$c->user_exists) {
+            # Dump a log message to the development server debug output
+            $c->log->debug('***Root::auto User not found, forwarding to /login');
+            # Redirect the user to the login page
+            $c->response->redirect($c->uri_for('/login'));
+            # Return 0 to cancel 'post-auto' processing and prevent use of application
+            return 0;
+        }
+    
+        # User found, so return 1 to continue with processing after this 'auto'
+        return 1;
+    }
+
+As discussed in
+L<Catalyst::Manual::Tutorial::03_MoreCatalystBasics/CREATE A CATALYST CONTROLLER>,
+every C<auto> method from the application/root controller down to the
+most specific controller will be called.  By placing the
+authentication enforcement code inside the C<auto> method of
+C<lib/MyApp/Controller/Root.pm> (or C<lib/MyApp.pm>), it will be
+called for I<every> request that is received by the entire
+application.
+
+
+=head2 Displaying Content Only to Authenticated Users
+
+Let's say you want to provide some information on the login page that
+changes depending on whether the user has authenticated yet.  To do
+this, open C<root/src/login.tt2> in your editor and add the following
+lines to the bottom of the file:
+
+    ...
+    <p>
+    [%
+       # This code illustrates how certain parts of the TT
+       # template will only be shown to users who have logged in
+    %]
+    [% IF c.user_exists %]
+        Please Note: You are already logged in as '[% c.user.username %]'.
+        You can <a href="[% c.uri_for('/logout') %]">logout</a> here.
+    [% ELSE %]
+        You need to log in to use this application.
+    [% END %]
+    [%#
+       Note that this whole block is a comment because the "#" appears
+       immediate after the "[%" (with no spaces in between).  Although it
+       can be a handy way to temporarily "comment out" a whole block of
+       TT code, it's probably a little too subtle for use in "normal"
+       comments.
+    %]
+    </p>
+
+Although most of the code is comments, the middle few lines provide a
+"you are already logged in" reminder if the user returns to the login
+page after they have already authenticated.  For users who have not yet
+authenticated, a "You need to log in..." message is displayed (note the
+use of an IF-THEN-ELSE construct in TT).
+
+
+=head2 Try Out Authentication
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still
+running) and restart it:
+
+    $ script/myapp_server.pl
+
+B<IMPORTANT NOTE:> If you are having issues with authentication on
+Internet Explorer, be sure to check the system clocks on both your
+server and client machines.  Internet Explorer is very picky about
+timestamps for cookies.  You can quickly sync a Debian system by
+installing the "ntpdate" package:
+
+    sudo aptitude -y install ntpdate
+
+And then run the following command:
+
+    sudo ntpdate-debian
+
+Or, depending on your firewall configuration:
+
+    sudo ntpdate-debian -u
+
+Note: NTP can be a little more finicky about firewalls because it uses
+UDP vs. the more common TCP that you see with most Internet protocols.
+Worse case, you might have to manually set the time on your development
+box instead of using NTP.
+
+Now trying going to L<http://localhost:3000/books/list> and you should
+be redirected to the login page, hitting Shift+Reload or Ctrl+Reload
+if necessary (the "You are already logged in" message should I<not>
+appear -- if it does, click the C<logout> button and try again). Note
+the C<***Root::auto User not found...> debug message in the
+development server output.  Enter username C<test01> and password
+C<mypass>, and you should be taken to the Book List page.
+
+Open C<root/src/books/list.tt2> and add the following lines to the
+bottom (below the closing </table> tag):
+
+    <p>
+      <a href="[% c.uri_for('/login') %]">Login</a>
+      <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Create</a>
+    </p>
+
+Reload your browser and you should now see a "Login" and "Create" links
+at the bottom of the page (as mentioned earlier, you can update template
+files without reloading the development server).  Click the first link
+to return to the login page.  This time you I<should> see the "You are
+already logged in" message.
+
+Finally, click the C<You can logout here> link on the C</login> page.
+You should stay at the login page, but the message should change to "You
+need to log in to use this application."
+
+
+=head1 USING PASSWORD HASHES
+
+In this section we increase the security of our system by converting 
+from cleartext passwords to SHA-1 password hashes that include a 
+random "salt" value to make them extremely difficult to crack with
+dictionary and "rainbow table" attacks.
+
+B<Note:> This section is optional.  You can skip it and the rest of the
+tutorial will function normally.
+
+Be aware that even with the techniques shown in this section, the browser
+still transmits the passwords in cleartext to your application.  We are
+just avoiding the I<storage> of cleartext passwords in the database by
+using a salted SHA-1 hash. If you are concerned about cleartext passwords
+between the browser and your application, consider using SSL/TLS, made
+easy with the Catalyst plugin Catalyst::Plugin:RequireSSL.
+
+
+=head2 Install DBIx::Class::EncodedColumn
+
+L<DBIx::Class::EncodedColumn|DBIx::Class::EncodedColumn> provides features
+that can greatly simplify the maintenance of passwords.  It's currently 
+not available as a .deb package in the normal Debian repositories, so let's
+install it directly from CPAN:
+
+    $ sudo cpan DBIx::Class::EncodedColumn
+
+
+=head2 Re-Run the DBIC::Schema Model Helper to Include DBIx::Class::EncodedColumn
+
+Next, we can re-run the model helper to have it include 
+L<DBIx::Class::EncodedColumn|DBIx::Class::EncodedColumn> in all of the 
+Result Classes it generates for us.  Simply use the same command we 
+saw in Chapters 3 and 4, but add C<,EncodedColumn> to the C<components>
+argument:
+
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db
+
+If you then open one of the Result Classes, you will see that it 
+includes EncodedColumn in the C<load_components> line.  Take a look at 
+C<lib/MyApp/Schema/Result/User.pm> since that's the main class where we
+want to use hashed and salted passwords:
+
+    __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn", "Core");
+
+
+=head2 Modify the "password" Column to Use EncodedColumn
+
+Open the file C<lib/MyApp/Schema/Result/User.pm> and enter the following
+text below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!" line but above
+the closing "1;":
+
+    # Have the 'password' column use a SHA-1 hash and 10-character salt
+    # with hex encoding; Generate the 'check_password" method
+    __PACKAGE__->add_columns(
+        'password' => {
+            data_type           => "TEXT",
+            size                => undef,
+            encode_column       => 1,
+            encode_class        => 'Digest',
+            encode_args         => {salt_length => 10},
+            encode_check_method => 'check_password',
+        },
+    );
+
+This redefines the automatically generated definition for the password 
+fields at the top of the Result Class file to now use EncodedColumn 
+logic (C<encoded_column> is set to 1).  C<encode_class> can be set to 
+either C<Digest> to use 
+L<DBIx::Class::EncodedColumn::Digest|DBIx::Class::EncodedColumn::Digest>, 
+or C<Crypt::Eksblowfish::Bcrypt> for 
+L<DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt|DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt>.
+C<encode_args> is then used to customize the type of Digest you 
+selected. Here we only specified the size of the salt to use, but
+we could have also modified the hashing algorithm ('SHA-256' is 
+the default) and the format to use ('base64' is the default, but
+'hex' and 'binary' are other options).  To use these, you could 
+change the C<encode_args> to something like:
+
+            encode_args         => {algorithm => 'SHA-1', 
+                                    format => 'hex', 
+                                    salt_length => 10},
+
+
+=head2 Load Hashed Passwords in the Database
+
+Next, let's create a quick script to load some hashed and salted passwords
+into the C<password> column of our C<users> table.  Open the file
+C<set_hashed_passwords.pl> in your editor and enter the following text:
+
+    #!/usr/bin/perl
+    
+    use strict;
+    use warnings;
+    
+    use MyApp::Schema;
+    
+    my $schema = MyApp::Schema->connect('dbi:SQLite:myapp.db');
+    
+    my @users = $schema->resultset('User')->all;
+    
+    foreach my $user (@users) {
+        $user->password('mypass');
+        $user->update;
+    }
+
+EncodedColumn lets us simple call C<$user->check_password($password)> 
+to see if the user has supplied the correct password, or, as we show 
+above, call C<$user->update($new_password)> to update the hashed 
+password stored for this user.
+
+Then run the following command:
+
+    $ perl -Ilib set_hashed_passwords.pl
+
+We had to use the C<-Ilib> arguement to tell perl to look under the 
+C<lib> directory for our C<MyApp::Schema> model.
+
+Then dump the users table to verify that it worked:
+
+    $ sqlite3 myapp.db "select * from user"
+    1|test01|38d3974fa9e9263099f7bc2574284b2f55473a9bM=fwpX2NR8|t01 at na.com|Joe|Blow|1
+    2|test02|6ed8586587e53e0d7509b1cfed5df08feadc68cbMJlnPyPt0I|t02 at na.com|Jane|Doe|1
+    3|test03|af929a151340c6aed4d54d7e2651795d1ad2e2f7UW8dHoGv9z|t03 at na.com|No|Go|0
+
+As you can see, the passwords are much harder to steal from the 
+database.  Also note that this demonstrates how to use a DBIx::Class 
+model outside of your web application -- a very useful feature in many 
+situations.
+
+
+=head2 Enable Hashed and Salted Passwords
+
+Edit C<lib/MyApp.pm> and update it to match the following text (the only change
+is to the C<password_type> field):
+
+    # Configure SimpleDB Authentication
+    __PACKAGE__->config->{'Plugin::Authentication'} = {
+            default => {
+                class           => 'SimpleDB',
+                user_model      => 'DB::User',
+                password_type   => 'self_check',
+            },
+        };
+
+The use of C<self_check> will cause 
+Catalyst::Plugin::Authentication::Store::DBIC to call the 
+C<check_password> method we enabled on our C<password> columns.
+
+
+=head2 Try Out the Hashed Passwords
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still
+running) and restart it:
+
+    $ script/myapp_server.pl
+
+You should now be able to go to L<http://localhost:3000/books/list> and
+login as before.  When done, click the "logout" link on the login page
+(or point your browser at L<http://localhost:3000/logout>).
+
+
+=head1 USING THE SESSION FOR FLASH
+
+As discussed in the previous chapter of the tutorial, C<flash> allows 
+you to set variables in a way that is very similar to C<stash>, but it 
+will remain set across multiple requests.  Once the value is read, it 
+is cleared (unless reset).  Although C<flash> has nothing to do with 
+authentication, it does leverage the same session plugins.  Now that 
+those plugins are enabled, let's go back and update the "delete and 
+redirect with query parameters" code seen at the end of the L<Basic 
+CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD> chapter of the tutorial to 
+take advantage of C<flash>.
+
+First, open C<lib/MyApp/Controller/Books.pm> and modify C<sub delete>
+to match the following (everything after the model search line of code
+has changed):
+
+    =head2 delete
+    
+    Delete a book
+    
+    =cut
+    
+    sub delete :Chained('object') :PathPart('delete') :Args(0) {
+        my ($self, $c) = @_;
+    
+        # Use the book object saved by 'object' and delete it along
+        # with related 'book_authors' entries
+        $c->stash->{object}->delete;
+    
+        # Use 'flash' to save information across requests until it's read
+        $c->flash->{status_msg} = "Book deleted";
+    
+        # Redirect the user back to the list page
+        $c->response->redirect($c->uri_for($self->action_for('list')));
+    }
+
+Next, open C<root/src/wrapper.tt2> and update the TT code to pull from
+flash vs. the C<status_msg> query parameter:
+
+    ...
+    <div id="content">
+        [%# Status and error messages %]
+        <span class="message">[% status_msg || c.flash.status_msg %]</span>
+        <span class="error">[% error_msg %]</span>
+        [%# This is where TT will stick all of your template's contents. -%]
+        [% content %]
+    </div><!-- end content -->
+    ...
+
+Although the sample above only shows the C<content> div, leave the
+rest of the file intact -- the only change we made to the C<wrapper.tt2>
+was to add "C<|| c.request.params.status_msg>" to the
+C<E<lt>span class="message"E<gt>> line.
+
+
+=head2 Try Out Flash
+
+Restart the development server, log in, and then point your browser to
+L<http://localhost:3000/books/url_create/Test/1/4> to create an extra
+several books.  Click the "Return to list" link and delete one of the
+"Test" books you just added.  The C<flash> mechanism should retain our
+"Book deleted" status message across the redirect.
+
+B<NOTE:> While C<flash> will save information across multiple requests,
+I<it does get cleared the first time it is read>.  In general, this is
+exactly what you want -- the C<flash> message will get displayed on
+the next screen where it's appropriate, but it won't "keep showing up"
+after that first time (unless you reset it).  Please refer to
+L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> for additional
+information.
+
+
+=head2 Switch To Flash-To-Stash
+
+Although the a use of flash above works well, the
+C<status_msg || c.flash.status_msg> statement is a little ugly. A nice
+alternative is to use the C<flash_to_stash> feature that automatically
+copies the content of flash to stash.  This makes your controller
+and template code work regardless of where it was directly access, a
+forward, or a redirect.  To enable C<flash_to_stash>, you can either
+set the value in C<lib/MyApp.pm> by changing the default
+C<__PACKAGE__-E<gt>config> setting to something like:
+
+    __PACKAGE__->config(
+            name    => 'MyApp',
+            session => {flash_to_stash => 1}
+        );
+
+B<or> add the following to C<myapp.conf>:
+
+    <session>
+        flash_to_stash   1
+    </session>
+
+The C<__PACKAGE__-E<gt>config> option is probably preferable here
+since it's not something you will want to change at runtime without it
+possibly breaking some of your code.
+
+Then edit C<root/src/wrapper.tt2> and change the C<status_msg> line
+to match the following:
+
+    <span class="message">[% status_msg %]</span>
+
+Restart the development server and go to
+L<http://localhost:3000/books/list> in your browser.  Delete another
+of the "Test" books you added in the previous step.  Flash should still
+maintain the status message across the redirect even though you are no
+longer explicitly accessing C<c.flash>.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/06_Authorization.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/06_Authorization.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/06_Authorization.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,362 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::06_Authorization - Catalyst Tutorial - Chapter 6: Authorization
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 6 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+B<06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This chapter of the tutorial adds role-based authorization to the 
+existing authentication implemented in Chapter 5.  It provides simple 
+examples of how to use roles in both TT templates and controller 
+actions.  The first half looks at basic authorization concepts. The 
+second half looks at how moving your authorization code to your model 
+can simplify your code and make things easier to maintain.
+
+You can checkout the source code for this example from the catalyst
+subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+
+
+=head1 BASIC AUTHORIZATION
+
+In this section you learn the basics of how authorization works under 
+Catalyst.
+
+
+=head2 Update Plugins to Include Support for Authorization
+
+Edit C<lib/MyApp.pm> and add C<Authorization::Roles> to the list:
+
+    # Load plugins
+    use Catalyst qw/-Debug
+                    ConfigLoader
+                    Static::Simple
+                
+                    StackTrace
+                
+                    Authentication
+                    Authorization::Roles
+        
+                    Session
+                    Session::Store::FastMmap
+                    Session::State::Cookie
+                    /;
+
+B<Note:> As discussed in MoreCatalystBasics, different versions of 
+C<Catalyst::Devel> have used a variety of methods to load the plugins. 
+You can put the plugins in the C<use Catalyst> statement if you 
+prefer.
+
+Once again (remain sharp, by now you should be getting the hang of things)
+include this additional plugin as a new dependency in the Makefile.PL file
+like this:
+
+    requires (
+        ...
+        'Catalyst::Plugin::Authorization::Roles' => '0',
+    );
+
+=head2 Add Role-Specific Logic to the "Book List" Template
+
+Open C<root/src/books/list.tt2> in your editor and add the following
+lines to the bottom of the file:
+
+    ...
+    <p>Hello [% c.user.username %], you have the following roles:</p>
+    
+    <ul>
+      [% # Dump list of roles -%]
+      [% FOR role = c.user.role %]<li>[% role %]</li>[% END %]
+    </ul>
+    
+    <p>
+    [% # Add some simple role-specific logic to template %]
+    [% # Use $c->check_user_roles() to check authz -%]
+    [% IF c.check_user_roles('user') %]
+      [% # Give normal users a link for 'logout' %]
+      <a href="[% c.uri_for('/logout') %]">User Logout</a>
+    [% END %]
+    
+    [% # Can also use $c->user->check_roles() to check authz -%]
+    [% IF c.check_user_roles('admin') %]
+      [% # Give admin users a link for 'create' %]
+      <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Admin Create</a>
+    [% END %]
+    </p>
+
+This code displays a different combination of links depending on the
+roles assigned to the user.
+
+
+=head2 Limit Books::add to 'admin' Users
+
+C<IF> statements in TT templates simply control the output that is sent
+to the user's browser; it provides no real enforcement (if users know or
+guess the appropriate URLs, they are still perfectly free to hit any
+action within your application).  We need to enhance the controller
+logic to wrap restricted actions with role-validation logic.
+
+For example, we might want to restrict the "formless create" action to
+admin-level users by editing C<lib/MyApp/Controller/Books.pm> and
+updating C<url_create> to match the following code:
+
+    =head2 url_create
+    
+    Create a book with the supplied title and rating,
+    with manual authorization
+    
+    =cut
+    
+    sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
+        # In addition to self & context, get the title, rating & author_id args
+        # from the URL.  Note that Catalyst automatically puts extra information
+        # after the "/<controller_name>/<action_name/" into @_
+        my ($self, $c, $title, $rating, $author_id) = @_;
+    
+        # Check the user's roles
+        if ($c->check_user_roles('admin')) {
+            # Call create() on the book model object. Pass the table
+            # columns/field values we want to set as hash values
+            my $book = $c->model('DB::Book')->create({
+                    title   => $title,
+                    rating  => $rating
+                });
+    
+            # Add a record to the join table for this book, mapping to
+            # appropriate author
+            $book->add_to_book_author({author_id => $author_id});
+            # Note: Above is a shortcut for this:
+            # $book->create_related('book_author', {author_id => $author_id});
+    
+            # Assign the Book object to the stash for display in the view
+            $c->stash->{book} = $book;
+    
+            # Set the TT template to use
+            $c->stash->{template} = 'books/create_done.tt2';
+        } else {
+            # Provide very simple feedback to the user.
+            $c->response->body('Unauthorized!');
+        }
+    }
+
+
+To add authorization, we simply wrap the main code of this method in an
+C<if> statement that calls C<check_user_roles>.  If the user does not
+have the appropriate permissions, they receive an "Unauthorized!"
+message.  Note that we intentionally chose to display the message this
+way to demonstrate that TT templates will not be used if the response
+body has already been set.  In reality you would probably want to use a
+technique that maintains the visual continuity of your template layout
+(for example, using the "status" or "error" message feature added in
+Chapter 3 or C<detach> to an action that shows an "unauthorized" page).
+
+B<TIP>: If you want to keep your existing C<url_create> method, you can
+create a new copy and comment out the original by making it look like a
+Pod comment.  For example, put something like C<=begin> before 
+C<sub add : Local {> and C<=end> after the closing C<}>.
+
+
+=head2 Try Out Authentication And Authorization
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still
+running) and restart it:
+
+    $ script/myapp_server.pl
+
+Now trying going to L<http://localhost:3000/books/list> and you should 
+be taken to the login page (you might have to C<Shift+Reload> or 
+C<Ctrl+Reload> your browser and/or click the "User Logout" link on the book 
+list page).  Try logging in with both C<test01> and C<test02> (both 
+use a password of C<mypass>) and notice how the roles information 
+updates at the bottom of the "Book List" page. Also try the "User Logout"
+link on the book list page.
+
+Now the "url_create" URL will work if you are already logged in as user
+C<test01>, but receive an authorization failure if you are logged in as
+C<test02>.  Try:
+
+    http://localhost:3000/books/url_create/test/1/6
+
+while logged in as each user.  Use one of the "logout" links (or go to 
+L<http://localhost:3000/logout> in your browser directly) when you are 
+done.
+
+
+=head1 ENABLE MODEL-BASED AUTHORIZATION
+
+Hopefully it's fairly obvious that adding detailed permission checking 
+logic to our controllers and view templates isn't a very clean or 
+scalable way to build role-based permissions into out application.  As 
+with many other aspects of MVC web development, the goal is to have 
+your controllers and views be an "thin" as possible, with all of the 
+"fancy business logic" built into your model.
+
+For example, let's add a method to our C<Books.pm> Result Class to 
+check if a user is allowed to delete a book.  Open 
+C<lib/MyApp/Schema/Result/Book.pm> and add the following method 
+(be sure to add it below the "C<DO NOT MODIFY ...>" line):
+
+    =head2 delete_allowed_by
+    
+    Can the specified user delete the current book?
+    
+    =cut
+    
+    sub delete_allowed_by {
+        my ($self, $user) = @_;
+        
+        # Only allow delete if user has 'admin' role
+        return $user->has_role('admin');
+    }
+
+Here we call a C<has_role> method on our user object, so we should add 
+this method to our Result Class.  Open 
+C<lib/MyApp/Schema/Result/User.pm> and add the following method below 
+the "C<DO NOT MODIFY ...>" line:
+
+    =head 2 has_role
+    
+    Check if a user has the specified role
+    
+    =cut
+    
+    use Perl6::Junction qw/any/;
+    sub has_role {
+        my ($self, $role) = @_;
+    
+        # Does this user posses the required role?
+        return any(map { $_->role } $self->roles) eq $role;
+    }
+
+Now we need to add some enforcement inside our controller.  Open
+C<lib/MyApp/Controller/Books.pm> and update the C<delete> method to
+match the following code:
+
+    =head2 delete
+    
+    Delete a book
+    
+    =cut
+    
+    sub delete :Chained('object') :PathPart('delete') :Args(0) {
+        my ($self, $c) = @_;
+    
+        # Check permissions
+        $c->detach('/error_noperms')
+            unless $c->stash->{object}->delete_allowed_by($c->user->get_object);
+    
+        # Use the book object saved by 'object' and delete it along
+        # with related 'book_authors' entries
+        $c->stash->{object}->delete;
+    
+        # Use 'flash' to save information across requests until it's read
+        $c->flash->{status_msg} = "Book deleted";
+    
+        # Redirect the user back to the list page
+        $c->response->redirect($c->uri_for($self->action_for('list')));
+    }    
+
+Here, we C<detach> to an error page if the user is lacking the 
+appropriate permissions.  For this to work, we need to make 
+arrangements for the '/error_noperms' action to work.  Open 
+C<lib/MyApp/Controller/Root.pm> and add this method:
+
+    =head2 error_noperms
+    
+    Permissions error screen
+    
+    =cut
+        
+    sub error_noperms :Chained('/') :PathPath('error_noperms') :Args(0) {
+        my ($self, $c) = @_;
+    
+        $c->stash->{template} = 'error_noperms.tt2';
+    }
+
+And also add the template file by putting the following text into
+C<root/src/error_noperms.tt2>:
+
+    <span class="error">Permission Denied</span>
+
+Then run the Catalyst development server script:
+
+    $ script/myapp_server.pl
+
+Log in as C<test01> and create several new books using the C<url_create>
+feature:
+
+    http://localhost:3000/books/url_create/Test/1/4
+
+Then, while still logged in as C<test01>, click the "Delete" link next 
+to one of these books.  The book should be removed and you should see 
+the usual green "Book deleted" message.  Next, click the "User Logout" 
+link and log back in as C<test02>.  Now try deleting one of the books. 
+You should be taken to the red "Permission Denied" message on our 
+error page.
+
+Use one of the 'Logout' links (or go to the
+L<http://localhost:3000/logout> URL directly) when you are done.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).
+

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/07_Debugging.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/07_Debugging.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/07_Debugging.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,380 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::07_Debugging - Catalyst Tutorial - Chapter 7: Debugging
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 7 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+B<07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This chapter of the tutorial takes a brief look at the primary options 
+available for troubleshooting Catalyst applications.
+
+Note that when it comes to debugging and troubleshooting, there are two
+camps:
+
+=over 4
+
+=item * 
+
+Fans of C<log> and C<print> statements embedded in the code.
+
+=item * 
+
+Fans of interactive debuggers.
+
+=back
+
+Catalyst is able to easily accommodate both styles of debugging.
+
+
+=head1 LOG STATEMENTS
+
+Folks in the former group can use Catalyst's C<$c-E<gt>log> facility. 
+(See L<Catalyst::Log|Catalyst::Log> for more detail.) For example, if 
+you add the following code to a controller action method:
+
+    $c->log->info("Starting the foreach loop here");
+
+    $c->log->debug("Value of \$id is: ".$id);
+
+Then the Catalyst development server will display your message along
+with the other debug output. To accomplish the same thing in a TT
+template view use:
+
+    [% c.log.debug("This is a test log message") %]
+
+As with many other logging facilities, you a method is defined for
+each of the following "logging levels" (in increasing order of
+severity/importance):
+
+    $c->log->debug
+    $c->log->info
+    $c->log->warn
+    $c->log->error
+    $c->log->fatal
+
+You can also use L<Data::Dumper|Data::Dumper> in both Catalyst code 
+(C<use Data::Dumper; $c-E<gt>log-E<gt>debug("\$var is: ".Dumper($var));)>) 
+and TT templates (C<[% Dumper.dump(book) %]>.
+
+
+=head1 RUNNING CATALYST UNDER THE PERL DEBUGGER
+
+Members of the interactive-debugger fan club will also be at home with
+Catalyst applications.  One approach to this style of Perl debugging is
+to embed breakpoints in your code.  For example, open
+C<lib/MyApp/Controller/Books.pm> in your editor and add the
+C<DB::single=1> line as follows inside the C<list> method (I like to
+"left-justify" my debug statements so I don't forget to remove them, but
+you can obviously indent them if you prefer):
+
+    sub list : Local {
+        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
+        # 'Context' that's used to 'glue together' the various components
+        # that make up the application
+        my ($self, $c) = @_;
+    
+    $DB::single=1;
+            
+        # Retrieve all of the book records as book model objects and store in the
+        # stash where they can be accessed by the TT template
+        $c->stash->{books} = [$c->model('DB::Book')->all];
+            
+        # Set the TT template to use.  You will almost always want to do this
+        # in your action methods.
+        $c->stash->{template} = 'books/list.tt2';
+    }
+
+This causes the Perl Debugger to enter "single step mode" when this command is 
+encountered (it has no effect when Perl is run without the C<-d> flag).
+
+B<NOTE:> The C<DB> here is the Perl Debugger, not the DB model.
+
+If you haven't done it already, enable SQL logging as before:
+
+    $ export DBIC_TRACE=1
+
+To now run the Catalyst development server under the Perl debugger, simply 
+prepend C<perl -d> to the front of C<script/myapp_server.pl>:
+
+    $ perl -d script/myapp_server.pl
+
+This will start the interactive debugger and produce output similar to:
+
+    $ perl -d script/myapp_server.pl  
+    
+    Loading DB routines from perl5db.pl version 1.3
+    Editor support available.
+    
+    Enter h or `h h' for help, or `man perldebug' for more help.
+    
+    main::(script/myapp_server.pl:16):      my $debug         = 0;
+    
+      DB<1> 
+
+Press the C<c> key and hit C<Enter> to continue executing the Catalyst
+development server under the debugger.  Although execution speed will be
+slightly slower than normal, you should soon see the usual Catalyst
+startup debug information.
+
+Now point your browser to L<http://localhost:3000/books/list> and log
+in.  Once the breakpoint is encountered in the
+C<MyApp::Controller::list> method, the console session running the
+development server will drop to the Perl debugger prompt:
+
+    MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:48):
+    48:         $c->stash->{books} = [$c->model('DB::Book')->all];
+    
+      DB<1>
+
+You now have the full Perl debugger at your disposal.  First use the
+C<next> feature by typing C<n> to execute the C<all> method on the Book
+model (C<n> jumps over method/subroutine calls; you can also use C<s> to
+C<single-step> into methods/subroutines):
+
+      DB<1> n
+    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
+    MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:53):
+    53:         $c->stash->{template} = 'books/list.tt2';
+    
+      DB<1>
+
+This takes you to the next line of code where the template name is set.
+Notice that because we enabled C<DBIC_TRACE=1> earlier, SQL debug 
+output also shows up in the development server debug information.
+
+Next, list the methods available on our C<Book> model:
+
+      DB<1> m $c->model('DB::Book')
+    ()
+    (0+
+    (bool
+    __result_class_accessor
+    __source_handle_accessor
+    _add_alias
+    __bool
+    _build_unique_query
+    _calculate_score
+    _collapse_cond
+    <lines removed for brevity>
+    
+      DB<2>
+
+We can also play with the model directly:
+
+      DB<2> x ($c->model('DB::Book')->all)[1]->title
+    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
+    0  'TCP/IP Illustrated, Volume 1'
+
+This uses the Perl debugger C<x> command to display the title of a book.
+
+Next we inspect the C<books> element of the Catalyst C<stash> (the C<4>
+argument to the C<x> command limits the depth of the dump to 4 levels):
+
+      DB<3> x 4 $c->stash->{books}
+    0  ARRAY(0xa8f3b7c)
+       0  MyApp::Model::DB::Book=HASH(0xb8e702c)
+          '_column_data' => HASH(0xb8e5e2c)
+             'created' => '2009-05-08 10:19:46'
+             'id' => 1
+             'rating' => 5
+             'title' => 'CCSP SNRS Exam Certification Guide'
+             'updated' => '2009-05-08 10:19:46'
+          '_in_storage' => 1
+    <lines removed for brevity>
+
+Then enter the C<c> command to continue processing until the next
+breakpoint is hit (or the application exits):
+
+      DB<4> c
+    SELECT author.id, author.first_name, author.last_name FROM ...
+
+Finally, press C<Ctrl+C> to break out of the development server.
+Because we are running inside the Perl debugger, you will drop to the
+debugger prompt.  
+
+    ^CCatalyst::Engine::HTTP::run(/usr/local/share/perl/5.10.0/Catalyst/Engine/HTTP.pm:260):
+    260:            while ( accept( Remote, $daemon ) ) {
+
+    DB<4>
+
+Finally, press C<q> to exit the debugger and return to your OS
+shell prompt:
+
+      DB<4> q
+    $
+
+For more information on using the Perl debugger, please see C<perldebug>
+and C<perldebtut>.  For those daring souls out there, you can dive down
+even deeper into the magical depths of this fine debugger by checking
+out C<perldebguts>.
+
+You can also type C<h> or C<h h> at the debugger prompt to view the
+built-in help screens.
+
+For an excellent book covering all aspects of the Perl debugger, we highly
+recommend reading 'Pro Perl Debugging' by Richard Foley.
+
+Oh yeah, before you forget, be sure to remove the C<DB::single=1> line you
+added above in C<lib/MyApp/Controller/Books.pm>.
+
+=head1 DEBUGGING MODULES FROM CPAN
+
+Although the techniques discussed above work well for code you are 
+writing, what if you want to use print/log/warn messages or set 
+breakpoints in code that you have installed from CPAN (or in module that 
+ship with Perl)?  One helpful approach is to place a copy of the module 
+inside the C<lib> directory of your Catalyst project.  When Catalyst 
+loads, it will load from inside your C<lib> directory first, only 
+turning to the global modules if a local copy cannot be found.  You can 
+then make modifications such as adding a C<$DB::single=1> to the local 
+copy of the module without risking the copy in the original location. 
+This can also be a great way to "locally override" bugs in modules while 
+you wait for a fix on CPAN.
+
+
+Matt Trout has suggested the following shortcut to create a local
+copy of an installed module:
+
+    mkdir -p lib/Module; cp `perldoc -l Module::Name` lib/Module/
+
+Note: If you are following along in Debian 5 or Ubuntu, you will
+need to install the C<perl-doc> package to use the C<perldoc> command.  
+Use C<sudo aptitude install perl-doc> to do that.
+
+For example, you could make a copy of 
+L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
+with the following command:
+
+    mkdir -p lib/Catalyst/Plugin; cp \
+        `perldoc -l Catalyst::Plugin::Authentication` lib/Catalyst/Plugin
+
+You can then use the local copy inside your project to place logging
+messages and/or breakpoints for further study of that module.
+
+B<Note:> Matt has also suggested the following tips for Perl 
+debugging:
+
+=over 4
+
+=item * 
+
+Check the version of an installed module:
+
+    perl -ME<lt>mod_nameE<gt> -e '"print $E<lt>mod_nameE<gt>::VERSION\n"'
+
+For example:
+
+    $ perl -MCatalyst::Plugin::Authentication -e \
+        'print $Catalyst::Plugin::Authentication::VERSION;'
+    0.07
+
+and if you are using bash aliases:
+
+    alias pmver="perl -le '\$m = shift; eval qq(require \$m) \
+        or die qq(module \"\$m\" is not installed\\n); \
+        print \$m->VERSION'"
+
+=item * 
+
+Check if a modules contains a given method:
+
+    perl -MModule::Name -e 'print Module::Name->can("method");'
+
+For example:
+
+    $ perl -MCatalyst::Plugin::Authentication -e \
+        'print Catalyst::Plugin::Authentication->can("user");'
+    CODE(0x9c8db2c)
+
+If the method exists, the Perl C<can> method returns a coderef.
+Otherwise, it returns undef and nothing will be printed.
+
+=back
+
+
+=head1 TT DEBUGGING
+
+If you run into issues during the rendering of your template, it might 
+be helpful to enable TT C<DEBUG> options.  You can do this in a Catalyst 
+environment by adding a C<DEBUG> line to the C<__PACKAGE__->config> 
+declaration in C<lib/MyApp/View/TT.pm>:
+
+    __PACKAGE__->config({
+        TEMPLATE_EXTENSION => '.tt2',
+        DEBUG              => 'undef',
+    });
+
+There are a variety of options you can use, such as 'undef', 'all', 
+'service', 'context', 'parser' and 'provider'.  See 
+L<Template::Constants|Template::Constants> for more information 
+(remove the C<DEBUG_> portion of the name shown in the TT docs and 
+convert to lower case for use inside Catalyst).
+
+B<NOTE:> B<Please be sure to disable TT debug options before continuing 
+with the tutorial> (especially the 'undef' option -- leaving this 
+enabled will conflict with several of the conventions used by this 
+tutorial to leave some variables undefined on purpose).
+
+Happy debugging.
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/08_Testing.pod (from rev 10275, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/08_Testing.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/08_Testing.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,406 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::08_Testing - Catalyst Tutorial - Chapter 8: Testing
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 8 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+B<08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+You may have noticed that the Catalyst Helper scripts automatically 
+create basic C<.t> test scripts under the C<t> directory.  This 
+chapter of the tutorial briefly looks at how these tests can be used 
+not only to ensure that your application is working correctly at the 
+present time, but also provide automated regression testing as you 
+upgrade various pieces of your application over time.
+
+You can check out the source code for this example from the Catalyst
+Subversion repository as per the instructions in
+L<Catalyst::Manual::Tutorial::01_Intro|Catalyst::Manual::Tutorial::01_Intro>.
+
+For an excellent introduction to learning the many benefits of testing
+your Perl applications and modules, you might want to read 'Perl Testing: 
+A Developer's Notebook' by Ian Langworth and chromatic.
+
+
+=head1 RUNNING THE "CANNED" CATALYST TESTS
+
+There are a variety of ways to run Catalyst and Perl tests (for example,
+C<perl Makefile.PL> and C<make test>), but one of the easiest is with the
+C<prove> command.  For example, to run all of the tests in the C<t>
+directory, enter:
+
+    $ prove --lib lib t
+
+There will be a lot of output because we have the C<-Debug> flag 
+enabled in C<lib/MyApp.pm> (see the C<CATALYST_DEBUG=0> tip below for 
+a quick and easy way to reduce the clutter).  Look for lines like this 
+for errors:
+
+    #   Failed test 'Request should succeed'
+    #   at t/controller_Books.t line 8.
+    # Looks like you failed 1 test of 3.
+
+The redirection used by the Authentication plugins will cause several 
+failures in the default tests.  You can fix this by making the following
+changes:
+
+1) Change the line in C<t/01app.t> that reads:
+
+    ok( request('/')->is_success, 'Request should succeed' );
+
+to:
+
+    ok( request('/login')->is_success, 'Request should succeed' );
+
+2) Change the line in C<t/controller_Logout.t> that reads:
+
+    ok( request('/logout')->is_success, 'Request should succeed' );
+
+to:
+
+    ok( request('/logout')->is_redirect, 'Request should succeed' );
+
+3) Change the line in C<t/controller_Books.t> that reads:
+
+    ok( request('/books')->is_success, 'Request should succeed' );
+
+to:
+
+    ok( request('/books')->is_redirect, 'Request should succeed' );
+
+4) Add the following statement to the top of C<t/view_TT.t>:
+
+    use MyApp;
+
+As you can see in the C<prove> command line above, the C<--lib> option
+is used to set the location of the Catalyst C<lib> directory.  With this
+command, you will get all of the usual development server debug output,
+something most people prefer to disable while running tests cases.
+Although you can edit the C<lib/MyApp.pm> to comment out the C<-Debug>
+plugin, it's generally easier to simply set the C<CATALYST_DEBUG=0>
+environment variable.  For example:
+
+    $ CATALYST_DEBUG=0 prove --lib lib t
+
+B<Note:> Depending on the versions of various modules you have 
+installed, you might get some C<used only once> warnings -- you can 
+ignore these.  If you want to eliminate the warnings, you can 
+edit C<Template::Base> to disable and then re-enable warnings
+are the C</usr/lib/perl5/Template/Base.pm> line in C<sub new>.
+You can locate where C<Template::Base> is located with the 
+following command (it's probably in a place similar to
+C</usr/lib/perl5/Template/Base.pm>):
+
+    perldoc -l Template::Base
+
+Edit the file and modify C<sub new> to match:
+
+    ...
+    {   no strict qw( refs );
+        # Disable warnings
+        no warnings;
+        $argnames = \@{"$class\::BASEARGS"} || [ ];
+        # Turn warnings back on
+        use warnings;
+    }
+    ...
+
+During the C<t/02pod> and C<t/03podcoverage> tests, you might notice the
+C<all skipped: set TEST_POD to enable this test> warning message.  To
+execute the Pod-related tests, add C<TEST_POD=1> to the C<prove>
+command:
+
+    $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib t
+
+If you omitted the Pod comments from any of the methods that were
+inserted, you might have to go back and fix them to get these tests to
+pass. :-)
+
+Another useful option is the C<verbose> (C<-v>) option to C<prove>.  It
+prints the name of each test case as it is being run:
+
+    $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib -v t
+
+
+=head1 RUNNING A SINGLE TEST
+
+You can also run a single script by appending its name to the C<prove>
+command. For example:
+
+    $ CATALYST_DEBUG=0 prove --lib lib t/01app.t
+
+Also note that you can also run tests directly from Perl without C<prove>.
+For example:
+
+    $ CATALYST_DEBUG=0 perl -Ilib t/01app.t
+
+
+=head1 ADDING YOUR OWN TEST SCRIPT
+
+Although the Catalyst helper scripts provide a basic level of checks
+"for free," testing can become significantly more helpful when you write
+your own script to exercise the various parts of your application.  The
+L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst> module 
+is very popular for writing these sorts of test cases.  This module 
+extends L<Test::WWW::Mechanize|Test::WWW::Mechanize> (and therefore 
+L<WWW::Mechanize|WWW::Mechanize>) to allow you to automate the action of
+a user "clicking around" inside your application.  It gives you all the
+benefits of testing on a live system without the messiness of having to
+use an actual web server, and a real person to do the clicking.
+
+To create a sample test case, open the C<t/live_app01.t> file in your
+editor and enter the following:
+
+    #!/usr/bin/perl
+    
+    use strict;
+    use warnings;
+    
+    # Load testing framework and use 'no_plan' to dynamically pick up
+    # all tests. Better to replace "'no_plan'" with "tests => 30" so it
+    # knows exactly how many tests need to be run (and will tell you if
+    # not), but 'no_plan' is nice for quick & dirty tests
+    
+    use Test::More 'no_plan';
+    
+    # Need to specify the name of your app as arg on next line
+    # Can also do:
+    #   use Test::WWW::Mechanize::Catalyst "MyApp";
+    
+    use ok "Test::WWW::Mechanize::Catalyst" => "MyApp";
+        
+    # Create two 'user agents' to simulate two different users ('test01' & 'test02')
+    my $ua1 = Test::WWW::Mechanize::Catalyst->new;
+    my $ua2 = Test::WWW::Mechanize::Catalyst->new;
+    
+    # Use a simplified for loop to do tests that are common to both users
+    # Use get_ok() to make sure we can hit the base URL
+    # Second arg = optional description of test (will be displayed for failed tests)
+    # Note that in test scripts you send everything to 'http://localhost'
+    $_->get_ok("http://localhost/", "Check redirect of base URL") for $ua1, $ua2;
+    # Use title_is() to check the contents of the <title>...</title> tags
+    $_->title_is("Login", "Check for login title") for $ua1, $ua2;
+    # Use content_contains() to match on text in the html body
+    $_->content_contains("You need to log in to use this application",
+        "Check we are NOT logged in") for $ua1, $ua2;
+    
+    # Log in as each user
+    # Specify username and password on the URL
+    $ua1->get_ok("http://localhost/login?username=test01&password=mypass", "Login 'test01'");
+    $ua1->get_ok("http://localhost/login?username=test02&password=mypass", "Login 'test02'");
+    
+    # Go back to the login page and it should show that we are already logged in
+    $_->get_ok("http://localhost/login", "Return to '/login'") for $ua1, $ua2;
+    $_->title_is("Login", "Check for login page") for $ua1, $ua2;
+    $_->content_contains("Please Note: You are already logged in as ",
+        "Check we ARE logged in" ) for $ua1, $ua2;
+    
+    # 'Click' the 'Logout' link (see also 'text_regex' and 'url_regex' options)
+    $_->follow_link_ok({n => 4}, "Logout via first link on page") for $ua1, $ua2;
+    $_->title_is("Login", "Check for login title") for $ua1, $ua2;
+    $_->content_contains("You need to log in to use this application",
+        "Check we are NOT logged in") for $ua1, $ua2;
+    
+    # Log back in
+    $ua1->get_ok("http://localhost/login?username=test01&password=mypass", "Login 'test01'");
+    $ua2->get_ok("http://localhost/login?username=test02&password=mypass", "Login 'test02'");
+    # Should be at the Book List page... do some checks to confirm
+    $_->title_is("Book List", "Check for book list title") for $ua1, $ua2;
+    
+    $ua1->get_ok("http://localhost/books/list", "'test01' book list");
+    $ua1->get_ok("http://localhost/login", "Login Page");
+    $ua1->get_ok("http://localhost/books/list", "'test01' book list");
+    
+    $_->content_contains("Book List", "Check for book list title") for $ua1, $ua2;
+    # Make sure the appropriate logout buttons are displayed
+    $_->content_contains("/logout\">User Logout</a>",
+        "Both users should have a 'User Logout'") for $ua1, $ua2;
+    $ua1->content_contains("/books/form_create\">Create</a>",
+        "Only 'test01' should have a create link");
+    
+    $ua1->get_ok("http://localhost/books/list", "View book list as 'test01'");
+    
+    # User 'test01' should be able to create a book with the "formless create" URL
+    $ua1->get_ok("http://localhost/books/url_create/TestTitle/2/4",
+        "'test01' formless create");
+    $ua1->title_is("Book Created", "Book created title");
+    $ua1->content_contains("Added book 'TestTitle'", "Check title added OK");
+    $ua1->content_contains("by 'Stevens'", "Check author added OK");
+    $ua1->content_contains("with a rating of 2.", "Check rating added");
+    # Try a regular expression to combine the previous 3 checks & account for whitespace
+    $ua1->content_like(qr/Added book 'TestTitle'\s+by 'Stevens'\s+with a rating of 2./, "Regex check");
+    
+    # Make sure the new book shows in the list
+    $ua1->get_ok("http://localhost/books/list", "'test01' book list");
+    $ua1->title_is("Book List", "Check logged in and at book list");
+    $ua1->content_contains("Book List", "Book List page test");
+    $ua1->content_contains("TestTitle", "Look for 'TestTitle'");
+    
+    # Make sure the new book can be deleted
+    # Get all the Delete links on the list page
+    my @delLinks = $ua1->find_all_links(text => 'Delete');
+    # Use the final link to delete the last book
+    $ua1->get_ok($delLinks[$#delLinks]->url, 'Delete last book');
+    # Check that delete worked
+    $ua1->content_contains("Book List", "Book List page test");
+    $ua1->content_contains("Book deleted", "Book was deleted");
+    
+    # User 'test02' should not be able to add a book
+    $ua2->get_ok("http://localhost/books/url_create/TestTitle2/2/5", "'test02' add");
+    $ua2->content_contains("Unauthorized!", "Check 'test02' cannot add");
+
+The C<live_app.t> test cases uses copious comments to explain each step
+of the process.  In addition to the techniques shown here, there are a
+variety of other methods available in 
+L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst> (for 
+example, regex-based matching). Consult the documentation for more
+detail.
+
+B<TIP>: For I<unit tests> vs. the "full application tests" approach used
+by L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst>, see 
+L<Catalyst::Test|Catalyst::Test>.
+
+B<Note:> The test script does not test the C<form_create> and
+C<form_create_do> actions.  That is left as an exercise for the reader
+(you should be able to complete that logic using the existing code as a
+template).
+
+To run the new test script, use a command such as:
+
+    $ CATALYST_DEBUG=0 prove --lib lib -v t/live_app01.t
+
+or
+
+    $ DBIC_TRACE=0 CATALYST_DEBUG=0 prove --lib lib -v t/live_app01.t
+
+Experiment with the C<DBIC_TRACE>, C<CATALYST_DEBUG> and C<-v> 
+settings.  If you find that there are errors, use the techniques 
+discussed in the "Catalyst Debugging" section (Chapter 7) to isolate 
+and fix any problems.
+
+If you want to run the test case under the Perl interactive debugger,
+try a command such as:
+
+    $ DBIC_TRACE=0 CATALYST_DEBUG=0 perl -d -Ilib t/live_app01.t
+
+Note that although this tutorial uses a single custom test case for
+simplicity, you may wish to break your tests into different files for
+better organization.
+
+B<TIP:> If you have a test case that fails, you will receive an error
+similar to the following:
+
+    #   Failed test 'Check we are NOT logged in'
+    #   in t/live_app01.t at line 31.
+    #     searched: "\x{0a}<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Tran"...
+    #   can't find: "You need to log in to use this application."
+
+Unfortunately, this only shows us the first 50 characters of the HTML
+returned by the request -- not enough to determine where the problem
+lies.  A simple technique that can be used in such situations is to 
+temporarily insert a line similar to the following right after the 
+failed test:
+
+    diag $ua1->content;
+
+This will cause the full HTML returned by the request to be displayed.
+
+Another approach to see the full HTML content at the failure point in 
+a series of tests would be to insert a "C<$DB::single=1;> right above 
+the location of the failure and run the test under the perl debugger 
+(with C<-d>) as shown above.  Then you can use the debugger to explore 
+the state of the application right before or after the failure.
+
+
+=head1 SUPPORTING BOTH PRODUCTION AND TEST DATABASES
+
+You may wish to leverage the techniques discussed in this tutorial to
+maintain both a "production database" for your live application and a
+"testing database" for your test cases.  One advantage to
+L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst> is that
+it runs your full application; however, this can complicate things when
+you want to support multiple databases.  One solution is to allow the
+database specification to be overridden with an environment variable.
+For example, open C<lib/MyApp/Model/DB.pm> in your editor and
+change the C<__PACKAGE__-E<gt>config(...> declaration to resemble:
+
+    my $dsn = $ENV{MYAPP_DSN} ||= 'dbi:SQLite:myapp.db';
+    __PACKAGE__->config(
+        schema_class => 'MyApp::Schema',
+        connect_info => [
+            $dsn,
+        ],
+    );
+
+Then, when you run your test case, you can use commands such as:
+
+    $ cp myapp.db myappTEST.db
+    $ CATALYST_DEBUG=0 MYAPP_DSN="dbi:SQLite:myappTEST.db" prove --lib lib -v t/live_app01.t
+
+This will modify the DSN only while the test case is running.  If you
+launch your normal application without the C<MYAPP_DSN> environment
+variable defined, it will default to the same C<dbi:SQLite:myapp.db> as
+before.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).
+

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD (from rev 10274, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD)

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormBuilder.pod (from rev 10274, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormBuilder.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormBuilder.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormBuilder.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,60 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormBuilder - Catalyst Tutorial - Chapter 9: Advanced CRUD - FormBuilder
+
+NOTE:  This chapter of the tutorial is in progress.  Feel free to 
+volunteer to help out. :-)
+
+=head1 OVERVIEW
+
+This is B<Chapter 9 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+B<09_Advanced CRUD::09_FormBuilder>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod (from rev 10274, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/09_FormFu.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,675 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormFu - Catalyst Tutorial - Chapter 9: Advanced CRUD - FormFu
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 9 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+B<09_Advanced CRUD::09_FormFu>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This portion of the tutorial explores L<HTML::FormFu|HTML::FormFu> and 
+how it can be used to manage forms, perform validation of form input, 
+as well as save and restore data to/from the database.  This was written
+using HTML::FormFu version 0.03007.
+
+See 
+L<Catalyst::Manual::Tutorial::09_AdvancedCRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+for additional form management options other than 
+L<HTML::FormFu|HTML::FormFu>.
+
+
+=head1 Install HTML::FormFu
+
+If you are following along in Debian 5, it turns out that some of the 
+modules we need are not yet available as Debian packages at the time 
+this was written.  To install it with a combination of Debian packages 
+and traditional CPAN modules, first use C<aptitude> to install most of 
+the modules:
+
+we need to install the
+L<HTML::FormFu|HTML::FormFu> package: 
+
+    sudo aptitude -y install libhtml-formfu-perl libmoose-perl \
+        libregexp-assemble-perl libhtml-formfu-model-dbic-perl
+        
+    ...
+    
+    sudo aptitude clean
+
+Then use the following command to install directly from CPAN the modules 
+that aren't available as Debian packages:
+
+    sudo cpan Catalyst::Component::InstancePerContext Catalyst::Controller::HTML::FormFu
+
+
+=head1 HTML::FormFu FORM CREATION
+
+This section looks at how L<HTML::FormFu|HTML::FormFu> can be used to 
+add additional functionality to the manually created form from Chapter 4.
+
+
+=head2 Inherit From Catalyst::Controller::HTML::FormFu
+
+First, change your C<lib/MyApp/Controller/Books.pm> to inherit from
+L<Catalyst::Controller::HTML::FormFu|Catalyst::Controller::HTML::FormFu>
+by changing the C<use parent> line from the default of:
+
+    use parent 'Catalyst::Controller';
+
+to use the FormFu base controller class:
+
+    use parent 'Catalyst::Controller::HTML::FormFu';
+
+
+=head2 Add Action to Display and Save the Form
+
+Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
+following method:
+
+    =head2 formfu_create
+    
+    Use HTML::FormFu to create a new book
+    
+    =cut
+    
+    sub formfu_create :Chained('base') :PathPart('formfu_create') :Args(0) :FormConfig {
+        my ($self, $c) = @_;
+    
+        # Get the form that the :FormConfig attribute saved in the stash
+        my $form = $c->stash->{form};
+  
+        # Check if the form has been submitted (vs. displaying the initial
+        # form) and if the data passed validation.  "submitted_and_valid"
+        # is shorthand for "$form->submitted && !$form->has_errors"
+        if ($form->submitted_and_valid) {
+            # Create a new book
+            my $book = $c->model('DB::Book')->new_result({});
+            # Save the form data for the book
+            $form->model->update($book);
+            # Set a status message for the user
+            $c->flash->{status_msg} = 'Book created';
+            # Return to the books list
+            $c->response->redirect($c->uri_for($self->action_for('list'))); 
+            $c->detach;
+        } else {
+            # Get the authors from the DB
+            my @author_objs = $c->model("DB::Author")->all();
+            # Create an array of arrayrefs where each arrayref is an author
+            my @authors;
+            foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
+                push(@authors, [$_->id, $_->last_name]);
+            }
+            # Get the select added by the config file
+            my $select = $form->get_element({type => 'Select'});
+            # Add the authors to it
+            $select->options(\@authors);
+        }
+        
+        # Set the template
+        $c->stash->{template} = 'books/formfu_create.tt2';
+    }
+
+
+=head2 Create a Form Config File
+
+Although C<HTML::FormFu> supports any configuration file handled by
+L<Config::Any|Config::Any>, most people tend to use YAML.  First
+create a directory to hold your form configuration files:
+
+    mkdir -p root/forms/books
+
+Then create the file C<root/forms/books/formfu_create.yml> and enter the 
+following text:
+
+    ---
+    # indicator is the field that is used to test for form submission
+    indicator: submit
+    # Start listing the form elements
+    elements:
+        # The first element will be a text field for the title
+        - type: Text
+          name: title
+          label: Title
+          # This is an optional 'mouse over' title pop-up
+          attributes:
+            title: Enter a book title here
+    
+        # Another text field for the numeric rating
+        - type: Text
+          name: rating
+          label: Rating
+          attributes:
+            title: Enter a rating between 1 and 5 here
+    
+        # Add a drop-down list for the author selection.  Note that we will
+        # dynamically fill in all the authors from the controller but we
+        # could manually set items in the drop-list by adding this YAML code:
+        # options:
+        #   - [ '1', 'Bastien' ]
+        #   - [ '2', 'Nasseh'  ]
+        - type: Select
+          name: authors
+          label: Author
+    
+        # The submit button
+        - type: Submit
+          name: submit
+          value: Submit
+
+B<NOTE:> Copying and pasting YAML from perl documentation is sometimes
+tricky.  See the L<Config::General Config for this tutorial> section of
+this document for a more foolproof config format.
+
+
+=head2 Update the CSS
+
+Edit C<root/static/css/main.css> and add the following lines to the bottom of
+the file:
+
+    ...
+    input {
+        display: block;
+    }
+    select {
+        display: block;
+    }
+    .submit {
+        padding-top: .5em;
+        display: block;
+    }
+
+These changes will display form elements vertically.  Note that the 
+existing definition of the C<.error> class is pulling the color scheme 
+settings from the C<root/lib/config/col> file that was created by the 
+TTSite helper.  This allows control over the CSS color settings from a 
+single location.
+
+
+=head2 Create a Template Page To Display The Form
+
+Open C<root/src/books/formfu_create.tt2> in your editor and enter the following:
+
+    [% META title = 'Create/Update Book' %]
+    
+    [%# Render the HTML::FormFu Form %]
+    [% form %]
+    
+    <p><a href="[% c.uri_for(c.controller.action_for('list')) %]">Return to book list</a></p>
+
+
+=head2 Add Links for Create and Update via C<HTML::FormFu>
+
+Open C<root/src/books/list.tt2> in your editor and add the following to
+the bottom of the existing file:
+
+    ...
+    <p>
+      HTML::FormFu:
+      <a href="[% c.uri_for(c.controller.action_for('formfu_create')) %]">Create</a>
+    </p>
+
+This adds a new link to the bottom of the book list page that we can
+use to easily launch our HTML::FormFu-based form.
+
+
+=head2 Test The HTML::FormFu Create Form
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still
+running) and restart it:
+
+    $ script/myapp_server.pl
+
+Login as C<test01> (password: mypass).  Once at the Book List page,
+click the new HTML::FormFu "Create" link at the bottom to display the
+form.  Fill in the following values:
+
+    Title  = "Internetworking with TCP/IP Vol. II"
+    Rating = "4"
+    Author = "Comer"
+    
+Click the Submit button, and you will be returned to the Book List page
+with a "Book created" status message displayed.
+
+Also note that this implementation allows you to create books with any
+bogus information.  Although we have constrained the authors with the 
+drop-down list (note that this isn't bulletproof because we still have 
+not prevented a user from "hacking" the form to specify other values), 
+there are no restrictions on items such as the length of the title (for 
+example, you can create a one-letter title) and the value of the rating 
+(you can use any number you want, and even non-numeric values with 
+SQLite).  The next section will address this concern.
+
+B<Note:> Depending on the database you are using and how you established
+the columns in your tables, the database could obviously provide various
+levels of "type enforcement" on your data.  The key point being made in
+the previous paragraph is that the I<web application> itself is not
+performing any validation.
+
+
+=head1 HTML::FormFu VALIDATION AND FILTERING
+
+Although the use of L<HTML::FormFu|HTML::FormFu> in the previous section 
+did provide an automated mechanism to build the form, the real power of 
+this module stems from functionality that can automatically validate and 
+filter the user input.  Validation uses constraints to be sure that 
+users input appropriate data (for example, that the email field of a 
+form contains a valid email address).  Filtering can also be used to 
+remove extraneous whitespace from fields or to escape meta-characters in 
+user input.
+
+
+=head2 Add Constraints
+
+Open C<root/forms/books/formfu_create.yml> in your editor and update it 
+to match:
+
+    ---
+    # indicator is the field that is used to test for form submission
+    indicator: submit
+    # Start listing the form elements
+    elements:
+        # The first element will be a text field for the title
+        - type: Text
+          name: title
+          label: Title
+          # This is an optional 'mouse over' title pop-up
+          attributes:
+            title: Enter a book title here
+          # Add constraints for the field
+          constraints:
+            # Force the length to be between 5 and 40 chars
+            - type: Length
+              min: 5
+              max: 40
+              # Override the default of 'Invalid input'
+              message: Length must be between 5 and 40 characters
+    
+        # Another text field for the numeric rating
+        - type: Text
+          name: rating
+          label: Rating
+          attributes:
+            title: Enter a rating between 1 and 5 here
+          # Use Filter to clean up the input data
+          # Could use 'NonNumeric' below, but since Filters apply *before*
+          # constraints, it would conflict with the 'Integer' constraint below.
+          # So let's skip this and just use the constraint.
+          #filter:
+            # Remove everything except digits
+            #- NonNumeric
+          # Add constraints to the field
+          constraints:
+            # Make sure it's a number
+            - type: Integer
+              message: "Required. Digits only, please."
+            # Check the min & max values
+            - type: Range
+              min: 1
+              max: 5
+              message: "Must be between 1 and 5."
+    
+        # Add a select list for the author selection.  Note that we will
+        # dynamically fill in all the authors from the controller but we
+        # could manually set items in the select by adding this YAML code:
+        # options:
+        #   - [ '1', 'Bastien' ]
+        #   - [ '2', 'Nasseh'  ]
+        - type: Select
+          name: authors
+          label: Author
+          # Convert the drop-down to a multi-select list
+          multiple: 1
+          # Display 3 entries (user can scroll to see others)
+          size: 3
+          # One could argue we don't need to do filters or constraints for
+          # a select list, but it's smart to do validation and sanity
+          # checks on this data in case a user "hacks" the input
+          # Add constraints to the field
+          constraints:
+            # Make sure it's a number
+            - Integer
+    
+        # The submit button
+        - type: Submit
+          name: submit
+          value: Submit
+    
+    # Global filters and constraints.
+    constraints:
+      # The user cannot leave any fields blank
+      - Required
+      # If not all fields are required, move the Required constraint to the 
+      # fields that are
+    filter:
+      # Remove whitespace at both ends
+      - TrimEdges
+      # Escape HTML characters for safety
+      - HTMLEscape
+
+B<NOTE:> Copying and pasting YAML from perl documentation is sometimes
+tricky.  See the L<Config::General Config for this tutorial> section of
+this document for a more foolproof config format.
+
+The main changes are:
+
+=over 4
+
+=item *
+
+The C<Select> element for C<authors> is changed from a single-select
+drop-down to a multi-select list by adding configuration for the 
+C<multiple> and C<size> options in C<formfu_create.yml>.
+
+=item *
+
+Constraints are added to provide validation of the user input.  See
+L<HTML::FormFu::Constraint|HTML::FormFu::Constraint> for other
+constraints that are available.
+
+=item *
+
+A variety of filters are run on every field to remove and escape 
+unwanted input.  See L<HTML::FormFu::Filter|HTML::FormFu::Filter>
+for more filter options.
+
+=back
+
+
+=head2 Try Out the Updated Form
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still 
+running) and restart it:
+
+    $ script/myapp_server.pl
+
+Make sure you are still logged in as C<test01> and try adding a book 
+with various errors: title less than 5 characters, non-numeric rating, a 
+rating of 0 or 6, etc.  Also try selecting one, two, and zero authors. 
+When you click Submit, the HTML::FormFu C<constraint> items will 
+validate the logic and insert feedback as appropriate.  Try adding blank 
+spaces at the front or the back of the title and note that it will be 
+removed.
+
+
+=head1 CREATE AND UPDATE/EDIT ACTION
+
+Let's expand the work done above to add an edit action.  First, open 
+C<lib/MyApp/Controller/Books.pm> and add the following method to the 
+bottom:
+
+    =head2 formfu_edit
+    
+    Use HTML::FormFu to update an existing book
+    
+    =cut
+    
+    sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0) 
+            :FormConfig('books/formfu_create.yml') {
+        my ($self, $c) = @_;
+    
+        # Get the specified book already saved by the 'object' method
+        my $book = $c->stash->{object};
+    
+        # Make sure we were able to get a book
+        unless ($book) {
+            $c->flash->{error_msg} = "Invalid book -- Cannot edit";
+            $c->response->redirect($c->uri_for($self->action_for('list')));
+            $c->detach;
+        }
+    
+        # Get the form that the :FormConfig attribute saved in the stash
+        my $form = $c->stash->{form};
+    
+        # Check if the form has been submitted (vs. displaying the initial
+        # form) and if the data passed validation.  "submitted_and_valid"
+        # is shorthand for "$form->submitted && !$form->has_errors"
+        if ($form->submitted_and_valid) {
+            # Save the form data for the book
+            $form->model->update($book);
+            # Set a status message for the user
+            $c->flash->{status_msg} = 'Book edited';
+            # Return to the books list
+            $c->response->redirect($c->uri_for($self->action_for('list')));
+            $c->detach;
+        } else {
+            # Get the authors from the DB
+            my @author_objs = $c->model("DB::Author")->all();
+            # Create an array of arrayrefs where each arrayref is an author
+            my @authors;
+            foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
+                push(@authors, [$_->id, $_->last_name]);
+            }
+            # Get the select added by the config file
+            my $select = $form->get_element({type => 'Select'});
+            # Add the authors to it
+            $select->options(\@authors);
+            # Populate the form with existing values from DB
+            $form->model->default_values($book);
+        }
+    
+        # Set the template
+        $c->stash->{template} = 'books/formfu_create.tt2';
+    }
+
+Most of this code should look familiar to what we used in the 
+C<formfu_create> method (in fact, we should probably centralize some of 
+the common code in separate methods).  The main differences are:
+
+=over 4
+
+=item *
+
+We have to manually specify the name of the FormFu .yml file as an 
+argument to C<:FormConfig> because the name can no longer be 
+automatically deduced from the name of our action/method (by default,
+FormFu would look for a file named C<books/formfu_edit.yml>).
+
+=item *
+
+We load the book object from the stash (found using the $id passed to 
+the Chained object method)
+
+=item *
+
+We use C<$id> to look up the existing book from the database.
+
+=item *
+
+We make sure the book lookup returned a valid book.  If not, we set 
+the error message and return to the book list.
+ 
+=item *
+
+If the form has been submitted and passes validation, we skip creating a 
+new book and just use C<$form-E<gt>model-E<gt>update> to update the existing 
+book.
+
+=item *
+
+If the form is being displayed for the first time (or has failed 
+validation and it being redisplayed), we use
+ C<$form-E<gt>model-E<gt>default_values> to populate the form with data from the
+database.
+
+=back
+
+Then, edit C<root/src/books/list.tt2> and add a new link below the 
+existing "Delete" link that allows us to edit/update each existing book. 
+The last E<lt>tdE<gt> cell in the book list table should look like the 
+following:
+
+    ...
+    <td>
+      [% # Add a link to delete a book %]
+      <a href="[% c.uri_for(c.controller.action_for('delete'), [book.id]) %]">Delete</a>
+      [% # Add a link to edit a book %]
+      <a href="[% c.uri_for(c.controller.action_for('formfu_edit'), [book.id]) %]">Edit</a>
+    </td>
+    ...
+
+B<Note:> Only add two lines (the "Add a link to edit a book" comment
+and the href for C<formfu_edit>).  Make sure you add it below the
+existing C<delete> link.
+
+
+=head2 Try Out the Edit/Update Feature
+
+Press C<Ctrl-C> to kill the previous server instance (if it's still 
+running) and restart it:
+
+    $ script/myapp_server.pl
+
+Make sure you are still logged in as C<test01> and go to the 
+L<http://localhost:3000/books/list> URL in your browser.  Click the 
+"Edit" link next to "Internetworking with TCP/IP Vol. II", change the 
+rating to a 3, the "II" at end of the title to the number "2", add 
+Stevens as a co-author (control-click), and click Submit.  You will then 
+be returned to the book list with a "Book edited" message at the top in 
+green.  Experiment with other edits to various books.
+
+
+=head2 More Things to Try
+
+You are now armed with enough knowledge to be dangerous.  You can keep
+tweaking the example application; some things you might want to do:
+
+=over 4
+
+=item *
+
+Add an appropriate authorization check to the new Edit function.
+
+=item *
+
+Cleanup the List page so that the Login link only displays when the user
+isn't logged in and the Logout link only displays when a user is logged
+in.
+
+=item *
+
+Add a more sensible policy for when and how users and admins can do
+things in the CRUD cycle.
+
+=item *
+
+Support the CRUD cycle for authors.
+
+=back
+
+Or you can proceed to write your own application, which is probably the
+real reason you worked through this Tutorial in the first place.
+
+
+=head2  Config::General Config for this tutorial
+
+If you are having difficulty with YAML config above, please save the
+below into the file C<formfu_create.conf> and delete the
+C<formfu_create.yml> file.  The below is in
+L<Config::General|Config::General> format which follows the syntax of
+Apache config files.
+
+   constraints   Required
+   <elements>
+       <constraints>
+           min   5
+           max   40
+           type   Length
+           message   Length must be between 5 and 40 characters
+       </constraints>
+       filter   TrimEdges
+       filter   HTMLEscape
+       name   title
+       type   Text
+       label   Title
+       <attributes>
+           title   Enter a book title here
+       </attributes>
+   </elements>
+   <elements>
+       constraints   Integer
+       filter   TrimEdges
+       filter   NonNumeric
+       name   rating
+       type   Text
+       label   Rating
+       <attributes>
+           title   Enter a rating between 1 and 5 here
+       </attributes>
+   </elements>
+   <elements>
+       constraints   Integer
+       filter   TrimEdges
+       filter   HTMLEscape
+       name   authors
+       type   Select
+       label   Author
+       multiple   1
+       size   3
+   </elements>
+   <elements>
+       value   Submit
+       name   submit
+       type   Submit
+   </elements>
+   indicator   submit
+   
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).    

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/FormBuilder.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormBuilder.pod	2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/FormBuilder.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,60 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::AdvancedCRUD::FormBuilder - Catalyst Tutorial - Chapter 9: Advanced CRUD - FormBuilder
-
-NOTE:  This chapter of the tutorial is in progress.  Feel free to 
-volunteer to help out. :-)
-
-=head1 OVERVIEW
-
-This is B<Chapter 9 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-B<Advanced CRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/FormFu.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD/FormFu.pod	2009-05-24 20:40:11 UTC (rev 10274)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD/FormFu.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,671 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::AdvancedCRUD::FormFu - Catalyst Tutorial - Chapter 9: Advanced CRUD - FormFu
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 9 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-B<Advanced CRUD::FormFu>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This portion of the tutorial explores L<HTML::FormFu|HTML::FormFu> and 
-how it can be used to manage forms, perform validation of form input, 
-as well as save and restore data to/from the database.  This was written
-using HTML::FormFu version 0.03007.
-
-See 
-L<Catalyst::Manual::Tutorial::AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-for additional form management options other than 
-L<HTML::FormFu|HTML::FormFu>.
-
-
-=head1 Install HTML::FormFu
-
-If you are following along in Debian 5, it turns out that some of the 
-modules we need are not yet available as Debian packages at the time 
-this was written.  To install it with a combination of Debian packages 
-and traditional CPAN modules, first use C<aptitude> to install most of 
-the modules:
-
-we need to install the
-L<HTML::FormFu|HTML::FormFu> package: 
-
-    sudo aptitude -y install libhtml-formfu-perl libmoose-perl \
-        libregexp-assemble-perl libhtml-formfu-model-dbic-perl
-        
-    ...
-    
-    sudo aptitude clean
-
-Then use the following command to install directly from CPAN the modules 
-that aren't available as Debian packages:
-
-    sudo cpan Catalyst::Component::InstancePerContext Catalyst::Controller::HTML::FormFu
-
-
-=head1 HTML::FormFu FORM CREATION
-
-This section looks at how L<HTML::FormFu|HTML::FormFu> can be used to 
-add additional functionality to the manually created form from Chapter 4.
-
-
-=head2 Inherit From Catalyst::Controller::HTML::FormFu
-
-First, change your C<lib/MyApp/Controller/Books.pm> to inherit from
-L<Catalyst::Controller::HTML::FormFu|Catalyst::Controller::HTML::FormFu>
-by changing the C<use parent> line from the default of:
-
-    use parent 'Catalyst::Controller';
-
-to use the FormFu base controller class:
-
-    use parent 'Catalyst::Controller::HTML::FormFu';
-
-
-=head2 Add Action to Display and Save the Form
-
-Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
-following method:
-
-    =head2 formfu_create
-    
-    Use HTML::FormFu to create a new book
-    
-    =cut
-    
-    sub formfu_create :Chained('base') :PathPart('formfu_create') :Args(0) :FormConfig {
-        my ($self, $c) = @_;
-    
-        # Get the form that the :FormConfig attribute saved in the stash
-        my $form = $c->stash->{form};
-  
-        # Check if the form has been submitted (vs. displaying the initial
-        # form) and if the data passed validation.  "submitted_and_valid"
-        # is shorthand for "$form->submitted && !$form->has_errors"
-        if ($form->submitted_and_valid) {
-            # Create a new book
-            my $book = $c->model('DB::Books')->new_result({});
-            # Save the form data for the book
-            $form->model->update($book);
-            # Set a status message for the user
-            $c->flash->{status_msg} = 'Book created';
-            # Return to the books list
-            $c->response->redirect($c->uri_for($self->action_for('list'))); 
-            $c->detach;
-        } else {
-            # Get the authors from the DB
-            my @author_objs = $c->model("DB::Authors")->all();
-            # Create an array of arrayrefs where each arrayref is an author
-            my @authors;
-            foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
-                push(@authors, [$_->id, $_->last_name]);
-            }
-            # Get the select added by the config file
-            my $select = $form->get_element({type => 'Select'});
-            # Add the authors to it
-            $select->options(\@authors);
-        }
-        
-        # Set the template
-        $c->stash->{template} = 'books/formfu_create.tt2';
-    }
-
-
-=head2 Create a Form Config File
-
-Although C<HTML::FormFu> supports any configuration file handled by
-L<Config::Any|Config::Any>, most people tend to use YAML.  First
-create a directory to hold your form configuration files:
-
-    mkdir -p root/forms/books
-
-Then create the file C<root/forms/books/formfu_create.yml> and enter the 
-following text:
-
-    ---
-    # indicator is the field that is used to test for form submission
-    indicator: submit
-    # Start listing the form elements
-    elements:
-        # The first element will be a text field for the title
-        - type: Text
-          name: title
-          label: Title
-          # This is an optional 'mouse over' title pop-up
-          attributes:
-            title: Enter a book title here
-    
-        # Another text field for the numeric rating
-        - type: Text
-          name: rating
-          label: Rating
-          attributes:
-            title: Enter a rating between 1 and 5 here
-    
-        # Add a drop-down list for the author selection.  Note that we will
-        # dynamically fill in all the authors from the controller but we
-        # could manually set items in the drop-list by adding this YAML code:
-        # options:
-        #   - [ '1', 'Bastien' ]
-        #   - [ '2', 'Nasseh'  ]
-        - type: Select
-          name: authors
-          label: Author
-    
-        # The submit button
-        - type: Submit
-          name: submit
-          value: Submit
-
-B<NOTE:> Copying and pasting YAML from perl documentation is sometimes
-tricky.  See the L<Config::General Config for this tutorial> section of
-this document for a more foolproof config format.
-
-
-=head2 Update the CSS
-
-Edit C<root/static/css/main.css> and add the following lines to the bottom of
-the file:
-
-    ...
-    input {
-        display: block;
-    }
-    select {
-        display: block;
-    }
-    .submit {
-        padding-top: .5em;
-        display: block;
-    }
-
-These changes will display form elements vertically.  Note that the 
-existing definition of the C<.error> class is pulling the color scheme 
-settings from the C<root/lib/config/col> file that was created by the 
-TTSite helper.  This allows control over the CSS color settings from a 
-single location.
-
-
-=head2 Create a Template Page To Display The Form
-
-Open C<root/src/books/formfu_create.tt2> in your editor and enter the following:
-
-    [% META title = 'Create/Update Book' %]
-    
-    [%# Render the HTML::FormFu Form %]
-    [% form %]
-    
-    <p><a href="[% c.uri_for(c.controller.action_for('list')) %]">Return to book list</a></p>
-
-
-=head2 Add Links for Create and Update via C<HTML::FormFu>
-
-Open C<root/src/books/list.tt2> in your editor and add the following to
-the bottom of the existing file:
-
-    ...
-    <p>
-      HTML::FormFu:
-      <a href="[% c.uri_for(c.controller.action_for('formfu_create')) %]">Create</a>
-    </p>
-
-This adds a new link to the bottom of the book list page that we can
-use to easily launch our HTML::FormFu-based form.
-
-
-=head2 Test The HTML::FormFu Create Form
-
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-Login as C<test01> (password: mypass).  Once at the Book List page,
-click the new HTML::FormFu "Create" link at the bottom to display the
-form.  Fill in the following values: Title = "Internetworking with
-TCP/IP Vol. II", Rating = "4", and Author = "Comer".  Click Submit,
-and you will be returned to the Book List page with a "Book created"
-status message displayed.
-
-Also note that this implementation allows you to can create books with 
-bogus information.  Although we have constrained the authors with the 
-drop-down list (note that this isn't bulletproof because we still have 
-not prevented a user from "hacking" the form to specify other values), 
-there are no restrictions on items such as the length of the title (for 
-example, you can create a one-letter title) and value for the rating 
-(you can use any number you want, and even non-numeric values with 
-SQLite).  The next section will address this concern.
-
-B<Note:> Depending on the database you are using and how you established
-the columns in your tables, the database could obviously provide various
-levels of "type enforcement" on your data.  The key point being made in
-the previous paragraph is that the I<web application> itself is not
-performing any validation.
-
-
-=head1 HTML::FormFu VALIDATION AND FILTERING
-
-Although the use of L<HTML::FormFu|HTML::FormFu> in the previous section 
-did provide an automated mechanism to build the form, the real power of 
-this module stems from functionality that can automatically validate and 
-filter the user input.  Validation uses constraints to be sure that 
-users input appropriate data (for example, that the email field of a 
-form contains a valid email address).  Filtering can also be used to 
-remove extraneous whitespace from fields or to escape meta-characters in 
-user input.
-
-
-=head2 Add Constraints
-
-Open C<root/forms/books/formfu_create.yml> in your editor and update it 
-to match:
-
-    ---
-    # indicator is the field that is used to test for form submission
-    indicator: submit
-    # Start listing the form elements
-    elements:
-        # The first element will be a text field for the title
-        - type: Text
-          name: title
-          label: Title
-          # This is an optional 'mouse over' title pop-up
-          attributes:
-            title: Enter a book title here
-          # Add constraints for the field
-          constraints:
-            # Force the length to be between 5 and 40 chars
-            - type: Length
-              min: 5
-              max: 40
-              # Override the default of 'Invalid input'
-              message: Length must be between 5 and 40 characters
-    
-        # Another text field for the numeric rating
-        - type: Text
-          name: rating
-          label: Rating
-          attributes:
-            title: Enter a rating between 1 and 5 here
-          # Use Filter to clean up the input data
-          # Could use 'NonNumeric' below, but since Filters apply *before*
-          # constraints, it would conflict with the 'Integer' constraint below.
-          # So let's skip this and just use the constraint.
-          #filter:
-            # Remove everything except digits
-            #- NonNumeric
-          # Add constraints to the field
-          constraints:
-            # Make sure it's a number
-            - type: Integer
-              message: "Required. Digits only, please."
-            # Check the min & max values
-            - type: Range
-              min: 1
-              max: 5
-              message: "Must be between 1 and 5."
-    
-        # Add a select list for the author selection.  Note that we will
-        # dynamically fill in all the authors from the controller but we
-        # could manually set items in the select by adding this YAML code:
-        # options:
-        #   - [ '1', 'Bastien' ]
-        #   - [ '2', 'Nasseh'  ]
-        - type: Select
-          name: authors
-          label: Author
-          # Convert the drop-down to a multi-select list
-          multiple: 1
-          # Display 3 entries (user can scroll to see others)
-          size: 3
-          # One could argue we don't need to do filters or constraints for
-          # a select list, but it's smart to do validation and sanity
-          # checks on this data in case a user "hacks" the input
-          # Add constraints to the field
-          constraints:
-            # Make sure it's a number
-            - Integer
-    
-        # The submit button
-        - type: Submit
-          name: submit
-          value: Submit
-    
-    # Global filters and constraints.
-    constraints:
-      # The user cannot leave any fields blank
-      - Required
-      # If not all fields are required, move the Required constraint to the 
-      # fields that are
-    filter:
-      # Remove whitespace at both ends
-      - TrimEdges
-      # Escape HTML characters for safety
-      - HTMLEscape
-
-B<NOTE:> Copying and pasting YAML from perl documentation is sometimes
-tricky.  See the L<Config::General Config for this tutorial> section of
-this document for a more foolproof config format.
-
-The main changes are:
-
-=over 4
-
-=item *
-
-The C<Select> element for C<authors> is changed from a single-select
-drop-down to a multi-select list by adding configuration for the 
-C<multiple> and C<size> options in C<formfu_create.yml>.
-
-=item *
-
-Constraints are added to provide validation of the user input.  See
-L<HTML::FormFu::Constraint|HTML::FormFu::Constraint> for other
-constraints that are available.
-
-=item *
-
-A variety of filters are run on every field to remove and escape 
-unwanted input.  See L<HTML::FormFu::Filter|HTML::FormFu::Filter>
-for more filter options.
-
-=back
-
-
-=head2 Try Out the Updated Form
-
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-Make sure you are still logged in as C<test01> and try adding a book 
-with various errors: title less than 5 characters, non-numeric rating, a 
-rating of 0 or 6, etc.  Also try selecting one, two, and zero authors. 
-When you click Submit, the HTML::FormFu C<constraint> items will 
-validate the logic and insert feedback as appropriate.  Try adding blank 
-spaces at the front or the back of the title and note that it will be 
-removed.
-
-
-=head1 CREATE AND UPDATE/EDIT ACTION
-
-Let's expand the work done above to add an edit action.  First, open 
-C<lib/MyApp/Controller/Books.pm> and add the following method to the 
-bottom:
-
-    =head2 formfu_edit
-    
-    Use HTML::FormFu to update an existing book
-    
-    =cut
-    
-    sub formfu_edit :Chained('object') :PathPart('formfu_edit') :Args(0) 
-            :FormConfig('books/formfu_create.yml') {
-        my ($self, $c) = @_;
-    
-        # Get the specified book already saved by the 'object' method
-        my $book = $c->stash->{object};
-    
-        # Make sure we were able to get a book
-        unless ($book) {
-            $c->flash->{error_msg} = "Invalid book -- Cannot edit";
-            $c->response->redirect($c->uri_for($self->action_for('list')));
-            $c->detach;
-        }
-    
-        # Get the form that the :FormConfig attribute saved in the stash
-        my $form = $c->stash->{form};
-    
-        # Check if the form has been submitted (vs. displaying the initial
-        # form) and if the data passed validation.  "submitted_and_valid"
-        # is shorthand for "$form->submitted && !$form->has_errors"
-        if ($form->submitted_and_valid) {
-            # Save the form data for the book
-            $form->model->update($book);
-            # Set a status message for the user
-            $c->flash->{status_msg} = 'Book edited';
-            # Return to the books list
-            $c->response->redirect($c->uri_for($self->action_for('list')));
-            $c->detach;
-        } else {
-            # Get the authors from the DB
-            my @author_objs = $c->model("DB::Authors")->all();
-            # Create an array of arrayrefs where each arrayref is an author
-            my @authors;
-            foreach (sort {$a->last_name cmp $b->last_name} @author_objs) {
-                push(@authors, [$_->id, $_->last_name]);
-            }
-            # Get the select added by the config file
-            my $select = $form->get_element({type => 'Select'});
-            # Add the authors to it
-            $select->options(\@authors);
-            # Populate the form with existing values from DB
-            $form->model->default_values($book);
-        }
-    
-        # Set the template
-        $c->stash->{template} = 'books/formfu_create.tt2';
-    }
-
-Most of this code should look familiar to what we used in the 
-C<formfu_create> method (in fact, we should probably centralize some of 
-the common code in separate methods).  The main differences are:
-
-=over 4
-
-=item *
-
-We have to manually specify the name of the FormFu .yml file as an 
-argument to C<:FormConfig> because the name can no longer be 
-automatically deduced from the name of our action/method (by default,
-FormFu would look for a file named C<books/formfu_edit.yml>).
-
-=item *
-
-We load the book object from the stash (found using the $id passed to 
-the Chained object method)
-
-=item *
-
-We use C<$id> to look up the existing book from the database.
-
-=item *
-
-We make sure the book lookup returned a valid book.  If not, we set 
-the error message and return to the book list.
- 
-=item *
-
-If the form has been submitted and passes validation, we skip creating a 
-new book and just use C<$form-E<gt>model-E<gt>update> to update the existing 
-book.
-
-=item *
-
-If the form is being displayed for the first time (or has failed 
-validation and it being redisplayed), we use
- C<$form-E<gt>model-E<gt>default_values> to populate the form with data from the
-database.
-
-=back
-
-Then, edit C<root/src/books/list.tt2> and add a new link below the 
-existing "Delete" link that allows us to edit/update each existing book. 
-The last E<lt>tdE<gt> cell in the book list table should look like the 
-following:
-
-    ...
-    <td>
-      [% # Add a link to delete a book %]
-      <a href="[% c.uri_for(c.controller.action_for('delete'), [book.id]) %]">Delete</a>
-      [% # Add a link to edit a book %]
-      <a href="[% c.uri_for(c.controller.action_for('formfu_edit'), [book.id]) %]">Edit</a>
-    </td>
-    ...
-
-B<Note:> Only add two lines (the "Add a link to edit a book" comment
-and the href for C<formfu_edit>).  Make sure you add it below the
-existing C<delete> link.
-
-
-=head2 Try Out the Edit/Update Feature
-
-Press C<Ctrl-C> to kill the previous server instance (if it's still 
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-Make sure you are still logged in as C<test01> and go to the 
-L<http://localhost:3000/books/list> URL in your browser.  Click the 
-"Edit" link next to "Internetworking with TCP/IP Vol. II", change the 
-rating to a 3, the "II" at end of the title to the number "2", add 
-Stevens as a co-author (control-click), and click Submit.  You will then 
-be returned to the book list with a "Book edited" message at the top in 
-green.  Experiment with other edits to various books.
-
-
-=head2 More Things to Try
-
-You are now armed with enough knowledge to be dangerous.  You can keep
-tweaking the example application; some things you might want to do:
-
-=over 4
-
-=item *
-
-Add an appropriate authorization check to the new Edit function.
-
-=item *
-
-Cleanup the List page so that the Login link only displays when the user
-isn't logged in and the Logout link only displays when a user is logged
-in.
-
-=item *
-
-Add a more sensible policy for when and how users and admins can do
-things in the CRUD cycle.
-
-=item *
-
-Support the CRUD cycle for authors.
-
-=back
-
-Or you can proceed to write your own application, which is probably the
-real reason you worked through this Tutorial in the first place.
-
-
-=head2  Config::General Config for this tutorial
-
-If you are having difficulty with YAML config above, please save the
-below into the file C<formfu_create.conf> and delete the
-C<formfu_create.yml> file.  The below is in
-L<Config::General|Config::General> format which follows the syntax of
-Apache config files.
-
-   constraints   Required
-   <elements>
-       <constraints>
-           min   5
-           max   40
-           type   Length
-           message   Length must be between 5 and 40 characters
-       </constraints>
-       filter   TrimEdges
-       filter   HTMLEscape
-       name   title
-       type   Text
-       label   Title
-       <attributes>
-           title   Enter a book title here
-       </attributes>
-   </elements>
-   <elements>
-       constraints   Integer
-       filter   TrimEdges
-       filter   NonNumeric
-       name   rating
-       type   Text
-       label   Rating
-       <attributes>
-           title   Enter a rating between 1 and 5 here
-       </attributes>
-   </elements>
-   <elements>
-       constraints   Integer
-       filter   TrimEdges
-       filter   HTMLEscape
-       name   authors
-       type   Select
-       label   Author
-       multiple   1
-       size   3
-   </elements>
-   <elements>
-       value   Submit
-       name   submit
-       type   Submit
-   </elements>
-   indicator   submit
-   
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).    

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD.pod (from rev 10274, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/09_AdvancedCRUD.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,99 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::09_AdvancedCRUD - Catalyst Tutorial - Chapter 9: Advanced CRUD
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 9 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+B<09_Advanced CRUD>
+
+=item 10
+
+L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This chapter of the tutorial explores more advanced functionality for
+Create, Read, Update, and Delete (CRUD) than we saw in Chapter 4.  In
+particular, it looks at a number of techniques that can be useful for
+the Update portion of CRUD, such as automated form generation,
+validation of user-entered data, and automated transfer of data between
+forms and model objects.
+
+In keeping with the Catalyst (and Perl) spirit of flexibility, there are 
+many different ways to approach advanced CRUD operations in a Catalyst 
+environment.  Therefore, this section of the tutorial allows you to pick 
+from one of several modules that that cover different form management 
+tools.  Select one or more options from the list below.
+
+=head1 ADVANCED CRUD OPTIONS
+
+=over 4
+
+=item *
+
+L<FormFu|Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormFu>
+
+=item *
+
+L<FormBuilder|Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormBuilder>
+
+=back
+
+B<NOTE:> Please contact the author if you would like to assist with 
+writing a new module.
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Copied: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/10_Appendices.pod (from rev 10274, Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Appendices.pod)
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/10_Appendices.pod	                        (rev 0)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/10_Appendices.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -0,0 +1,784 @@
+=head1 NAME
+
+Catalyst::Manual::Tutorial::10_Appendices - Catalyst Tutorial - Chapter 10: Appendices
+
+
+=head1 OVERVIEW
+
+This is B<Chapter 10 of 10> for the Catalyst tutorial.
+
+L<Tutorial Overview|Catalyst::Manual::Tutorial>
+
+=over 4
+
+=item 1
+
+L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
+
+=item 2
+
+L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
+
+=item 3
+
+L<More Catalyst Basics|Catalyst::Manual::Tutorial::03_MoreCatalystBasics>
+
+=item 4
+
+L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
+
+=item 5
+
+L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
+
+=item 6
+
+L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
+
+=item 7
+
+L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
+
+=item 8
+
+L<Testing|Catalyst::Manual::Tutorial::08_Testing>
+
+=item 9
+
+L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
+
+=item 10
+
+B<10_Appendices>
+
+=back
+
+
+=head1 DESCRIPTION
+
+This chapter of the tutorial provides supporting information relevant to
+the Catalyst tutorial.
+
+
+=head1 APPENDIX 1: CUT AND PASTE FOR POD-BASED EXAMPLES
+
+You may notice that Pod indents example code with four spaces.  This
+section provides some quick advice to "un-indent" this text in common
+editors.
+
+=head2 "Un-indenting" with Vi/Vim
+
+When cutting and pasting multi-line text from Pod-based documents, the
+following vi/vim regexs can be helpful to "un-indent" the inserted text
+(do NOT type the quotes, they are only included to show spaces in the
+regex patterns).  I<Note that all 3 of the regexs end in 4 spaces>:
+
+=over 4
+
+=item *
+
+":0,$s/^    "
+
+Removes four leading spaces from the entire file (from the first line,
+C<0>, to the last line, C<$>).
+
+=item *
+
+"%s/^    "
+
+A shortcut for the previous item (C<%> specifies the entire file; so
+this removes four leading spaces from every line).
+
+=item *
+
+":.,$s/^    "
+
+Removes the first four spaces from the line the cursor is on at the time
+the regex command is executed (".") to the last line of the file.
+
+=item *
+
+":.,44s/^    "
+
+Removes four leading space from the current line through line 44
+(obviously adjust the C<44> to the appropriate value in your example).
+
+=back
+
+=head2 "Un-indenting" with Emacs
+
+Although the author has not used Emacs for many years (apologies to
+the Emacs fans out there), here is a quick hint to get you started.  To
+replace the leading spaces of every line in a file, use:
+
+    M-x replace-regexp<RET>
+    Replace regexp: ^    <RET>
+    with: <RET>
+
+All of that will occur on the single line at the bottom of your screen.
+Note that "<RET>" represents the return key/enter.  Also, there are
+four spaces after the "^" on the "Replace regexp:" line and no spaces
+entered on the last line.
+
+You can limit the replacement operation by selecting text first (depending
+on your version of Emacs, you can either use the mouse or experiment with
+commands such as C<C-SPC> to set the mark at the cursor location and
+C<C-E<lt>> and C<C-E<gt>> to set the mark at the beginning and end of the
+file respectively.
+
+Also, Stefan Kangas sent in the following tip about an alternate 
+approach using the command C<indent-region> to redo the indentation 
+for the currently selected region (adhering to indent rules in the 
+current major mode). You can run the command by typing M-x indent-
+region or pressing the default keybinding C-M-\ in cperl-mode. 
+Additional details can be found here:
+
+L<http://www.gnu.org/software/emacs/manual/html_node/emacs/Indentation-Comman>
+
+
+=head1 APPENDIX 2: USING POSTGRESQL AND MYSQL
+
+The main database used in this tutorial is the very simple yet powerful
+SQLite.  This section provides information that can be used to "convert"
+the tutorial to use PostgreSQL and MySQL.  However, note that part of
+the beauty of the MVC architecture is that very little database-specific
+code is spread throughout the system (at least when MVC is "done
+right").  Consequently, converting from one database to another is
+relatively painless with most Catalyst applications.  In general, you
+just need to adapt the schema definition C<.sql> file you use to
+initialize your database and adjust a few configuration parameters.
+
+Also note that the purpose of the data definition statements for this
+section are not designed to take maximum advantage of the various
+features in each database for issues such as referential integrity and
+field types/constraints.
+
+
+=head2 PostgreSQL
+
+Use the following steps to adapt the tutorial to PostgreSQL.  Thanks 
+to Caelum (Rafael Kitover) for assistance with the most recent 
+updates, and Louis Moore, Marcello Romani and Tom Lanyon for help with 
+earlier versions.
+
+=over 4
+
+=item *
+
+Chapter 3: More Catalyst Basics
+
+=over 4
+
+=item *
+
+Install the PostgreSQL server and client and DBD::Pg:
+
+If you are following along in Debian 5, you can quickly install these 
+items via this command:
+
+    sudo aptitude install postgresql libdbd-pg-perl libdatetime-format-pg-perl
+
+To configure the permissions, you can open 
+C</etc/postgresql/8.3/main/pg_hba.conf> and change this line (near the 
+bottom):
+
+    # "local" is for Unix domain socket connections only
+    local   all         all                               ident sameuser
+
+to:
+
+    # "local" is for Unix domain socket connections only
+    local   all         all                               trust
+
+And then restart PostgreSQL:
+
+    sudo /etc/init.d/postgresql-8.3 restart
+
+
+=item *
+
+Create the database and a user for the database (note that we are 
+using "E<lt>catalystE<gt>" to represent the hidden password of 
+"catalyst"):
+
+    $ sudo -u postgres createuser -P catappuser
+    Enter password for new role: <catalyst>
+    Enter it again: <catalyst>
+    Shall the new role be a superuser? (y/n) n
+    Shall the new role be allowed to create databases? (y/n) n
+    Shall the new role be allowed to create more new roles? (y/n) n
+    CREATE ROLE
+    $ sudo -u postgres createdb -O catappuser catappdb
+    CREATE DATABASE
+
+=item *
+
+Create the C<.sql> file and load the data:
+
+=over 4
+
+=item *
+
+Open the C<myapp01_psql.sql> in your editor and enter:
+
+    --
+    -- Drops just in case you are reloading
+    ---
+    DROP TABLE IF EXISTS books CASCADE;
+    DROP TABLE IF EXISTS authors CASCADE;
+    DROP TABLE IF EXISTS book_authors CASCADE;
+    DROP TABLE IF EXISTS users CASCADE;
+    DROP TABLE IF EXISTS roles CASCADE;
+    DROP TABLE IF EXISTS user_roles CASCADE;
+    
+    --
+    -- Create a very simple database to hold book and author information
+    --
+    CREATE TABLE books (
+        id          SERIAL PRIMARY KEY,
+        title       TEXT ,
+        rating      INTEGER,
+        -- Manually add these later
+        -- created     TIMESTAMP NOT NULL DEFAULT now(),
+        -- updated     TIMESTAMP
+    );
+    
+    CREATE TABLE authors (
+        id          SERIAL PRIMARY KEY,
+        first_name  TEXT,
+        last_name   TEXT
+    );
+    
+    -- 'book_authors' is a many-to-many join table between books & authors
+    CREATE TABLE book_authors (
+        book_id     INTEGER REFERENCES books(id) ON DELETE CASCADE ON UPDATE CASCADE,
+        author_id   INTEGER REFERENCES authors(id) ON DELETE CASCADE ON UPDATE CASCADE,
+        PRIMARY KEY (book_id, author_id)
+    );
+    
+    ---
+    --- Load some sample data
+    ---
+    INSERT INTO books (title, rating) VALUES ('CCSP SNRS Exam Certification Guide', 5);
+    INSERT INTO books (title, rating) VALUES ('TCP/IP Illustrated, Volume 1', 5);
+    INSERT INTO books (title, rating) VALUES ('Internetworking with TCP/IP Vol.1', 4);
+    INSERT INTO books (title, rating) VALUES ('Perl Cookbook', 5);
+    INSERT INTO books (title, rating) VALUES ('Designing with Web Standards', 5);
+    INSERT INTO authors (first_name, last_name) VALUES ('Greg', 'Bastien');
+    INSERT INTO authors (first_name, last_name) VALUES ('Sara', 'Nasseh');
+    INSERT INTO authors (first_name, last_name) VALUES ('Christian', 'Degu');
+    INSERT INTO authors (first_name, last_name) VALUES ('Richard', 'Stevens');
+    INSERT INTO authors (first_name, last_name) VALUES ('Douglas', 'Comer');
+    INSERT INTO authors (first_name, last_name) VALUES ('Tom', 'Christiansen');
+    INSERT INTO authors (first_name, last_name) VALUES ('Nathan', 'Torkington');
+    INSERT INTO authors (first_name, last_name) VALUES ('Jeffrey', 'Zeldman');
+    INSERT INTO book_authors VALUES (1, 1);
+    INSERT INTO book_authors VALUES (1, 2);
+    INSERT INTO book_authors VALUES (1, 3);
+    INSERT INTO book_authors VALUES (2, 4);
+    INSERT INTO book_authors VALUES (3, 5);
+    INSERT INTO book_authors VALUES (4, 6);
+    INSERT INTO book_authors VALUES (4, 7);
+    INSERT INTO book_authors VALUES (5, 8);
+
+=item *
+
+Load the data:
+
+    $ psql -U catappuser -W catappdb -f myapp01_psql.sql
+    Password for user catappuser: 
+    psql:myapp01_psql.sql:8: NOTICE:  CREATE TABLE will create implicit sequence "books_id_seq" for serial column "books.id"
+    psql:myapp01_psql.sql:8: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "books_pkey" for table "books"
+    CREATE TABLE
+    psql:myapp01_psql.sql:15: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "book_authors_pkey" for table "book_authors"
+    CREATE TABLE
+    psql:myapp01_psql.sql:21: NOTICE:  CREATE TABLE will create implicit sequence "authors_id_seq" for serial column "authors.id"
+    psql:myapp01_psql.sql:21: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "authors_pkey" for table "authors"
+    CREATE TABLE
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    ...
+
+=item *
+
+Make sure the data loaded correctly:
+
+    $ psql -U catappuser -W catappdb
+    Password for user catappuser: <catalyst>
+    Welcome to psql 8.3.7, the PostgreSQL interactive terminal.
+    
+    Type:  \copyright for distribution terms
+           \h for help with SQL commands
+           \? for help with psql commands
+           \g or terminate with semicolon to execute query
+           \q to quit
+    
+    catappdb=> \dt
+                 List of relations
+     Schema |     Name     | Type  |   Owner    
+    --------+--------------+-------+------------
+     public | authors      | table | catappuser
+     public | book_authors | table | catappuser
+     public | books        | table | catappuser
+    (3 rows)
+    
+    catappdb=> select * from books;
+     id |               title                | rating 
+    ----+------------------------------------+--------
+      1 | CCSP SNRS Exam Certification Guide |      5
+      2 | TCP/IP Illustrated, Volume 1       |      5
+      3 | Internetworking with TCP/IP Vol.1  |      4
+      4 | Perl Cookbook                      |      5
+      5 | Designing with Web Standards       |      5
+    (5 rows)
+    
+    catappdb=> 
+
+=back
+
+=item *
+
+After the steps where you:
+
+    edit lib/MyApp.pm
+    
+    create lib/MyAppDB.pm
+    
+    create lib/MyAppDB/Book.pm
+    
+    create lib/MyAppDB/Author.pm
+    
+    create lib/MyAppDB/BookAuthor.pm
+
+
+=item *
+
+Generate the model using the Catalyst "_create.pl" script:
+
+    $ rm lib/MyApp/Model/DB.pm   # Delete just in case already there
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp,EncodedColumn \
+        'dbi:Pg:dbname=catappdb' 'catappuser' 'catalyst' '{ AutoCommit => 1 }'
+
+=back
+
+=item *
+
+Chapter 4: Basic CRUD
+
+Add Datetime Columns to Our Existing Books Table
+
+    $ psql -U catappuser -W catappdb
+    ...
+    catappdb=> ALTER TABLE books ADD created TIMESTAMP NOT NULL DEFAULT now();
+    ALTER TABLE
+    catappdb=> ALTER TABLE books ADD updated TIMESTAMP;
+    ALTER TABLE
+    catappdb=> \q
+
+Re-generate the model using the Catalyst "_create.pl" script:
+
+    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        create=static components=TimeStamp,EncodedColumn \
+        'dbi:Pg:dbname=catappdb' 'catappuser' 'catalyst' '{ AutoCommit => 1 }'
+
+
+=item *
+
+Chapter 5: Authentication
+
+=over 4
+
+=item *
+
+Create the C<.sql> file for the user/roles data:
+
+Open C<myapp02_psql.sql> in your editor and enter:
+
+    --
+    -- Add users and roles tables, along with a many-to-many join table
+    --
+    
+    CREATE TABLE users (
+        id            SERIAL PRIMARY KEY,
+        username      TEXT,
+        password      TEXT,
+        email_address TEXT,
+        first_name    TEXT,
+        last_name     TEXT,
+        active        INTEGER
+    );
+    
+    CREATE TABLE roles (
+        id   SERIAL PRIMARY KEY,
+        role TEXT
+    );
+    
+    CREATE TABLE user_roles (
+        user_id INTEGER REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
+        role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE ON UPDATE CASCADE,
+        PRIMARY KEY (user_id, role_id)
+    );
+    
+    --
+    -- Load up some initial test data
+    --
+    INSERT INTO users (username, password, email_address, first_name, last_name, active) 
+        VALUES ('test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
+    INSERT INTO users (username, password, email_address, first_name, last_name, active) 
+        VALUES ('test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
+    INSERT INTO users (username, password, email_address, first_name, last_name, active)
+        VALUES ('test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
+    INSERT INTO roles (role) VALUES ('user');
+    INSERT INTO roles (role) VALUES ('admin');
+    INSERT INTO user_roles VALUES (1, 1);
+    INSERT INTO user_roles VALUES (1, 2);
+    INSERT INTO user_roles VALUES (2, 1);
+    INSERT INTO user_roles VALUES (3, 1);
+
+=item *
+
+Load the data:
+
+    $ psql -U catappuser -W catappdb -f myapp02_psql.sql
+    Password for user catappuser: <catalyst>
+    psql:myapp02_psql.sql:13: NOTICE:  CREATE TABLE will create implicit sequence "users_id_seq" for serial column "users.id"
+    psql:myapp02_psql.sql:13: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
+    CREATE TABLE
+    psql:myapp02_psql.sql:18: NOTICE:  CREATE TABLE will create implicit sequence "roles_id_seq" for serial column "roles.id"
+    psql:myapp02_psql.sql:18: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "roles_pkey" for table "roles"
+    CREATE TABLE
+    psql:myapp02_psql.sql:24: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "user_roles_pkey" for table "user_roles"
+    CREATE TABLE
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+    INSERT 0 1
+
+Confirm with:
+
+    $ psql -U catappuser -W catappdb -c "select * from users"
+    Password for user catappuser: <catalyst>
+     id | username | password | email_address | first_name | last_name | active 
+    ----+----------+----------+---------------+------------+-----------+--------
+      1 | test01   | mypass   | t01 at na.com    | Joe        | Blow      |      1
+      2 | test02   | mypass   | t02 at na.com    | Jane       | Doe       |      1
+      3 | test03   | mypass   | t03 at na.com    | No         | Go        |      0
+    (3 rows)
+
+
+=item *
+
+Modify C<set_hashed_passwords.pl> to match the following (the only difference
+is the C<connect> line):
+
+    #!/usr/bin/perl
+    
+    use strict;
+    use warnings;
+    
+    use MyApp::Schema;
+    
+    my $schema = MyApp::Schema->connect('dbi:Pg:dbname=catappdb', 'catappuser', 'catalyst');
+    
+    my @users = $schema->resultset('Users')->all;
+    
+    foreach my $user (@users) {
+        $user->password('mypass');
+        $user->update;
+    }
+
+Run the C<set_hashed_passwords.pl> as per the "normal" flow of the 
+tutorial:
+
+    $ perl -Ilib set_hashed_passwords.pl
+
+You can verify that it worked with this command:
+
+    $ psql -U catappuser -W catappdb -c "select * from users"
+
+
+=back
+
+=back
+
+
+=head2 MySQL
+
+B<NOTE:> This section is out of data with the rest of the tutorial.
+Consider using SQLite or PostgreSQL since they are current.
+
+Use the following steps to adapt the tutorial to MySQL.  Thanks to Jim
+Howard for the help.
+
+=over 4
+
+=item *
+
+Chapter 3: Catalyst Basics
+
+=over 4
+
+=item *
+
+Install the required software:
+
+=over 4
+
+=item *
+
+The MySQL database server and client utility.
+
+=item *
+
+The Perl C<DBD::MySQL> module
+
+=back
+
+For CentOS users (see
+L<Catalyst::Manual::Installation::CentOS4|Catalyst::Manual::Installation::CentOS4>),
+you can use the following commands to install the software and start the MySQL
+daemon:
+
+    yum -y install mysql mysql-server
+    service mysqld start
+
+=item *
+
+Create the database and set the permissions:
+
+    $ mysql
+    Welcome to the MySQL monitor.  Commands end with ; or \g.
+    Your MySQL connection id is 2 to server version: 4.1.20
+    
+    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
+    
+    mysql> create database myapp;
+    Query OK, 1 row affected (0.01 sec)
+    
+    mysql> grant all on myapp.* to tutorial@'localhost';
+    Query OK, 0 rows affected (0.00 sec)
+    
+    mysql> flush privileges;
+    Query OK, 0 rows affected (0.00 sec)
+    
+    mysql> quit
+    Bye
+
+=item *
+
+Create the C<.sql> file and load the data:
+
+=over 4
+
+=item *
+
+Open the C<myapp01_mysql.sql> in your editor and enter:
+
+    --
+    -- Create a very simple database to hold book and author information
+    --
+    DROP TABLE IF EXISTS books;
+    DROP TABLE IF EXISTS book_authors;
+    DROP TABLE IF EXISTS authors;
+    CREATE TABLE books (
+           id          INT(11) PRIMARY KEY AUTO_INCREMENT,
+           title       TEXT ,
+           rating      INT(11)
+    );
+    -- 'book_authors' is a many-to-many join table between books & authors
+    CREATE TABLE book_authors (
+           book_id     INT(11),
+           author_id   INT(11),
+           PRIMARY KEY (book_id, author_id)
+    );
+    CREATE TABLE authors (
+           id          INT(11) PRIMARY KEY AUTO_INCREMENT,
+           first_name  TEXT,
+           last_name   TEXT
+    );
+    ---
+    --- Load some sample data
+    ---
+    INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
+    INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
+    INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
+    INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
+    INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
+    INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
+    INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
+    INSERT INTO authors VALUES (3, 'Christian', 'Degu');
+    INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
+    INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
+    INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
+    INSERT INTO authors VALUES (7, ' Nathan', 'Torkington');
+    INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
+    INSERT INTO book_authors VALUES (1, 1);
+    INSERT INTO book_authors VALUES (1, 2);
+    INSERT INTO book_authors VALUES (1, 3);
+    INSERT INTO book_authors VALUES (2, 4);
+    INSERT INTO book_authors VALUES (3, 5);
+    INSERT INTO book_authors VALUES (4, 6);
+    INSERT INTO book_authors VALUES (4, 7);
+    INSERT INTO book_authors VALUES (5, 8);
+
+=item *
+
+Load the data:
+
+    mysql -ututorial myapp < myapp01_mysql.sql
+
+=item *
+
+Make sure the data loaded correctly:
+
+    $ mysql -ututorial myapp
+    Reading table information for completion of table and column names
+    You can turn off this feature to get a quicker startup with -A
+    
+    Welcome to the MySQL monitor.  Commands end with ; or \g.
+    Your MySQL connection id is 4 to server version: 4.1.20
+    
+    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
+    
+    mysql> show tables;
+    +-----------------+
+    | Tables_in_myapp |
+    +-----------------+
+    | authors         |
+    | book_authors    |
+    | books           |
+    +-----------------+
+    3 rows in set (0.00 sec)
+    
+    mysql> select * from books;
+    +----+------------------------------------+--------+
+    | id | title                              | rating |
+    +----+------------------------------------+--------+
+    |  1 | CCSP SNRS Exam Certification Guide |      5 |
+    |  2 | TCP/IP Illustrated, Volume 1       |      5 |
+    |  3 | Internetworking with TCP/IP Vol.1  |      4 |
+    |  4 | Perl Cookbook                      |      5 |
+    |  5 | Designing with Web Standards       |      5 |
+    +----+------------------------------------+--------+
+    5 rows in set (0.00 sec)
+    
+    mysql>
+
+=back
+
+=item *
+
+Update the model:
+
+=over 4
+
+=item *
+
+Delete the existing model:
+
+    rm lib/MyApp/Model/MyAppDB.pm
+
+=item *
+
+Regenerate the model using the Catalyst "_create.pl" script:
+
+    script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
+        dbi:mysql:myapp '_username_here_' '_password_here_' '{ AutoCommit => 1 }'
+
+=back
+
+=back
+
+=item *
+
+Chapter 5: Authentication
+
+=over 4
+
+=item *
+
+Create the C<.sql> file for the user/roles data:
+
+Open C<myapp02_mysql.sql> in your editor and enter:
+
+    --
+    -- Add users and roles tables, along with a many-to-many join table
+    --
+    CREATE TABLE users (
+            id            INT(11) PRIMARY KEY,
+            username      TEXT,
+            password      TEXT,
+            email_address TEXT,
+            first_name    TEXT,
+            last_name     TEXT,
+            active        INT(11)
+    );
+    CREATE TABLE roles (
+            id   INTEGER PRIMARY KEY,
+            role TEXT
+    );
+    CREATE TABLE user_roles (
+            user_id INT(11),
+            role_id INT(11),
+            PRIMARY KEY (user_id, role_id)
+    );
+    --
+    -- Load up some initial test data
+    --
+    INSERT INTO users VALUES (1, 'test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
+    INSERT INTO users VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
+    INSERT INTO users VALUES (3, 'test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
+    INSERT INTO roles VALUES (1, 'user');
+    INSERT INTO roles VALUES (2, 'admin');
+    INSERT INTO user_roles VALUES (1, 1);
+    INSERT INTO user_roles VALUES (1, 2);
+    INSERT INTO user_roles VALUES (2, 1);
+    INSERT INTO user_roles VALUES (3, 1);
+
+=item *
+
+Load the user/roles data:
+
+    mysql -ututorial myapp < myapp02_mysql.sql
+
+=item *
+
+Create the C<.sql> file for the hashed password data:
+
+Open C<myapp03_mysql.sql> in your editor and enter:
+
+    --
+    -- Convert passwords to SHA-1 hashes
+    --
+    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 1;
+    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 2;
+    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 3;
+
+=item *
+
+Load the user/roles data:
+
+    mysql -ututorial myapp < myapp03_mysql.sql
+
+=back
+
+=back
+
+
+=head1 AUTHOR
+
+Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
+
+Copyright 2006-2008, Kennedy Clark, under Creative Commons License
+(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,99 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::AdvancedCRUD - Catalyst Tutorial - Chapter 9: Advanced CRUD
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 9 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-B<Advanced CRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This chapter of the tutorial explores more advanced functionality for
-Create, Read, Update, and Delete (CRUD) than we saw in Chapter 4.  In
-particular, it looks at a number of techniques that can be useful for
-the Update portion of CRUD, such as automated form generation,
-validation of user-entered data, and automated transfer of data between
-forms and model objects.
-
-In keeping with the Catalyst (and Perl) spirit of flexibility, there are 
-many different ways to approach advanced CRUD operations in a Catalyst 
-environment.  Therefore, this section of the tutorial allows you to pick 
-from one of several modules that that cover different form management 
-tools.  Select one or more options from the list below.
-
-=head1 ADVANCED CRUD OPTIONS
-
-=over 4
-
-=item *
-
-L<FormFu|Catalyst::Manual::Tutorial::AdvancedCRUD::FormFu>
-
-=item *
-
-L<FormBuilder|Catalyst::Manual::Tutorial::AdvancedCRUD::FormBuilder>
-
-=back
-
-B<NOTE:> Please contact the author if you would like to assist with 
-writing a new module.
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Appendices.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Appendices.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Appendices.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,784 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::Appendices - Catalyst Tutorial - Chapter 10: Appendices
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 10 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-B<Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This chapter of the tutorial provides supporting information relevant to
-the Catalyst tutorial.
-
-
-=head1 APPENDIX 1: CUT AND PASTE FOR POD-BASED EXAMPLES
-
-You may notice that Pod indents example code with four spaces.  This
-section provides some quick advice to "un-indent" this text in common
-editors.
-
-=head2 "Un-indenting" with Vi/Vim
-
-When cutting and pasting multi-line text from Pod-based documents, the
-following vi/vim regexs can be helpful to "un-indent" the inserted text
-(do NOT type the quotes, they are only included to show spaces in the
-regex patterns).  I<Note that all 3 of the regexs end in 4 spaces>:
-
-=over 4
-
-=item *
-
-":0,$s/^    "
-
-Removes four leading spaces from the entire file (from the first line,
-C<0>, to the last line, C<$>).
-
-=item *
-
-"%s/^    "
-
-A shortcut for the previous item (C<%> specifies the entire file; so
-this removes four leading spaces from every line).
-
-=item *
-
-":.,$s/^    "
-
-Removes the first four spaces from the line the cursor is on at the time
-the regex command is executed (".") to the last line of the file.
-
-=item *
-
-":.,44s/^    "
-
-Removes four leading space from the current line through line 44
-(obviously adjust the C<44> to the appropriate value in your example).
-
-=back
-
-=head2 "Un-indenting" with Emacs
-
-Although the author has not used Emacs for many years (apologies to
-the Emacs fans out there), here is a quick hint to get you started.  To
-replace the leading spaces of every line in a file, use:
-
-    M-x replace-regexp<RET>
-    Replace regexp: ^    <RET>
-    with: <RET>
-
-All of that will occur on the single line at the bottom of your screen.
-Note that "<RET>" represents the return key/enter.  Also, there are
-four spaces after the "^" on the "Replace regexp:" line and no spaces
-entered on the last line.
-
-You can limit the replacement operation by selecting text first (depending
-on your version of Emacs, you can either use the mouse or experiment with
-commands such as C<C-SPC> to set the mark at the cursor location and
-C<C-E<lt>> and C<C-E<gt>> to set the mark at the beginning and end of the
-file respectively.
-
-Also, Stefan Kangas sent in the following tip about an alternate 
-approach using the command C<indent-region> to redo the indentation 
-for the currently selected region (adhering to indent rules in the 
-current major mode). You can run the command by typing M-x indent-
-region or pressing the default keybinding C-M-\ in cperl-mode. 
-Additional details can be found here:
-
-L<http://www.gnu.org/software/emacs/manual/html_node/emacs/Indentation-Comman>
-
-
-=head1 APPENDIX 2: USING POSTGRESQL AND MYSQL
-
-The main database used in this tutorial is the very simple yet powerful
-SQLite.  This section provides information that can be used to "convert"
-the tutorial to use PostgreSQL and MySQL.  However, note that part of
-the beauty of the MVC architecture is that very little database-specific
-code is spread throughout the system (at least when MVC is "done
-right").  Consequently, converting from one database to another is
-relatively painless with most Catalyst applications.  In general, you
-just need to adapt the schema definition C<.sql> file you use to
-initialize your database and adjust a few configuration parameters.
-
-Also note that the purpose of the data definition statements for this
-section are not designed to take maximum advantage of the various
-features in each database for issues such as referential integrity and
-field types/constraints.
-
-
-=head2 PostgreSQL
-
-Use the following steps to adapt the tutorial to PostgreSQL.  Thanks 
-to Caelum (Rafael Kitover) for assistance with the most recent 
-updates, and Louis Moore, Marcello Romani and Tom Lanyon for help with 
-earlier versions.
-
-=over 4
-
-=item *
-
-Chapter 3: More Catalyst Basics
-
-=over 4
-
-=item *
-
-Install the PostgreSQL server and client and DBD::Pg:
-
-If you are following along in Debian 5, you can quickly install these 
-items via this command:
-
-    sudo aptitude install postgresql libdbd-pg-perl libdatetime-format-pg-perl
-
-To configure the permissions, you can open 
-C</etc/postgresql/8.3/main/pg_hba.conf> and change this line (near the 
-bottom):
-
-    # "local" is for Unix domain socket connections only
-    local   all         all                               ident sameuser
-
-to:
-
-    # "local" is for Unix domain socket connections only
-    local   all         all                               trust
-
-And then restart PostgreSQL:
-
-    sudo /etc/init.d/postgresql-8.3 restart
-
-
-=item *
-
-Create the database and a user for the database (note that we are 
-using "E<lt>catalystE<gt>" to represent the hidden password of 
-"catalyst"):
-
-    $ sudo -u postgres createuser -P catappuser
-    Enter password for new role: <catalyst>
-    Enter it again: <catalyst>
-    Shall the new role be a superuser? (y/n) n
-    Shall the new role be allowed to create databases? (y/n) n
-    Shall the new role be allowed to create more new roles? (y/n) n
-    CREATE ROLE
-    $ sudo -u postgres createdb -O catappuser catappdb
-    CREATE DATABASE
-
-=item *
-
-Create the C<.sql> file and load the data:
-
-=over 4
-
-=item *
-
-Open the C<myapp01_psql.sql> in your editor and enter:
-
-    --
-    -- Drops just in case you are reloading
-    ---
-    DROP TABLE IF EXISTS books CASCADE;
-    DROP TABLE IF EXISTS authors CASCADE;
-    DROP TABLE IF EXISTS book_authors CASCADE;
-    DROP TABLE IF EXISTS users CASCADE;
-    DROP TABLE IF EXISTS roles CASCADE;
-    DROP TABLE IF EXISTS user_roles CASCADE;
-    
-    --
-    -- Create a very simple database to hold book and author information
-    --
-    CREATE TABLE books (
-        id          SERIAL PRIMARY KEY,
-        title       TEXT ,
-        rating      INTEGER,
-        -- Manually add these later
-        -- created     TIMESTAMP NOT NULL DEFAULT now(),
-        -- updated     TIMESTAMP
-    );
-    
-    CREATE TABLE authors (
-        id          SERIAL PRIMARY KEY,
-        first_name  TEXT,
-        last_name   TEXT
-    );
-    
-    -- 'book_authors' is a many-to-many join table between books & authors
-    CREATE TABLE book_authors (
-        book_id     INTEGER REFERENCES books(id) ON DELETE CASCADE ON UPDATE CASCADE,
-        author_id   INTEGER REFERENCES authors(id) ON DELETE CASCADE ON UPDATE CASCADE,
-        PRIMARY KEY (book_id, author_id)
-    );
-    
-    ---
-    --- Load some sample data
-    ---
-    INSERT INTO books (title, rating) VALUES ('CCSP SNRS Exam Certification Guide', 5);
-    INSERT INTO books (title, rating) VALUES ('TCP/IP Illustrated, Volume 1', 5);
-    INSERT INTO books (title, rating) VALUES ('Internetworking with TCP/IP Vol.1', 4);
-    INSERT INTO books (title, rating) VALUES ('Perl Cookbook', 5);
-    INSERT INTO books (title, rating) VALUES ('Designing with Web Standards', 5);
-    INSERT INTO authors (first_name, last_name) VALUES ('Greg', 'Bastien');
-    INSERT INTO authors (first_name, last_name) VALUES ('Sara', 'Nasseh');
-    INSERT INTO authors (first_name, last_name) VALUES ('Christian', 'Degu');
-    INSERT INTO authors (first_name, last_name) VALUES ('Richard', 'Stevens');
-    INSERT INTO authors (first_name, last_name) VALUES ('Douglas', 'Comer');
-    INSERT INTO authors (first_name, last_name) VALUES ('Tom', 'Christiansen');
-    INSERT INTO authors (first_name, last_name) VALUES ('Nathan', 'Torkington');
-    INSERT INTO authors (first_name, last_name) VALUES ('Jeffrey', 'Zeldman');
-    INSERT INTO book_authors VALUES (1, 1);
-    INSERT INTO book_authors VALUES (1, 2);
-    INSERT INTO book_authors VALUES (1, 3);
-    INSERT INTO book_authors VALUES (2, 4);
-    INSERT INTO book_authors VALUES (3, 5);
-    INSERT INTO book_authors VALUES (4, 6);
-    INSERT INTO book_authors VALUES (4, 7);
-    INSERT INTO book_authors VALUES (5, 8);
-
-=item *
-
-Load the data:
-
-    $ psql -U catappuser -W catappdb -f myapp01_psql.sql
-    Password for user catappuser: 
-    psql:myapp01_psql.sql:8: NOTICE:  CREATE TABLE will create implicit sequence "books_id_seq" for serial column "books.id"
-    psql:myapp01_psql.sql:8: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "books_pkey" for table "books"
-    CREATE TABLE
-    psql:myapp01_psql.sql:15: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "book_authors_pkey" for table "book_authors"
-    CREATE TABLE
-    psql:myapp01_psql.sql:21: NOTICE:  CREATE TABLE will create implicit sequence "authors_id_seq" for serial column "authors.id"
-    psql:myapp01_psql.sql:21: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "authors_pkey" for table "authors"
-    CREATE TABLE
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    ...
-
-=item *
-
-Make sure the data loaded correctly:
-
-    $ psql -U catappuser -W catappdb
-    Password for user catappuser: <catalyst>
-    Welcome to psql 8.3.7, the PostgreSQL interactive terminal.
-    
-    Type:  \copyright for distribution terms
-           \h for help with SQL commands
-           \? for help with psql commands
-           \g or terminate with semicolon to execute query
-           \q to quit
-    
-    catappdb=> \dt
-                 List of relations
-     Schema |     Name     | Type  |   Owner    
-    --------+--------------+-------+------------
-     public | authors      | table | catappuser
-     public | book_authors | table | catappuser
-     public | books        | table | catappuser
-    (3 rows)
-    
-    catappdb=> select * from books;
-     id |               title                | rating 
-    ----+------------------------------------+--------
-      1 | CCSP SNRS Exam Certification Guide |      5
-      2 | TCP/IP Illustrated, Volume 1       |      5
-      3 | Internetworking with TCP/IP Vol.1  |      4
-      4 | Perl Cookbook                      |      5
-      5 | Designing with Web Standards       |      5
-    (5 rows)
-    
-    catappdb=> 
-
-=back
-
-=item *
-
-After the steps where you:
-
-    edit lib/MyApp.pm
-    
-    create lib/MyAppDB.pm
-    
-    create lib/MyAppDB/Book.pm
-    
-    create lib/MyAppDB/Author.pm
-    
-    create lib/MyAppDB/BookAuthor.pm
-
-
-=item *
-
-Generate the model using the Catalyst "_create.pl" script:
-
-    $ rm lib/MyApp/Model/DB.pm   # Delete just in case already there
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp,EncodedColumn \
-        'dbi:Pg:dbname=catappdb' 'catappuser' 'catalyst' '{ AutoCommit => 1 }'
-
-=back
-
-=item *
-
-Chapter 4: Basic CRUD
-
-Add Datetime Columns to Our Existing Books Table
-
-    $ psql -U catappuser -W catappdb
-    ...
-    catappdb=> ALTER TABLE books ADD created TIMESTAMP NOT NULL DEFAULT now();
-    ALTER TABLE
-    catappdb=> ALTER TABLE books ADD updated TIMESTAMP;
-    ALTER TABLE
-    catappdb=> \q
-
-Re-generate the model using the Catalyst "_create.pl" script:
-
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp,EncodedColumn \
-        'dbi:Pg:dbname=catappdb' 'catappuser' 'catalyst' '{ AutoCommit => 1 }'
-
-
-=item *
-
-Chapter 5: Authentication
-
-=over 4
-
-=item *
-
-Create the C<.sql> file for the user/roles data:
-
-Open C<myapp02_psql.sql> in your editor and enter:
-
-    --
-    -- Add users and roles tables, along with a many-to-many join table
-    --
-    
-    CREATE TABLE users (
-        id            SERIAL PRIMARY KEY,
-        username      TEXT,
-        password      TEXT,
-        email_address TEXT,
-        first_name    TEXT,
-        last_name     TEXT,
-        active        INTEGER
-    );
-    
-    CREATE TABLE roles (
-        id   SERIAL PRIMARY KEY,
-        role TEXT
-    );
-    
-    CREATE TABLE user_roles (
-        user_id INTEGER REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE,
-        role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE ON UPDATE CASCADE,
-        PRIMARY KEY (user_id, role_id)
-    );
-    
-    --
-    -- Load up some initial test data
-    --
-    INSERT INTO users (username, password, email_address, first_name, last_name, active) 
-        VALUES ('test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
-    INSERT INTO users (username, password, email_address, first_name, last_name, active) 
-        VALUES ('test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
-    INSERT INTO users (username, password, email_address, first_name, last_name, active)
-        VALUES ('test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
-    INSERT INTO roles (role) VALUES ('user');
-    INSERT INTO roles (role) VALUES ('admin');
-    INSERT INTO user_roles VALUES (1, 1);
-    INSERT INTO user_roles VALUES (1, 2);
-    INSERT INTO user_roles VALUES (2, 1);
-    INSERT INTO user_roles VALUES (3, 1);
-
-=item *
-
-Load the data:
-
-    $ psql -U catappuser -W catappdb -f myapp02_psql.sql
-    Password for user catappuser: <catalyst>
-    psql:myapp02_psql.sql:13: NOTICE:  CREATE TABLE will create implicit sequence "users_id_seq" for serial column "users.id"
-    psql:myapp02_psql.sql:13: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "users_pkey" for table "users"
-    CREATE TABLE
-    psql:myapp02_psql.sql:18: NOTICE:  CREATE TABLE will create implicit sequence "roles_id_seq" for serial column "roles.id"
-    psql:myapp02_psql.sql:18: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "roles_pkey" for table "roles"
-    CREATE TABLE
-    psql:myapp02_psql.sql:24: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "user_roles_pkey" for table "user_roles"
-    CREATE TABLE
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-    INSERT 0 1
-
-Confirm with:
-
-    $ psql -U catappuser -W catappdb -c "select * from users"
-    Password for user catappuser: <catalyst>
-     id | username | password | email_address | first_name | last_name | active 
-    ----+----------+----------+---------------+------------+-----------+--------
-      1 | test01   | mypass   | t01 at na.com    | Joe        | Blow      |      1
-      2 | test02   | mypass   | t02 at na.com    | Jane       | Doe       |      1
-      3 | test03   | mypass   | t03 at na.com    | No         | Go        |      0
-    (3 rows)
-
-
-=item *
-
-Modify C<set_hashed_passwords.pl> to match the following (the only difference
-is the C<connect> line):
-
-    #!/usr/bin/perl
-    
-    use strict;
-    use warnings;
-    
-    use MyApp::Schema;
-    
-    my $schema = MyApp::Schema->connect('dbi:Pg:dbname=catappdb', 'catappuser', 'catalyst');
-    
-    my @users = $schema->resultset('Users')->all;
-    
-    foreach my $user (@users) {
-        $user->password('mypass');
-        $user->update;
-    }
-
-Run the C<set_hashed_passwords.pl> as per the "normal" flow of the 
-tutorial:
-
-    $ perl -Ilib set_hashed_passwords.pl
-
-You can verify that it worked with this command:
-
-    $ psql -U catappuser -W catappdb -c "select * from users"
-
-
-=back
-
-=back
-
-
-=head2 MySQL
-
-B<NOTE:> This section is out of data with the rest of the tutorial.
-Consider using SQLite or PostgreSQL since they are current.
-
-Use the following steps to adapt the tutorial to MySQL.  Thanks to Jim
-Howard for the help.
-
-=over 4
-
-=item *
-
-Chapter 3: Catalyst Basics
-
-=over 4
-
-=item *
-
-Install the required software:
-
-=over 4
-
-=item *
-
-The MySQL database server and client utility.
-
-=item *
-
-The Perl C<DBD::MySQL> module
-
-=back
-
-For CentOS users (see
-L<Catalyst::Manual::Installation::CentOS4|Catalyst::Manual::Installation::CentOS4>),
-you can use the following commands to install the software and start the MySQL
-daemon:
-
-    yum -y install mysql mysql-server
-    service mysqld start
-
-=item *
-
-Create the database and set the permissions:
-
-    $ mysql
-    Welcome to the MySQL monitor.  Commands end with ; or \g.
-    Your MySQL connection id is 2 to server version: 4.1.20
-    
-    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
-    
-    mysql> create database myapp;
-    Query OK, 1 row affected (0.01 sec)
-    
-    mysql> grant all on myapp.* to tutorial@'localhost';
-    Query OK, 0 rows affected (0.00 sec)
-    
-    mysql> flush privileges;
-    Query OK, 0 rows affected (0.00 sec)
-    
-    mysql> quit
-    Bye
-
-=item *
-
-Create the C<.sql> file and load the data:
-
-=over 4
-
-=item *
-
-Open the C<myapp01_mysql.sql> in your editor and enter:
-
-    --
-    -- Create a very simple database to hold book and author information
-    --
-    DROP TABLE IF EXISTS books;
-    DROP TABLE IF EXISTS book_authors;
-    DROP TABLE IF EXISTS authors;
-    CREATE TABLE books (
-           id          INT(11) PRIMARY KEY AUTO_INCREMENT,
-           title       TEXT ,
-           rating      INT(11)
-    );
-    -- 'book_authors' is a many-to-many join table between books & authors
-    CREATE TABLE book_authors (
-           book_id     INT(11),
-           author_id   INT(11),
-           PRIMARY KEY (book_id, author_id)
-    );
-    CREATE TABLE authors (
-           id          INT(11) PRIMARY KEY AUTO_INCREMENT,
-           first_name  TEXT,
-           last_name   TEXT
-    );
-    ---
-    --- Load some sample data
-    ---
-    INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
-    INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
-    INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
-    INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
-    INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
-    INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
-    INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
-    INSERT INTO authors VALUES (3, 'Christian', 'Degu');
-    INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
-    INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
-    INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
-    INSERT INTO authors VALUES (7, ' Nathan', 'Torkington');
-    INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
-    INSERT INTO book_authors VALUES (1, 1);
-    INSERT INTO book_authors VALUES (1, 2);
-    INSERT INTO book_authors VALUES (1, 3);
-    INSERT INTO book_authors VALUES (2, 4);
-    INSERT INTO book_authors VALUES (3, 5);
-    INSERT INTO book_authors VALUES (4, 6);
-    INSERT INTO book_authors VALUES (4, 7);
-    INSERT INTO book_authors VALUES (5, 8);
-
-=item *
-
-Load the data:
-
-    mysql -ututorial myapp < myapp01_mysql.sql
-
-=item *
-
-Make sure the data loaded correctly:
-
-    $ mysql -ututorial myapp
-    Reading table information for completion of table and column names
-    You can turn off this feature to get a quicker startup with -A
-    
-    Welcome to the MySQL monitor.  Commands end with ; or \g.
-    Your MySQL connection id is 4 to server version: 4.1.20
-    
-    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
-    
-    mysql> show tables;
-    +-----------------+
-    | Tables_in_myapp |
-    +-----------------+
-    | authors         |
-    | book_authors    |
-    | books           |
-    +-----------------+
-    3 rows in set (0.00 sec)
-    
-    mysql> select * from books;
-    +----+------------------------------------+--------+
-    | id | title                              | rating |
-    +----+------------------------------------+--------+
-    |  1 | CCSP SNRS Exam Certification Guide |      5 |
-    |  2 | TCP/IP Illustrated, Volume 1       |      5 |
-    |  3 | Internetworking with TCP/IP Vol.1  |      4 |
-    |  4 | Perl Cookbook                      |      5 |
-    |  5 | Designing with Web Standards       |      5 |
-    +----+------------------------------------+--------+
-    5 rows in set (0.00 sec)
-    
-    mysql>
-
-=back
-
-=item *
-
-Update the model:
-
-=over 4
-
-=item *
-
-Delete the existing model:
-
-    rm lib/MyApp/Model/MyAppDB.pm
-
-=item *
-
-Regenerate the model using the Catalyst "_create.pl" script:
-
-    script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        dbi:mysql:myapp '_username_here_' '_password_here_' '{ AutoCommit => 1 }'
-
-=back
-
-=back
-
-=item *
-
-Chapter 5: Authentication
-
-=over 4
-
-=item *
-
-Create the C<.sql> file for the user/roles data:
-
-Open C<myapp02_mysql.sql> in your editor and enter:
-
-    --
-    -- Add users and roles tables, along with a many-to-many join table
-    --
-    CREATE TABLE users (
-            id            INT(11) PRIMARY KEY,
-            username      TEXT,
-            password      TEXT,
-            email_address TEXT,
-            first_name    TEXT,
-            last_name     TEXT,
-            active        INT(11)
-    );
-    CREATE TABLE roles (
-            id   INTEGER PRIMARY KEY,
-            role TEXT
-    );
-    CREATE TABLE user_roles (
-            user_id INT(11),
-            role_id INT(11),
-            PRIMARY KEY (user_id, role_id)
-    );
-    --
-    -- Load up some initial test data
-    --
-    INSERT INTO users VALUES (1, 'test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
-    INSERT INTO users VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
-    INSERT INTO users VALUES (3, 'test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
-    INSERT INTO roles VALUES (1, 'user');
-    INSERT INTO roles VALUES (2, 'admin');
-    INSERT INTO user_roles VALUES (1, 1);
-    INSERT INTO user_roles VALUES (1, 2);
-    INSERT INTO user_roles VALUES (2, 1);
-    INSERT INTO user_roles VALUES (3, 1);
-
-=item *
-
-Load the user/roles data:
-
-    mysql -ututorial myapp < myapp02_mysql.sql
-
-=item *
-
-Create the C<.sql> file for the hashed password data:
-
-Open C<myapp03_mysql.sql> in your editor and enter:
-
-    --
-    -- Convert passwords to SHA-1 hashes
-    --
-    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 1;
-    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 2;
-    UPDATE users SET password = 'e727d1464ae12436e899a726da5b2f11d8381b26' WHERE id = 3;
-
-=item *
-
-Load the user/roles data:
-
-    mysql -ututorial myapp < myapp03_mysql.sql
-
-=back
-
-=back
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authentication.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,916 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::Authentication - Catalyst Tutorial - Chapter 5: Authentication
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 5 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-B<Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-Now that we finally have a simple yet functional application, we can
-focus on providing authentication (with authorization coming next in
-Chapter 6).
-
-This chapter of the tutorial is divided into two main sections: 1) basic,
-cleartext authentication and 2) hash-based authentication.
-
-You can checkout the source code for this example from the catalyst
-subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
-
-
-=head1 BASIC AUTHENTICATION
-
-This section explores how to add authentication logic to a Catalyst
-application.
-
-
-=head2 Add Users and Roles to the Database
-
-First, we add both user and role information to the database (we will
-add the role information here although it will not be used until the
-authorization section, Chapter 6).  Create a new SQL script file by opening
-C<myapp02.sql> in your editor and insert:
-
-    --
-    -- Add user and role tables, along with a many-to-many join table
-    --
-    CREATE TABLE user (
-            id            INTEGER PRIMARY KEY,
-            username      TEXT,
-            password      TEXT,
-            email_address TEXT,
-            first_name    TEXT,
-            last_name     TEXT,
-            active        INTEGER
-    );
-    CREATE TABLE role (
-            id   INTEGER PRIMARY KEY,
-            role TEXT
-    );
-    CREATE TABLE user_role (
-            user_id INTEGER,
-            role_id INTEGER,
-            PRIMARY KEY (user_id, role_id)
-    );
-    --
-    -- Load up some initial test data
-    --
-    INSERT INTO user VALUES (1, 'test01', 'mypass', 't01 at na.com', 'Joe',  'Blow', 1);
-    INSERT INTO user VALUES (2, 'test02', 'mypass', 't02 at na.com', 'Jane', 'Doe',  1);
-    INSERT INTO user VALUES (3, 'test03', 'mypass', 't03 at na.com', 'No',   'Go',   0);
-    INSERT INTO role VALUES (1, 'user');
-    INSERT INTO role VALUES (2, 'admin');
-    INSERT INTO user_role VALUES (1, 1);
-    INSERT INTO user_role VALUES (1, 2);
-    INSERT INTO user_role VALUES (2, 1);
-    INSERT INTO user_role VALUES (3, 1);
-
-Then load this into the C<myapp.db> database with the following command:
-
-    $ sqlite3 myapp.db < myapp02.sql
-
-=head2 Add User and Role Information to DBIC Schema
-
-Although we could manually edit the DBIC schema information to include
-the new tables added in the previous step, let's use the C<create=static>
-option on the DBIC model helper to do most of the work for us:
-
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
-     exists "/root/dev/MyApp/script/../lib/MyApp/Model"
-     exists "/root/dev/MyApp/script/../t"
-    Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
-    Schema dump completed.
-     exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
-    $
-    $ ls lib/MyApp/Schema/Result
-    Author.pm  BookAuthor.pm  Book.pm  Role.pm  User.pm  UserRole.pm
-
-Notice how the helper has added three new table-specific result source
-files to the C<lib/MyApp/Schema/Result> directory.  And, more
-importantly, even if there were changes to the existing result source
-files, those changes would have only been written above the C<# DO NOT
-MODIFY THIS OR ANYTHING ABOVE!> comment and your hand-edited
-enhancements would have been preserved.
-
-Speaking of "hand-editted enhancements," we should now add
-relationship information to the three new result source files.  Edit
-each of these files and add the following information between the C<#
-DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment and the closing C<1;>:
-
-C<lib/MyApp/Schema/Result/User.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRole', 'user_id');
-    
-    # many_to_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of has_many() relationship this many_to_many() is shortcut for
-    #     3) Name of belongs_to() relationship in model class of has_many() above
-    #   You must already have the has_many() defined to use a many_to_many().
-    __PACKAGE__->many_to_many(roles => 'map_user_role', 'role');
-
-
-C<lib/MyApp/Schema/Result/Role.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(map_user_role => 'MyApp::Schema::Result::UserRole', 'role_id');
-
-
-C<lib/MyApp/Schema/Result/UserRole.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(user => 'MyApp::Schema::Result::User', 'user_id');
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(role => 'MyApp::Schema::Result::Role', 'role_id');
-
-The code for these three sets of updates is obviously very similar to
-the edits we made to the C<Book>, C<Author>, and C<BookAuthor>
-classes created in Chapter 3.
-
-Note that we do not need to make any change to the
-C<lib/MyApp/Schema.pm> schema file.  It simply tells DBIC to load all
-of the Result Class and ResultSet Class files it finds in below the
-C<lib/MyApp/Schema> directory, so it will automatically pick up our
-new table information.
-
-
-=head2 Sanity-Check Reload of Development Server
-
-We aren't ready to try out the authentication just yet; we only want
-to do a quick check to be sure our model loads correctly.  Press
-C<Ctrl-C> to kill the previous server instance (if it's still running)
-and restart it:
-
-    $ script/myapp_server.pl
-
-Look for the three new model objects in the startup debug output:
-
-    ...
-     .-------------------------------------------------------------------+----------.
-    | Class                                                             | Type     |
-    +-------------------------------------------------------------------+----------+
-    | MyApp::Controller::Books                                          | instance |
-    | MyApp::Controller::Root                                           | instance |
-    | MyApp::Model::DB                                                  | instance |
-    | MyApp::Model::DB::Author                                          | class    |
-    | MyApp::Model::DB::Book                                            | class    |
-    | MyApp::Model::DB::BookAuthor                                      | class    |
-    | MyApp::Model::DB::Role                                            | class    |
-    | MyApp::Model::DB::User                                            | class    |
-    | MyApp::Model::DB::UserRole                                        | class    |
-    | MyApp::View::TT                                                   | instance |
-    '-------------------------------------------------------------------+----------'
-    ...
-
-Again, notice that your "Result Class" classes have been "re-loaded"
-by Catalyst under C<MyApp::Model>.
-
-
-=head2 Include Authentication and Session Plugins
-
-Edit C<lib/MyApp.pm> and update it as follows (everything below
-C<StackTrace> is new):
-
-    # Load plugins
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple
-    
-                    StackTrace
-    
-                    Authentication
-    
-                    Session
-                    Session::Store::FastMmap
-                    Session::State::Cookie
-                    /;
-
-B<Note:> As discussed in MoreCatalystBasics, different versions of
-C<Catalyst::Devel> have used a variety of methods to load the plugins.
-You can put the plugins in the C<use Catalyst> statement if you prefer.
-
-The C<Authentication> plugin supports Authentication while the
-C<Session> plugins are required to maintain state across multiple HTTP
-requests.
-
-Note that the only required Authentication class is the main one. This
-is a change that occurred in version 0.09999_01 of the
-C<Authentication> plugin. You B<do not need> to specify a particular
-Authentication::Store or Authentication::Credential plugin. Instead,
-indicate the Store and Credential you want to use in your application
-configuration (see below).
-
-Make sure you include the additional plugins as new dependencies in
-the Makefile.PL file something like this:
-
-    requires (
-        'Catalyst::Plugin::Authentication' => '0',
-        'Catalyst::Plugin::Session' => '0',
-        'Catalyst::Plugin::Session::Store::FastMmap' => '0',
-        'Catalyst::Plugin::Session::State::Cookie' => '0',
-    );
-
-Note that there are several options for
-L<Session::Store|Catalyst::Plugin::Session::Store>
-(L<Session::Store::FastMmap|Catalyst::Plugin::Session::Store::FastMmap>
-is generally a good choice if you are on Unix; try
-L<Session::Store::File|Catalyst::Plugin::Session::Store::File> if you
-are on Win32) -- consult
-L<Session::Store|Catalyst::Plugin::Session::Store> and its subclasses
-for additional information and options (for example to use a database-
-backed session store).
-
-
-=head2 Configure Authentication
-
-There are a variety of ways to provide configuration information to
-L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>.
-Here we will use 
-L<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
-because it automatically sets a reasonable set of defaults for us. Open 
-C<lib/MyApp.pm> and place the following text above the call to
-C<__PACKAGE__-E<gt>setup();>:
-
-    # Configure SimpleDB Authentication
-    __PACKAGE__->config->{'Plugin::Authentication'} = {
-            default => {
-                class           => 'SimpleDB',
-                user_model      => 'DB::User',
-                password_type   => 'clear',
-            },
-        };
-
-We could have placed this configuration in C<myapp.conf>, but placing 
-it in C<lib/MyApp.pm> is probably a better place since it's not likely 
-something that users of your application will want to change during 
-deployment (or you could use a mixture: leave C<class> and 
-C<user_model> defined in C<lib/MyApp.pm> as we show above, but place 
-C<password_type> in C<myapp.conf> to allow the type of password to be 
-easily modified during deployment).  We will stick with putting 
-all of the authentication-related configuration in C<lib/MyApp.pm> 
-for the tutorial, but if you wish to use C<myapp.conf>, just convert
-to the following code:
-
-    <Plugin::Authentication>
-        use_session 1
-        <default>
-            password_type self_check
-            user_model    DB::User
-            class         SimpleDB
-        </default>
-    </Plugin::Authentication>
-
-B<TIP:> Here is a short script that will dump the contents of 
-C<MyApp->config> to L<Config::General|Config::General> format in
-C<myapp.conf>:
-
-    $ perl -Ilib -e 'use MyApp; use Config::General; 
-        Config::General->new->save_file("myapp.conf", MyApp->config);'
-
-B<NOTE:> Because we are using SimpleDB along with a database layout 
-that complies with its default assumptions, we don't need to specify
-the names of the columns where our username and password information
-is stored (hence, the "Simple" part of "SimpleDB").  That being said,
-SimpleDB lets you specify that type of information if you need to.
-Take a look at 
-C<Catalyst::Authentication::Realm::SimpleDB|Catalyst::Authentication::Realm::SimpleDB>
-for details.
-
-
-=head2 Add Login and Logout Controllers
-
-Use the Catalyst create script to create two stub controller files:
-
-    $ script/myapp_create.pl controller Login
-    $ script/myapp_create.pl controller Logout
-
-You could easily use a single controller here.  For example, you could
-have a C<User> controller with both C<login> and C<logout> actions.
-Remember, Catalyst is designed to be very flexible, and leaves such
-matters up to you, the designer and programmer.
-
-Then open C<lib/MyApp/Controller/Login.pm>, locate the
-C<sub index :Path :Args(0)> method (or C<sub index : Private> if you
-are using an older version of Catalyst) that was automatically
-inserted by the helpers when we created the Login controller above,
-and update the definition of C<sub index> to match:
-
-    =head2 index
-    
-    Login logic
-    
-    =cut
-    
-    sub index :Path :Args(0) {
-        my ($self, $c) = @_;
-    
-        # Get the username and password from form
-        my $username = $c->request->params->{username} || "";
-        my $password = $c->request->params->{password} || "";
-    
-        # If the username and password values were found in form
-        if ($username && $password) {
-            # Attempt to log the user in
-            if ($c->authenticate({ username => $username,
-                                   password => $password  } )) {
-                # If successful, then let them use the application
-                $c->response->redirect($c->uri_for(
-                    $c->controller('Books')->action_for('list')));
-                return;
-            } else {
-                # Set an error message
-                $c->stash->{error_msg} = "Bad username or password.";
-            }
-        }
-    
-        # If either of above don't work out, send to the login page
-        $c->stash->{template} = 'login.tt2';
-    }
-
-Be sure to remove the C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Login in Login.');>
-line of the C<sub index>.
-
-This controller fetches the C<username> and C<password> values from the
-login form and attempts to authenticate the user.  If successful, it
-redirects the user to the book list page.  If the login fails, the user
-will stay at the login page and receive an error message.  If the
-C<username> and C<password> values are not present in the form, the
-user will be taken to the empty login form.
-
-Note that we could have used something like "C<sub default :Path>",
-however, it is generally recommended (partly for historical reasons,
-and partly for code clarity) only to use C<default> in
-C<MyApp::Controller::Root>, and then mainly to generate the 404 not
-found page for the application.
-
-Instead, we are using "C<sub somename :Path :Args(0) {...}>" here to
-specifically match the URL C</login>. C<Path> actions (aka, "literal
-actions") create URI matches relative to the namespace of the
-controller where they are defined.  Although C<Path> supports
-arguments that allow relative and absolute paths to be defined, here
-we use an empty C<Path> definition to match on just the name of the
-controller itself.  The method name, C<index>, is arbitrary. We make
-the match even more specific with the C<:Args(0)> action modifier --
-this forces the match on I<only> C</login>, not
-C</login/somethingelse>.
-
-Next, update the corresponding method in
-C<lib/MyApp/Controller/Logout.pm> to match:
-
-    =head2 index
-    
-    Logout logic
-    
-    =cut
-    
-    sub index :Path :Args(0) {
-        my ($self, $c) = @_;
-    
-        # Clear the user's state
-        $c->logout;
-    
-        # Send the user to the starting point
-        $c->response->redirect($c->uri_for('/'));
-    }
-
-As with the login controller, be sure to delete the
-C<$c-E<gt>response-E<gt>body('Matched MyApp::Controller::Logout in Logout.');>
-line of the C<sub index>.
-
-
-=head2 Add a Login Form TT Template Page
-
-Create a login form by opening C<root/src/login.tt2> and inserting:
-
-    [% META title = 'Login' %]
-    
-    <!-- Login form -->
-    <form method="post" action="[% c.uri_for('/login') %]">
-      <table>
-        <tr>
-          <td>Username:</td>
-          <td><input type="text" name="username" size="40" /></td>
-        </tr>
-        <tr>
-          <td>Password:</td>
-          <td><input type="password" name="password" size="40" /></td>
-        </tr>
-        <tr>
-          <td colspan="2"><input type="submit" name="submit" value="Submit" /></td>
-        </tr>
-      </table>
-    </form>
-
-
-=head2 Add Valid User Check
-
-We need something that provides enforcement for the authentication
-mechanism -- a I<global> mechanism that prevents users who have not
-passed authentication from reaching any pages except the login page.
-This is generally done via an C<auto> action/method (prior to Catalyst
-v5.66, this sort of thing would go in C<MyApp.pm>, but starting in
-v5.66, the preferred location is C<lib/MyApp/Controller/Root.pm>).
-
-Edit the existing C<lib/MyApp/Controller/Root.pm> class file and insert
-the following method:
-
-    =head2 auto
-    
-    Check if there is a user and, if not, forward to login page
-    
-    =cut
-    
-    # Note that 'auto' runs after 'begin' but before your actions and that
-    # 'auto's "chain" (all from application path to most specific class are run)
-    # See the 'Actions' section of 'Catalyst::Manual::Intro' for more info.
-    sub auto : Private {
-        my ($self, $c) = @_;
-    
-        # Allow unauthenticated users to reach the login page.  This
-        # allows unauthenticated users to reach any action in the Login
-        # controller.  To lock it down to a single action, we could use:
-        #   if ($c->action eq $c->controller('Login')->action_for('index'))
-        # to only allow unauthenticated access to the 'index' action we
-        # added above.
-        if ($c->controller eq $c->controller('Login')) {
-            return 1;
-        }
-    
-        # If a user doesn't exist, force login
-        if (!$c->user_exists) {
-            # Dump a log message to the development server debug output
-            $c->log->debug('***Root::auto User not found, forwarding to /login');
-            # Redirect the user to the login page
-            $c->response->redirect($c->uri_for('/login'));
-            # Return 0 to cancel 'post-auto' processing and prevent use of application
-            return 0;
-        }
-    
-        # User found, so return 1 to continue with processing after this 'auto'
-        return 1;
-    }
-
-As discussed in
-L<Catalyst::Manual::Tutorial::MoreCatalystBasics/CREATE A CATALYST CONTROLLER>,
-every C<auto> method from the application/root controller down to the
-most specific controller will be called.  By placing the
-authentication enforcement code inside the C<auto> method of
-C<lib/MyApp/Controller/Root.pm> (or C<lib/MyApp.pm>), it will be
-called for I<every> request that is received by the entire
-application.
-
-
-=head2 Displaying Content Only to Authenticated Users
-
-Let's say you want to provide some information on the login page that
-changes depending on whether the user has authenticated yet.  To do
-this, open C<root/src/login.tt2> in your editor and add the following
-lines to the bottom of the file:
-
-    ...
-    <p>
-    [%
-       # This code illustrates how certain parts of the TT
-       # template will only be shown to users who have logged in
-    %]
-    [% IF c.user_exists %]
-        Please Note: You are already logged in as '[% c.user.username %]'.
-        You can <a href="[% c.uri_for('/logout') %]">logout</a> here.
-    [% ELSE %]
-        You need to log in to use this application.
-    [% END %]
-    [%#
-       Note that this whole block is a comment because the "#" appears
-       immediate after the "[%" (with no spaces in between).  Although it
-       can be a handy way to temporarily "comment out" a whole block of
-       TT code, it's probably a little too subtle for use in "normal"
-       comments.
-    %]
-    </p>
-
-Although most of the code is comments, the middle few lines provide a
-"you are already logged in" reminder if the user returns to the login
-page after they have already authenticated.  For users who have not yet
-authenticated, a "You need to log in..." message is displayed (note the
-use of an IF-THEN-ELSE construct in TT).
-
-
-=head2 Try Out Authentication
-
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-B<IMPORTANT NOTE:> If you are having issues with authentication on
-Internet Explorer, be sure to check the system clocks on both your
-server and client machines.  Internet Explorer is very picky about
-timestamps for cookies.  You can quickly sync a Debian system by
-installing the "ntpdate" package:
-
-    sudo aptitude -y install ntpdate
-
-And then run the following command:
-
-    sudo ntpdate-debian
-
-Or, depending on your firewall configuration:
-
-    sudo ntpdate-debian -u
-
-Note: NTP can be a little more finicky about firewalls because it uses
-UDP vs. the more common TCP that you see with most Internet protocols.
-Worse case, you might have to manually set the time on your development
-box instead of using NTP.
-
-Now trying going to L<http://localhost:3000/books/list> and you should
-be redirected to the login page, hitting Shift+Reload or Ctrl+Reload
-if necessary (the "You are already logged in" message should I<not>
-appear -- if it does, click the C<logout> button and try again). Note
-the C<***Root::auto User not found...> debug message in the
-development server output.  Enter username C<test01> and password
-C<mypass>, and you should be taken to the Book List page.
-
-Open C<root/src/books/list.tt2> and add the following lines to the
-bottom (below the closing </table> tag):
-
-    <p>
-      <a href="[% c.uri_for('/login') %]">Login</a>
-      <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Create</a>
-    </p>
-
-Reload your browser and you should now see a "Login" and "Create" links
-at the bottom of the page (as mentioned earlier, you can update template
-files without reloading the development server).  Click the first link
-to return to the login page.  This time you I<should> see the "You are
-already logged in" message.
-
-Finally, click the C<You can logout here> link on the C</login> page.
-You should stay at the login page, but the message should change to "You
-need to log in to use this application."
-
-
-=head1 USING PASSWORD HASHES
-
-In this section we increase the security of our system by converting 
-from cleartext passwords to SHA-1 password hashes that include a 
-random "salt" value to make them extremely difficult to crack with
-dictionary and "rainbow table" attacks.
-
-B<Note:> This section is optional.  You can skip it and the rest of the
-tutorial will function normally.
-
-Be aware that even with the techniques shown in this section, the browser
-still transmits the passwords in cleartext to your application.  We are
-just avoiding the I<storage> of cleartext passwords in the database by
-using a salted SHA-1 hash. If you are concerned about cleartext passwords
-between the browser and your application, consider using SSL/TLS, made
-easy with the Catalyst plugin Catalyst::Plugin:RequireSSL.
-
-
-=head2 Install DBIx::Class::EncodedColumn
-
-L<DBIx::Class::EncodedColumn|DBIx::Class::EncodedColumn> provides features
-that can greatly simplify the maintenance of passwords.  It's currently 
-not available as a .deb package in the normal Debian repositories, so let's
-install it directly from CPAN:
-
-    $ sudo cpan DBIx::Class::EncodedColumn
-
-
-=head2 Re-Run the DBIC::Schema Model Helper to Include DBIx::Class::EncodedColumn
-
-Next, we can re-run the model helper to have it include 
-L<DBIx::Class::EncodedColumn|DBIx::Class::EncodedColumn> in all of the 
-Result Classes it generates for us.  Simply use the same command we 
-saw in Chapters 3 and 4, but add C<,EncodedColumn> to the C<components>
-argument:
-
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp,EncodedColumn dbi:SQLite:myapp.db
-
-If you then open one of the Result Classes, you will see that it 
-includes EncodedColumn in the C<load_components> line.  Take a look at 
-C<lib/MyApp/Schema/Result/User.pm> since that's the main class where we
-want to use hashed and salted passwords:
-
-    __PACKAGE__->load_components("InflateColumn::DateTime", "TimeStamp", "EncodedColumn", "Core");
-
-
-=head2 Modify the "password" Column to Use EncodedColumn
-
-Open the file C<lib/MyApp/Schema/Result/User.pm> and enter the following
-text below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!" line but above
-the closing "1;":
-
-    # Have the 'password' column use a SHA-1 hash and 10-character salt
-    # with hex encoding; Generate the 'check_password" method
-    __PACKAGE__->add_columns(
-        'password' => {
-            data_type           => "TEXT",
-            size                => undef,
-            encode_column       => 1,
-            encode_class        => 'Digest',
-            encode_args         => {salt_length => 10},
-            encode_check_method => 'check_password',
-        },
-    );
-
-This redefines the automatically generated definition for the password 
-fields at the top of the Result Class file to now use EncodedColumn 
-logic (C<encoded_column> is set to 1).  C<encode_class> can be set to 
-either C<Digest> to use 
-L<DBIx::Class::EncodedColumn::Digest|DBIx::Class::EncodedColumn::Digest>, 
-or C<Crypt::Eksblowfish::Bcrypt> for 
-L<DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt|DBIx::Class::EncodedColumn::Crypt::Eksblowfish::Bcrypt>.
-C<encode_args> is then used to customize the type of Digest you 
-selected. Here we only specified the size of the salt to use, but
-we could have also modified the hashing algorithm ('SHA-256' is 
-the default) and the format to use ('base64' is the default, but
-'hex' and 'binary' are other options).  To use these, you could 
-change the C<encode_args> to something like:
-
-            encode_args         => {algorithm => 'SHA-1', 
-                                    format => 'hex', 
-                                    salt_length => 10},
-
-
-=head2 Load Hashed Passwords in the Database
-
-Next, let's create a quick script to load some hashed and salted passwords
-into the C<password> column of our C<users> table.  Open the file
-C<set_hashed_passwords.pl> in your editor and enter the following text:
-
-    #!/usr/bin/perl
-    
-    use strict;
-    use warnings;
-    
-    use MyApp::Schema;
-    
-    my $schema = MyApp::Schema->connect('dbi:SQLite:myapp.db');
-    
-    my @users = $schema->resultset('User')->all;
-    
-    foreach my $user (@users) {
-        $user->password('mypass');
-        $user->update;
-    }
-
-EncodedColumn lets us simple call C<$user->check_password($password)> 
-to see if the user has supplied the correct password, or, as we show 
-above, call C<$user->update($new_password)> to update the hashed 
-password stored for this user.
-
-Then run the following command:
-
-    $ perl -Ilib set_hashed_passwords.pl
-
-We had to use the C<-Ilib> arguement to tell perl to look under the 
-C<lib> directory for our C<MyApp::Schema> model.
-
-Then dump the users table to verify that it worked:
-
-    $ sqlite3 myapp.db "select * from user"
-    1|test01|38d3974fa9e9263099f7bc2574284b2f55473a9bM=fwpX2NR8|t01 at na.com|Joe|Blow|1
-    2|test02|6ed8586587e53e0d7509b1cfed5df08feadc68cbMJlnPyPt0I|t02 at na.com|Jane|Doe|1
-    3|test03|af929a151340c6aed4d54d7e2651795d1ad2e2f7UW8dHoGv9z|t03 at na.com|No|Go|0
-
-As you can see, the passwords are much harder to steal from the 
-database.  Also note that this demonstrates how to use a DBIx::Class 
-model outside of your web application -- a very useful feature in many 
-situations.
-
-
-=head2 Enable Hashed and Salted Passwords
-
-Edit C<lib/MyApp.pm> and update it to match the following text (the only change
-is to the C<password_type> field):
-
-    # Configure SimpleDB Authentication
-    __PACKAGE__->config->{'Plugin::Authentication'} = {
-            default => {
-                class           => 'SimpleDB',
-                user_model      => 'DB::User',
-                password_type   => 'self_check',
-            },
-        };
-
-The use of C<self_check> will cause 
-Catalyst::Plugin::Authentication::Store::DBIC to call the 
-C<check_password> method we enabled on our C<password> columns.
-
-
-=head2 Try Out the Hashed Passwords
-
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-You should now be able to go to L<http://localhost:3000/books/list> and
-login as before.  When done, click the "logout" link on the login page
-(or point your browser at L<http://localhost:3000/logout>).
-
-
-=head1 USING THE SESSION FOR FLASH
-
-As discussed in the previous chapter of the tutorial, C<flash> allows 
-you to set variables in a way that is very similar to C<stash>, but it 
-will remain set across multiple requests.  Once the value is read, it 
-is cleared (unless reset).  Although C<flash> has nothing to do with 
-authentication, it does leverage the same session plugins.  Now that 
-those plugins are enabled, let's go back and update the "delete and 
-redirect with query parameters" code seen at the end of the L<Basic 
-CRUD|Catalyst::Manual::Tutorial::BasicCRUD> chapter of the tutorial to 
-take advantage of C<flash>.
-
-First, open C<lib/MyApp/Controller/Books.pm> and modify C<sub delete>
-to match the following (everything after the model search line of code
-has changed):
-
-    =head2 delete
-    
-    Delete a book
-    
-    =cut
-    
-    sub delete :Chained('object') :PathPart('delete') :Args(0) {
-        my ($self, $c) = @_;
-    
-        # Use the book object saved by 'object' and delete it along
-        # with related 'book_authors' entries
-        $c->stash->{object}->delete;
-    
-        # Use 'flash' to save information across requests until it's read
-        $c->flash->{status_msg} = "Book deleted";
-    
-        # Redirect the user back to the list page
-        $c->response->redirect($c->uri_for($self->action_for('list')));
-    }
-
-Next, open C<root/src/wrapper.tt2> and update the TT code to pull from
-flash vs. the C<status_msg> query parameter:
-
-    ...
-    <div id="content">
-        [%# Status and error messages %]
-        <span class="message">[% status_msg || c.flash.status_msg %]</span>
-        <span class="error">[% error_msg %]</span>
-        [%# This is where TT will stick all of your template's contents. -%]
-        [% content %]
-    </div><!-- end content -->
-    ...
-
-Although the sample above only shows the C<content> div, leave the
-rest of the file intact -- the only change we made to the C<wrapper.tt2>
-was to add "C<|| c.request.params.status_msg>" to the
-C<E<lt>span class="message"E<gt>> line.
-
-
-=head2 Try Out Flash
-
-Restart the development server, log in, and then point your browser to
-L<http://localhost:3000/books/url_create/Test/1/4> to create an extra
-several books.  Click the "Return to list" link and delete one of the
-"Test" books you just added.  The C<flash> mechanism should retain our
-"Book deleted" status message across the redirect.
-
-B<NOTE:> While C<flash> will save information across multiple requests,
-I<it does get cleared the first time it is read>.  In general, this is
-exactly what you want -- the C<flash> message will get displayed on
-the next screen where it's appropriate, but it won't "keep showing up"
-after that first time (unless you reset it).  Please refer to
-L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> for additional
-information.
-
-
-=head2 Switch To Flash-To-Stash
-
-Although the a use of flash above works well, the
-C<status_msg || c.flash.status_msg> statement is a little ugly. A nice
-alternative is to use the C<flash_to_stash> feature that automatically
-copies the content of flash to stash.  This makes your controller
-and template code work regardless of where it was directly access, a
-forward, or a redirect.  To enable C<flash_to_stash>, you can either
-set the value in C<lib/MyApp.pm> by changing the default
-C<__PACKAGE__-E<gt>config> setting to something like:
-
-    __PACKAGE__->config(
-            name    => 'MyApp',
-            session => {flash_to_stash => 1}
-        );
-
-B<or> add the following to C<myapp.conf>:
-
-    <session>
-        flash_to_stash   1
-    </session>
-
-The C<__PACKAGE__-E<gt>config> option is probably preferable here
-since it's not something you will want to change at runtime without it
-possibly breaking some of your code.
-
-Then edit C<root/src/wrapper.tt2> and change the C<status_msg> line
-to match the following:
-
-    <span class="message">[% status_msg %]</span>
-
-Restart the development server and go to
-L<http://localhost:3000/books/list> in your browser.  Delete another
-of the "Test" books you added in the previous step.  Flash should still
-maintain the status message across the redirect even though you are no
-longer explicitly accessing C<c.flash>.
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Authorization.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,362 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::Authorization - Catalyst Tutorial - Chapter 6: Authorization
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 6 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-B<Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This chapter of the tutorial adds role-based authorization to the 
-existing authentication implemented in Chapter 5.  It provides simple 
-examples of how to use roles in both TT templates and controller 
-actions.  The first half looks at basic authorization concepts. The 
-second half looks at how moving your authorization code to your model 
-can simplify your code and make things easier to maintain.
-
-You can checkout the source code for this example from the catalyst
-subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
-
-
-=head1 BASIC AUTHORIZATION
-
-In this section you learn the basics of how authorization works under 
-Catalyst.
-
-
-=head2 Update Plugins to Include Support for Authorization
-
-Edit C<lib/MyApp.pm> and add C<Authorization::Roles> to the list:
-
-    # Load plugins
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple
-                
-                    StackTrace
-                
-                    Authentication
-                    Authorization::Roles
-        
-                    Session
-                    Session::Store::FastMmap
-                    Session::State::Cookie
-                    /;
-
-B<Note:> As discussed in MoreCatalystBasics, different versions of 
-C<Catalyst::Devel> have used a variety of methods to load the plugins. 
-You can put the plugins in the C<use Catalyst> statement if you 
-prefer.
-
-Once again (remain sharp, by now you should be getting the hang of things)
-include this additional plugin as a new dependency in the Makefile.PL file
-like this:
-
-    requires (
-        ...
-        'Catalyst::Plugin::Authorization::Roles' => '0',
-    );
-
-=head2 Add Role-Specific Logic to the "Book List" Template
-
-Open C<root/src/books/list.tt2> in your editor and add the following
-lines to the bottom of the file:
-
-    ...
-    <p>Hello [% c.user.username %], you have the following roles:</p>
-    
-    <ul>
-      [% # Dump list of roles -%]
-      [% FOR role = c.user.role %]<li>[% role %]</li>[% END %]
-    </ul>
-    
-    <p>
-    [% # Add some simple role-specific logic to template %]
-    [% # Use $c->check_user_roles() to check authz -%]
-    [% IF c.check_user_roles('user') %]
-      [% # Give normal users a link for 'logout' %]
-      <a href="[% c.uri_for('/logout') %]">User Logout</a>
-    [% END %]
-    
-    [% # Can also use $c->user->check_roles() to check authz -%]
-    [% IF c.check_user_roles('admin') %]
-      [% # Give admin users a link for 'create' %]
-      <a href="[% c.uri_for(c.controller.action_for('form_create')) %]">Admin Create</a>
-    [% END %]
-    </p>
-
-This code displays a different combination of links depending on the
-roles assigned to the user.
-
-
-=head2 Limit Books::add to 'admin' Users
-
-C<IF> statements in TT templates simply control the output that is sent
-to the user's browser; it provides no real enforcement (if users know or
-guess the appropriate URLs, they are still perfectly free to hit any
-action within your application).  We need to enhance the controller
-logic to wrap restricted actions with role-validation logic.
-
-For example, we might want to restrict the "formless create" action to
-admin-level users by editing C<lib/MyApp/Controller/Books.pm> and
-updating C<url_create> to match the following code:
-
-    =head2 url_create
-    
-    Create a book with the supplied title and rating,
-    with manual authorization
-    
-    =cut
-    
-    sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
-        # In addition to self & context, get the title, rating & author_id args
-        # from the URL.  Note that Catalyst automatically puts extra information
-        # after the "/<controller_name>/<action_name/" into @_
-        my ($self, $c, $title, $rating, $author_id) = @_;
-    
-        # Check the user's roles
-        if ($c->check_user_roles('admin')) {
-            # Call create() on the book model object. Pass the table
-            # columns/field values we want to set as hash values
-            my $book = $c->model('DB::Book')->create({
-                    title   => $title,
-                    rating  => $rating
-                });
-    
-            # Add a record to the join table for this book, mapping to
-            # appropriate author
-            $book->add_to_book_author({author_id => $author_id});
-            # Note: Above is a shortcut for this:
-            # $book->create_related('book_author', {author_id => $author_id});
-    
-            # Assign the Book object to the stash for display in the view
-            $c->stash->{book} = $book;
-    
-            # Set the TT template to use
-            $c->stash->{template} = 'books/create_done.tt2';
-        } else {
-            # Provide very simple feedback to the user.
-            $c->response->body('Unauthorized!');
-        }
-    }
-
-
-To add authorization, we simply wrap the main code of this method in an
-C<if> statement that calls C<check_user_roles>.  If the user does not
-have the appropriate permissions, they receive an "Unauthorized!"
-message.  Note that we intentionally chose to display the message this
-way to demonstrate that TT templates will not be used if the response
-body has already been set.  In reality you would probably want to use a
-technique that maintains the visual continuity of your template layout
-(for example, using the "status" or "error" message feature added in
-Chapter 3 or C<detach> to an action that shows an "unauthorized" page).
-
-B<TIP>: If you want to keep your existing C<url_create> method, you can
-create a new copy and comment out the original by making it look like a
-Pod comment.  For example, put something like C<=begin> before 
-C<sub add : Local {> and C<=end> after the closing C<}>.
-
-
-=head2 Try Out Authentication And Authorization
-
-Press C<Ctrl-C> to kill the previous server instance (if it's still
-running) and restart it:
-
-    $ script/myapp_server.pl
-
-Now trying going to L<http://localhost:3000/books/list> and you should 
-be taken to the login page (you might have to C<Shift+Reload> or 
-C<Ctrl+Reload> your browser and/or click the "User Logout" link on the book 
-list page).  Try logging in with both C<test01> and C<test02> (both 
-use a password of C<mypass>) and notice how the roles information 
-updates at the bottom of the "Book List" page. Also try the "User Logout"
-link on the book list page.
-
-Now the "url_create" URL will work if you are already logged in as user
-C<test01>, but receive an authorization failure if you are logged in as
-C<test02>.  Try:
-
-    http://localhost:3000/books/url_create/test/1/6
-
-while logged in as each user.  Use one of the "logout" links (or go to 
-L<http://localhost:3000/logout> in your browser directly) when you are 
-done.
-
-
-=head1 ENABLE MODEL-BASED AUTHORIZATION
-
-Hopefully it's fairly obvious that adding detailed permission checking 
-logic to our controllers and view templates isn't a very clean or 
-scalable way to build role-based permissions into out application.  As 
-with many other aspects of MVC web development, the goal is to have 
-your controllers and views be an "thin" as possible, with all of the 
-"fancy business logic" built into your model.
-
-For example, let's add a method to our C<Books.pm> Result Class to 
-check if a user is allowed to delete a book.  Open 
-C<lib/MyApp/Schema/Result/Book.pm> and add the following method 
-(be sure to add it below the "C<DO NOT MODIFY ...>" line):
-
-    =head2 delete_allowed_by
-    
-    Can the specified user delete the current book?
-    
-    =cut
-    
-    sub delete_allowed_by {
-        my ($self, $user) = @_;
-        
-        # Only allow delete if user has 'admin' role
-        return $user->has_role('admin');
-    }
-
-Here we call a C<has_role> method on our user object, so we should add 
-this method to our Result Class.  Open 
-C<lib/MyApp/Schema/Result/User.pm> and add the following method below 
-the "C<DO NOT MODIFY ...>" line:
-
-    =head 2 has_role
-    
-    Check if a user has the specified role
-    
-    =cut
-    
-    use Perl6::Junction qw/any/;
-    sub has_role {
-        my ($self, $role) = @_;
-    
-        # Does this user posses the required role?
-        return any(map { $_->role } $self->roles) eq $role;
-    }
-
-Now we need to add some enforcement inside our controller.  Open
-C<lib/MyApp/Controller/Books.pm> and update the C<delete> method to
-match the following code:
-
-    =head2 delete
-    
-    Delete a book
-    
-    =cut
-    
-    sub delete :Chained('object') :PathPart('delete') :Args(0) {
-        my ($self, $c) = @_;
-    
-        # Check permissions
-        $c->detach('/error_noperms')
-            unless $c->stash->{object}->delete_allowed_by($c->user->get_object);
-    
-        # Use the book object saved by 'object' and delete it along
-        # with related 'book_authors' entries
-        $c->stash->{object}->delete;
-    
-        # Use 'flash' to save information across requests until it's read
-        $c->flash->{status_msg} = "Book deleted";
-    
-        # Redirect the user back to the list page
-        $c->response->redirect($c->uri_for($self->action_for('list')));
-    }    
-
-Here, we C<detach> to an error page if the user is lacking the 
-appropriate permissions.  For this to work, we need to make 
-arrangements for the '/error_noperms' action to work.  Open 
-C<lib/MyApp/Controller/Root.pm> and add this method:
-
-    =head2 error_noperms
-    
-    Permissions error screen
-    
-    =cut
-        
-    sub error_noperms :Chained('/') :PathPath('error_noperms') :Args(0) {
-        my ($self, $c) = @_;
-    
-        $c->stash->{template} = 'error_noperms.tt2';
-    }
-
-And also add the template file by putting the following text into
-C<root/src/error_noperms.tt2>:
-
-    <span class="error">Permission Denied</span>
-
-Then run the Catalyst development server script:
-
-    $ script/myapp_server.pl
-
-Log in as C<test01> and create several new books using the C<url_create>
-feature:
-
-    http://localhost:3000/books/url_create/Test/1/4
-
-Then, while still logged in as C<test01>, click the "Delete" link next 
-to one of these books.  The book should be removed and you should see 
-the usual green "Book deleted" message.  Next, click the "User Logout" 
-link and log back in as C<test02>.  Now try deleting one of the books. 
-You should be taken to the red "Permission Denied" message on our 
-error page.
-
-Use one of the 'Logout' links (or go to the
-L<http://localhost:3000/logout> URL directly) when you are done.
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).
-

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/BasicCRUD.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,1302 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::BasicCRUD - Catalyst Tutorial - Chapter 4: Basic CRUD
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 4 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-B<Basic CRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This chapter of the tutorial builds on the fairly primitive 
-application created in Chapter 3 to add basic support for Create, 
-Read, Update, and Delete (CRUD) of C<Book> objects.  Note that the 
-'list' function in Chapter 2 already implements the Read portion of 
-CRUD (although Read normally refers to reading a single object; you 
-could implement full Read functionality using the techniques 
-introduced below).  This section will focus on the Create and Delete 
-aspects of CRUD.  More advanced capabilities, including full Update 
-functionality, will be addressed in Chapter 9.
-
-Although this chapter of the tutorial will show you how to build CRUD 
-functionality yourself, another option is to use a "CRUD builder" type 
-of tool to automate the process.  You get less control, but it's quick 
-and easy.  For example, see 
-L<CatalystX::ListFramework::Builder|CatalystX::ListFramework::Builder>, 
-L<CatalystX::CRUD|CatalystX::CRUD>, and 
-L<CatalystX::CRUD::YUI|CatalystX::CRUD::YUI>.
-
-You can check out the source code for this example from the Catalyst
-Subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
-
-
-=head1 FORMLESS SUBMISSION
-
-Our initial attempt at object creation will utilize the "URL
-arguments" feature of Catalyst (we will employ the more common form-
-based submission in the sections that follow).
-
-
-=head2 Include a Create Action in the Books Controller
-
-Edit C<lib/MyApp/Controller/Books.pm> and enter the following method:
-
-    =head2 url_create
-
-    Create a book with the supplied title, rating, and author
-
-    =cut
-
-    sub url_create : Local {
-        # In addition to self & context, get the title, rating, &
-        # author_id args from the URL.  Note that Catalyst automatically
-        # puts extra information after the "/<controller_name>/<action_name/"
-        # into @_
-        my ($self, $c, $title, $rating, $author_id) = @_;
-
-        # Call create() on the book model object. Pass the table
-        # columns/field values we want to set as hash values
-        my $book = $c->model('DB::Book')->create({
-                title  => $title,
-                rating => $rating
-            });
-
-        # Add a record to the join table for this book, mapping to
-        # appropriate author
-        $book->add_to_book_author({author_id => $author_id});
-        # Note: Above is a shortcut for this:
-        # $book->create_related('book_author', {author_id => $author_id});
-
-        # Assign the Book object to the stash for display in the view
-        $c->stash->{book} = $book;
-
-        # Set the TT template to use
-        $c->stash->{template} = 'books/create_done.tt2';
-    }
-
-Notice that Catalyst takes "extra slash-separated information" from the
-URL and passes it as arguments in C<@_>.  The C<url_create> action then
-uses a simple call to the DBIC C<create> method to add the requested
-information to the database (with a separate call to
-C<add_to_book_author> to update the join table).  As do virtually all
-controller methods (at least the ones that directly handle user input),
-it then sets the template that should handle this request.
-
-
-=head2 Include a Template for the 'url_create' Action:
-
-Edit C<root/src/books/create_done.tt2> and then enter:
-
-    [% # Use the TT Dumper plugin to Data::Dumper variables to the browser   -%]
-    [% # Not a good idea for production use, though. :-)  'Indent=1' is      -%]
-    [% # optional, but prevents "massive indenting" of deeply nested objects -%]
-    [% USE Dumper(Indent=1) -%]
-
-    [% # Set the page title.  META can 'go back' and set values in templates -%]
-    [% # that have been processed 'before' this template (here it's for      -%]
-    [% # root/lib/site/html and root/lib/site/header).  Note that META only  -%]
-    [% # works on simple/static strings (i.e. there is no variable           -%]
-    [% # interpolation).                                                     -%]
-    [% META title = 'Book Created' %]
-
-    [% # Output information about the record that was added.  First title.       -%]
-    <p>Added book '[% book.title %]'
-
-    [% # Output the last name of the first author.  This is complicated by an    -%]
-    [% # issue in TT 2.15 where blessed hash objects are not handled right.      -%]
-    [% # First, fetch 'book.author' from the DB once.                           -%]
-    [% authors = book.author %]
-    [% # Now use IF statements to test if 'authors.first' is "working". If so,   -%]
-    [% # we use it.  Otherwise we use a hack that seems to keep TT 2.15 happy.   -%]
-    by '[% authors.first.last_name IF authors.first;
-           authors.list.first.value.last_name IF ! authors.first %]'
-
-    [% # Output the rating for the book that was added -%]
-    with a rating of [% book.rating %].</p>
-
-    [% # Provide a link back to the list page                                    -%]
-    [% # 'uri_for()' builds a full URI; e.g., 'http://localhost:3000/books/list' -%]
-    <p><a href="[% c.uri_for('/books/list') %]">Return to list</a></p>
-
-    [% # Try out the TT Dumper (for development only!) -%]
-    <pre>
-    Dump of the 'book' variable:
-    [% Dumper.dump(book) %]
-    </pre>
-
-The TT C<USE> directive allows access to a variety of plugin modules
-(TT plugins, that is, not Catalyst plugins) to add extra functionality
-to the base TT capabilities.  Here, the plugin allows
-L<Data::Dumper|Data::Dumper> "pretty printing" of objects and
-variables.  Other than that, the rest of the code should be familiar
-from the examples in Chapter 3.
-
-
-=head2 Try the 'url_create' Feature
-
-If the application is still running from before, use C<Ctrl-C> to kill
-it. Then restart the server:
-
-    $ DBIC_TRACE=1 script/myapp_server.pl
-
-Note that new path for C</books/url_create> appears in the startup debug
-output.
-
-B<TIP>: You can use C<script/myapp_server.pl -r> to have the development
-server auto-detect changed files and reload itself (if your browser acts
-odd, you should also try throwing in a C<-k>).  If you make changes to
-the TT templates only, you do not need to reload the development server
-(only changes to "compiled code" such as Controller and Model C<.pm>
-files require a reload).
-
-Next, use your browser to enter the following URL:
-
-    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
-
-Your browser should display "Added book 'TCPIP_Illustrated_Vol-2' by
-'Stevens' with a rating of 5." along with a dump of the new book model
-object as it was returned by DBIC.  You should also see the following
-DBIC debug messages displayed in the development server log messages
-if you have DBIC_TRACE set:
-
-    INSERT INTO book (rating, title) VALUES (?, ?): `5', `TCPIP_Illustrated_Vol-2'
-    INSERT INTO book_author (author_id, book_id) VALUES (?, ?): `4', `6'
-
-The C<INSERT> statements are obviously adding the book and linking it to
-the existing record for Richard Stevens.  The C<SELECT> statement results
-from DBIC automatically fetching the book for the C<Dumper.dump(book)>.
-
-If you then click the "Return to list" link, you should find that
-there are now six books shown (if necessary, Shift+Reload or
-Ctrl+Reload your browser at the C</books/list> page).  You should now see
-the following six DBIC debug messages displayed for N=1-6:
-
-    SELECT author.id, author.first_name, author.last_name \
-        FROM book_author me  JOIN author author \
-        ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): 'N'
-
-
-=head1 CONVERT TO A CHAINED ACTION
-
-Although the example above uses the same C<Local> action type for the
-method that we saw in the previous chapter of the tutorial, there is an
-alternate approach that allows us to be more specific while also
-paving the way for more advanced capabilities.  Change the method
-declaration for C<url_create> in C<lib/MyApp/Controller/Books.pm> you
-entered above to match the following:
-
-    sub url_create :Chained('/') :PathPart('books/url_create') :Args(3) {
-
-This converts the method to take advantage of the Chained
-action/dispatch type. Chaining lets you have a single URL
-automatically dispatch to several controller methods, each of which
-can have precise control over the number of arguments that it will
-receive.  A chain can essentially be thought of having three parts --
-a beginning, a middle, and an end.  The bullets below summarize the key
-points behind each of these parts of a chain:
-
-
-=over 4
-
-
-=item *
-
-Beginning
-
-=over 4
-
-=item *
-
-B<Use "C<:Chained('/')>" to start a chain>
-
-=item *
-
-Get arguments through C<CaptureArgs()>
-
-=item *
-
-Specify the path to match with C<PathPart()>
-
-=back
-
-
-=item *
-
-Middle
-
-=over 4
-
-=item *
-
-Link to previous part of the chain with C<:Chained('_name_')>
-
-=item *
-
-Get arguments through C<CaptureArgs()>
-
-=item *
-
-Specify the path to match with C<PathPart()>
-
-=back
-
-
-=item *
-
-End
-
-=over 4
-
-=item *
-
-Link to previous part of the chain with C<:Chained('_name_')>
-
-=item *
-
-B<Do NOT get arguments through "C<CaptureArgs()>," use "C<Args()>" instead to end a chain>
-
-=item *
-
-Specify the path to match with C<PathPart()>
-
-=back
-
-
-=back
-
-In our C<url_create> method above, we have combined all three parts into
-a single method: C<:Chained('/')> to start the chain,
-C<:PathPart('books/url_create')> to specify the base URL to match, and
-C<:Args(3)> to capture exactly three arguments and to end the chain.
-
-As we will see shortly, a chain can consist of as many "links" as you
-wish, with each part capturing some arguments and doing some work
-along the way.  We will continue to use the Chained action type in this
-chapter of the tutorial and explore slightly more advanced capabilities
-with the base method and delete feature below.  But Chained dispatch
-is capable of far more.  For additional information, see
-L<Catalyst::Manual::Intro/Action types>,
-L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained>,
-and the 2006 Advent calendar entry on the subject:
-L<http://www.catalystframework.org/calendar/2006/10>.
-
-
-=head2 Try the Chained Action
-
-If you look back at the development server startup logs from your
-initial version of the C<url_create> method (the one using the
-C<:Local> attribute), you will notice that it produced output similar
-to the following:
-
-    [debug] Loaded Path actions:
-    .-------------------------------------+--------------------------------------.
-    | Path                                | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /                                   | /default                             |
-    | /                                   | /index                               |
-    | /books                              | /books/index                         |
-    | /books/list                         | /books/list                          |
-    | /books/url_create                   | /books/url_create                    |
-    '-------------------------------------+--------------------------------------'
-
-Now start the development server with our basic chained method in
-place and the startup debug output should change to something along
-the lines of the following:
-
-    [debug] Loaded Path actions:
-    .-------------------------------------+--------------------------------------.
-    | Path                                | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /                                   | /default                             |
-    | /                                   | /index                               |
-    | /books                              | /books/index                         |
-    | /books/list                         | /books/list                          |
-    '-------------------------------------+--------------------------------------'
-
-    [debug] Loaded Chained actions:
-    .-------------------------------------+--------------------------------------.
-    | Path Spec                           | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /books/url_create/*/*/*             | /books/url_create                    |
-    '-------------------------------------+--------------------------------------'
-
-C<url_create> has disappeared form the "Loaded Path actions" section
-but it now shows up under the newly created "Loaded Chained actions"
-section.  And the "/*/*/*" portion clearly shows our requirement for
-three arguments.
-
-As with our non-chained version of C<url_create>, use your browser to
-enter the following URL:
-
-    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
-
-You should see the same "Added book 'TCPIP_Illustrated_Vol-2' by
-'Stevens' with a rating of 5." along with a dump of the new book model
-object.  Click the "Return to list" link, and you should find that there
-are now seven books shown (two copies of I<TCPIP_Illustrated_Vol-2>).
-
-
-=head2 Refactor to Use a 'base' Method to Start the Chains
-
-Let's make a quick update to our initial Chained action to show a
-little more of the power of chaining.  First, open
-C<lib/MyApp/Controller/Books.pm> in your editor and add the following
-method:
-
-    =head2 base
-
-    Can place common logic to start chained dispatch here
-
-    =cut
-
-    sub base :Chained('/') :PathPart('books') :CaptureArgs(0) {
-        my ($self, $c) = @_;
-
-        # Store the ResultSet in stash so it's available for other methods
-        $c->stash->{resultset} = $c->model('DB::Book');
-
-        # Print a message to the debug log
-        $c->log->debug('*** INSIDE BASE METHOD ***');
-    }
-
-Here we print a log message and store the DBIC ResultSet in
-C<$c-E<gt>stash-E<gt>{resultset}> so that it's automatically available
-for other actions that chain off C<base>.  If your controller always
-needs a book ID as its first argument, you could have the base method
-capture that argument (with C<:CaptureArgs(1)>) and use it to pull the
-book object with C<-E<gt>find($id)> and leave it in the stash for
-later parts of your chains to then act upon. Because we have several
-actions that don't need to retrieve a book (such as the C<url_create>
-we are working with now), we will instead add that functionality
-to a common C<object> action shortly.
-
-As for C<url_create>, let's modify it to first dispatch to C<base>.
-Open up C<lib/MyApp/Controller/Books.pm> and edit the declaration for
-C<url_create> to match the following:
-
-    sub url_create :Chained('base') :PathPart('url_create') :Args(3) {
-
-Next, try out the refactored chain by restarting the development
-server.  Notice that our "Loaded Chained actions" section has changed
-slightly:
-
-    [debug] Loaded Chained actions:
-    .-------------------------------------+--------------------------------------.
-    | Path Spec                           | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /books/url_create/*/*/*             | /books/base (0)                      |
-    |                                     | => /books/url_create                 |
-    '-------------------------------------+--------------------------------------'
-
-The "Path Spec" is the same, but now it maps to two Private actions as
-we would expect.
-
-Once again, enter the following URL into your browser:
-
-    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
-
-The same "Added book 'TCPIP_Illustrated_Vol-2' by 'Stevens' with a
-rating of 5." message and a dump of the new book object should appear.
-Also notice the extra debug message in the development server output
-from the C<base> method.  Click the "Return to list" link, and you
-should find that there are now eight books shown.
-
-
-=head1 MANUALLY BUILDING A CREATE FORM
-
-Although the C<url_create> action in the previous step does begin to
-reveal the power and flexibility of both Catalyst and DBIC, it's
-obviously not a very realistic example of how users should be expected
-to enter data.  This section begins to address that concern.
-
-
-=head2 Add Method to Display The Form
-
-Edit C<lib/MyApp/Controller/Books.pm> and add the following method:
-
-    =head2 form_create
-
-    Display form to collect information for book to create
-
-    =cut
-
-    sub form_create :Chained('base') :PathPart('form_create') :Args(0) {
-        my ($self, $c) = @_;
-
-        # Set the TT template to use
-        $c->stash->{template} = 'books/form_create.tt2';
-    }
-
-This action simply invokes a view containing a form to create a book.
-
-
-=head2 Add a Template for the Form
-
-Open C<root/src/books/form_create.tt2> in your editor and enter:
-
-    [% META title = 'Manual Form Book Create' -%]
-
-    <form method="post" action="[% c.uri_for('form_create_do') %]">
-    <table>
-      <tr><td>Title:</td><td><input type="text" name="title"></td></tr>
-      <tr><td>Rating:</td><td><input type="text" name="rating"></td></tr>
-      <tr><td>Author ID:</td><td><input type="text" name="author_id"></td></tr>
-    </table>
-    <input type="submit" name="Submit" value="Submit">
-    </form>
-
-Note that we have specified the target of the form data as
-C<form_create_do>, the method created in the section that follows.
-
-
-=head2 Add a Method to Process Form Values and Update Database
-
-Edit C<lib/MyApp/Controller/Books.pm> and add the following method to
-save the form information to the database:
-
-    =head2 form_create_do
-
-    Take information from form and add to database
-
-    =cut
-
-    sub form_create_do :Chained('base') :PathPart('form_create_do') :Args(0) {
-        my ($self, $c) = @_;
-
-        # Retrieve the values from the form
-        my $title     = $c->request->params->{title}     || 'N/A';
-        my $rating    = $c->request->params->{rating}    || 'N/A';
-        my $author_id = $c->request->params->{author_id} || '1';
-
-        # Create the book
-        my $book = $c->model('DB::Book')->create({
-                title   => $title,
-                rating  => $rating,
-            });
-        # Handle relationship with author
-        $book->add_to_book_author({author_id => $author_id});
-
-        # Store new model object in stash
-        $c->stash->{book} = $book;
-
-        # Avoid Data::Dumper issue mentioned earlier
-        # You can probably omit this
-        $Data::Dumper::Useperl = 1;
-
-        # Set the TT template to use
-        $c->stash->{template} = 'books/create_done.tt2';
-    }
-
-
-=head2 Test Out The Form
-
-If the application is still running from before, use C<Ctrl-C> to kill
-it.  Then restart the server:
-
-    $ script/myapp_server.pl
-
-Notice that the server startup log reflects the two new chained
-methods that we added:
-
-    [debug] Loaded Chained actions:
-    .-------------------------------------+--------------------------------------.
-    | Path Spec                           | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /books/form_create                  | /books/base (0)                      |
-    |                                     | => /books/form_create                |
-    | /books/form_create_do               | /books/base (0)                      |
-    |                                     | => /books/form_create_do             |
-    | /books/url_create/*/*/*             | /books/base (0)                      |
-    |                                     | => /books/url_create                 |
-    '-------------------------------------+--------------------------------------'
-
-Point your browser to L<http://localhost:3000/books/form_create> and
-enter "TCP/IP Illustrated, Vol 3" for the title, a rating of 5, and an
-author ID of 4.  You should then see the output of the same
-C<create_done.tt2> template seen in earlier examples.  Finally, click
-"Return to list" to view the full list of books.
-
-B<Note:> Having the user enter the primary key ID for the author is
-obviously crude; we will address this concern with a drop-down list in
-Chapter 9.
-
-
-=head1 A SIMPLE DELETE FEATURE
-
-Turning our attention to the Delete portion of CRUD, this section
-illustrates some basic techniques that can be used to remove information
-from the database.
-
-
-=head2 Include a Delete Link in the List
-
-Edit C<root/src/books/list.tt2> and update it to match the following (two
-sections have changed: 1) the additional '<th>Links</th>' table header,
-and 2) the four lines for the Delete link near the bottom):
-
-    [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
-    [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
-    [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
-    [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
-
-    [% # Provide a title -%]
-    [% META title = 'Book List' -%]
-
-    <table>
-    <tr><th>Title</th><th>Rating</th><th>Author(s)</th><th>Links</th></tr>
-    [% # Display each book in a table row %]
-    [% FOREACH book IN books -%]
-      <tr>
-        <td>[% book.title %]</td>
-        <td>[% book.rating %]</td>
-        <td>
-          [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
-          [% # loop in 'side effect notation' to load just the last names of the     -%]
-          [% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
-          [% # a value, so nothing will be printed here.  But, if you have something -%]
-          [% # in TT that does return a value and you don't want it printed, you can -%]
-          [% # 1) assign it to a bogus value, or # 2) use the CALL keyword to        -%]
-          [% # call it and discard the return value.                                 -%]
-          [% tt_authors = [ ];
-             tt_authors.push(author.last_name) FOREACH author = book.author %]
-          [% # Now use a TT 'virtual method' to display the author count in parens   -%]
-          [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
-          ([% tt_authors.size | html %])
-          [% # Use another TT vmethod to join & print the names & comma separators   -%]
-          [% tt_authors.join(', ') | html %]
-        </td>
-        <td>
-          [% # Add a link to delete a book %]
-          <a href="[% c.uri_for(c.controller.action_for('delete'), [book.id]) %]">Delete</a>
-        </td>
-      </tr>
-    [% END -%]
-    </table>
-
-The additional code is obviously designed to add a new column to the
-right side of the table with a C<Delete> "button" (for simplicity, links
-will be used instead of full HTML buttons; in practice, anything that
-modifies data should be handled with a form sending a PUT request).
-
-Also notice that we are using a more advanced form of C<uri_for> than
-we have seen before.  Here we use
-C<$c-E<gt>controller-E<gt>action_for> to automatically generate a URI
-appropriate for that action based on the method we want to link to
-while inserting the C<book.id> value into the appropriate place.  Now,
-if you ever change C<:PathPart('delete')> in your controller method to
-C<:PathPart('kill')>, then your links will automatically update
-without any changes to your .tt2 template file.  As long as the name
-of your method does not change (here, "delete"), then your links will
-still be correct.  There are a few shortcuts and options when using
-C<action_for()>:
-
-=over 4
-
-=item *
-
-If you are referring to a method in the current controller, you can
-use C<$self-E<gt>action_for('_method_name_')>.
-
-=item *
-
-If you are referring to a method in a different controller, you need
-to include that controller's name as an argument to C<controller()>, as in
-C<$c-E<gt>controller('_controller_name_')-E<gt>action_for('_method_name_')>.
-
-=back
-
-B<Note:> In practice you should B<never> use a GET request to delete a
-record -- always use POST for actions that will modify data.  We are
-doing it here for illustrative and simplicity purposes only.
-
-
-=head2 Add a Common Method to Retrieve a Book for the Chain
-
-As mentioned earlier, since we have a mixture of actions that operate
-on a single book ID and others that do not, we should not have C<base>
-capture the book ID, find the corresponding book in the database and
-save it in the stash for later links in the chain.  However, just
-because that logic does not belong in C<base> doesn't mean that we
-can't create another location to centralize the book lookup code.  In
-our case, we will create a method called C<object> that will store the
-specific book in the stash.  Chains that always operate on a single
-existing book can chain off this method, but methods such as
-C<url_create> that don't operate on an existing book can chain
-directly off base.
-
-To add the C<object> method, edit C<lib/MyApp/Controller/Books.pm>
-and add the following code:
-
-    =head2 object
-
-    Fetch the specified book object based on the book ID and store
-    it in the stash
-
-    =cut
-
-    sub object :Chained('base') :PathPart('id') :CaptureArgs(1) {
-        # $id = primary key of book to delete
-        my ($self, $c, $id) = @_;
-
-        # Find the book object and store it in the stash
-        $c->stash(object => $c->stash->{resultset}->find($id));
-
-        # Make sure the lookup was successful.  You would probably
-        # want to do something like this in a real app:
-        #   $c->detach('/error_404') if !$c->stash->{object};
-        die "Book $id not found!" if !$c->stash->{object};
-    }
-
-Now, any other method that chains off C<object> will automatically
-have the appropriate book waiting for it in
-C<$c-E<gt>stash-E<gt>{object}>.
-
-Also note that we are using a different technique for setting
-C<$c-E<gt>stash>.  The advantage of this style is that it lets you set
-multiple stash variables at a time.  For example:
-
-    $c->stash(object => $c->stash->{resultset}->find($id),
-              another_thing => 1);
-
-or as a hashref:
-
-    $c->stash({object => $c->stash->{resultset}->find($id),
-              another_thing => 1});
-
-Either format works, but the C<$c-E<gt>stash(name =E<gt> value);>
-style is growing in popularity -- you may wish to use it all
-the time (even when you are only setting a single value).
-
-
-=head2 Add a Delete Action to the Controller
-
-Open C<lib/MyApp/Controller/Books.pm> in your editor and add the
-following method:
-
-    =head2 delete
-
-    Delete a book
-
-    =cut
-
-    sub delete :Chained('object') :PathPart('delete') :Args(0) {
-        my ($self, $c) = @_;
-
-        # Use the book object saved by 'object' and delete it along
-        # with related 'book_author' entries
-        $c->stash->{object}->delete;
-
-        # Set a status message to be displayed at the top of the view
-        $c->stash->{status_msg} = "Book deleted.";
-
-        # Forward to the list action/method in this controller
-        $c->forward('list');
-    }
-
-This method first deletes the book object saved by the C<object> method.
-However, it also removes the corresponding entry from the
-C<book_author> table with a cascading delete.
-
-Then, rather than forwarding to a "delete done" page as we did with the
-earlier create example, it simply sets the C<status_msg> to display a
-notification to the user as the normal list view is rendered.
-
-The C<delete> action uses the context C<forward> method to return the
-user to the book list.  The C<detach> method could have also been used.
-Whereas C<forward> I<returns> to the original action once it is
-completed, C<detach> does I<not> return.  Other than that, the two are
-equivalent.
-
-
-=head2 Try the Delete Feature
-
-If the application is still running from before, use C<Ctrl-C> to kill
-it.  Then restart the server:
-
-    $ DBIC_TRACE=1 script/myapp_server.pl
-
-The C<delete> method now appears in the "Loaded Chained actions" section
-of the startup debug output:
-
-    [debug] Loaded Chained actions:
-    .-------------------------------------+--------------------------------------.
-    | Path Spec                           | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /books/id/*/delete                  | /books/base (0)                      |
-    |                                     | -> /books/object (1)                 |
-    |                                     | => /books/delete                     |
-    | /books/form_create                  | /books/base (0)                      |
-    |                                     | => /books/form_create                |
-    | /books/form_create_do               | /books/base (0)                      |
-    |                                     | => /books/form_create_do             |
-    | /books/url_create/*/*/*             | /books/base (0)                      |
-    |                                     | => /books/url_create                 |
-    '-------------------------------------+--------------------------------------'
-
-Then point your browser to L<http://localhost:3000/books/list> and click
-the "Delete" link next to the first "TCPIP_Illustrated_Vol-2".  A green
-"Book deleted" status message should display at the top of the page,
-along with a list of the eight remaining books.  You will also see the
-cascading delete operation via the DBIC_TRACE output:
-
-    SELECT me.id, me.title, me.rating FROM book me WHERE ( ( me.id = ? ) ): '6'
-    DELETE FROM book WHERE ( id = ? ): '6'
-    SELECT me.book_id, me.author_id FROM book_author me WHERE ( me.book_id = ? ): '6'
-    DELETE FROM book_author WHERE ( author_id = ? AND book_id = ? ): '4', '6'
-
-
-=head2 Fixing a Dangerous URL
-
-Note the URL in your browser once you have performed the deletion in the
-prior step -- it is still referencing the delete action:
-
-    http://localhost:3000/books/id/6/delete
-
-What if the user were to press reload with this URL still active?  In
-this case the redundant delete is harmless (although it does generate
-an exception screen, it doesn't perform any undesirable actions on the
-application or database), but in other cases this could clearly be
-extremely dangerous.
-
-We can improve the logic by converting to a redirect.  Unlike
-C<$c-E<gt>forward('list'))> or C<$c-E<gt>detach('list'))> that perform
-a server-side alteration in the flow of processing, a redirect is a
-client-side mechanism that causes the browser to issue an entirely
-new request.  As a result, the URL in the browser is updated to match
-the destination of the redirection URL.
-
-To convert the forward used in the previous section to a redirect,
-open C<lib/MyApp/Controller/Books.pm> and edit the existing
-C<sub delete> method to match:
-
-    =head2 delete
-
-    Delete a book
-
-    =cut
-
-    sub delete :Chained('object') :PathPart('delete') :Args(0) {
-        my ($self, $c) = @_;
-
-        # Use the book object saved by 'object' and delete it along
-        # with related 'book_author' entries
-        $c->stash->{object}->delete;
-
-        # Set a status message to be displayed at the top of the view
-        $c->stash->{status_msg} = "Book deleted.";
-
-        # Redirect the user back to the list page.  Note the use
-        # of $self->action_for as earlier in this section (BasicCRUD)
-        $c->response->redirect($c->uri_for($self->action_for('list')));
-    }
-
-
-=head2 Try the Delete and Redirect Logic
-
-Restart the development server and point your browser to
-L<http://localhost:3000/books/list> (don't just hit "Refresh" in your
-browser since we left the URL in an invalid state in the previous
-section!) and delete the first copy of the remaining two
-"TCPIP_Illustrated_Vol-2" books.  The URL in your browser should return
-to the L<http://localhost:3000/books/list> URL, so that is an
-improvement, but notice that I<no green "Book deleted" status message is
-displayed>.  Because the stash is reset on every request (and a redirect
-involves a second request), the C<status_msg> is cleared before it can
-be displayed.
-
-
-=head2 Using 'uri_for' to Pass Query Parameters
-
-There are several ways to pass information across a redirect. One 
-option is to use the C<flash> technique that we will see in Chapter 5 
-of this tutorial; however, here we will pass the information via query 
-parameters on the redirect itself.  Open 
-C<lib/MyApp/Controller/Books.pm> and update the existing C<sub delete> 
-method to match the following:
-
-    =head2 delete
-
-    Delete a book
-
-    =cut
-
-    sub delete :Chained('object') :PathPart('delete') :Args(0) {
-        my ($self, $c) = @_;
-
-        # Use the book object saved by 'object' and delete it along
-        # with related 'book_author' entries
-        $c->stash->{object}->delete;
-
-        # Redirect the user back to the list page with status msg as an arg
-        $c->response->redirect($c->uri_for($self->action_for('list'),
-            {status_msg => "Book deleted."}));
-    }
-
-This modification simply leverages the ability of C<uri_for> to include
-an arbitrary number of name/value pairs in a hash reference.  Next, we
-need to update C<root/src/wrapper.tt2> to handle C<status_msg> as a
-query parameter:
-
-    ...
-    <div id="content">
-        [%# Status and error messages %]
-        <span class="message">[% status_msg || c.request.params.status_msg %]</span>
-        <span class="error">[% error_msg %]</span>
-        [%# This is where TT will stick all of your template's contents. -%]
-        [% content %]
-    </div><!-- end content -->
-    ...
-
-Although the sample above only shows the C<content> div, leave the
-rest of the file intact -- the only change we made to the C<wrapper.tt2>
-was to add "C<|| c.request.params.status_msg>" to the
-C<E<lt>span class="message"E<gt>> line.
-
-
-=head2 Try the Delete and Redirect With Query Param Logic
-
-Restart the development server and point your browser to
-L<http://localhost:3000/books/list> (you should now be able to safely
-hit "refresh" in your browser).  Then delete the remaining copy of
-"TCPIP_Illustrated_Vol-2".  The green "Book deleted" status message
-should return.
-
-B<NOTE:> Another popular method for maintaining server-side
-information across a redirect is to use the C<flash> technique we
-discuss in the next chapter of the tutorial,
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>. While
-C<flash> is a "slicker" mechanism in that it's all handled by the
-server and doesn't "pollute" your URLs, B<it is important to note that
-C<flash> can lead to situations where the wrong information shows up
-in the wrong browser window if the user has multiple windows or
-browser tabs open>.  For example, Window A causes something to be
-placed in the stash, but before that window performs a redirect,
-Window B makes a request to the server and gets the status information
-that should really go to Window A.  For this reason, you may wish
-to use the "query param" technique shown here in your applications.
-
-
-=head1 EXPLORING THE POWER OF DBIC
-
-In this section we will explore some additional capabilities offered
-by DBIx::Class.  Although these features have relatively little to do
-with Catalyst per se, you will almost certainly want to take advantage
-of them in your applications.
-
-
-=head2 Add Datetime Columns to Our Existing Books Table
-
-Let's add two columns to our existing C<books> table to track when
-each book was added and when each book is updated:
-
-    $ sqlite3 myapp.db
-    sqlite> ALTER TABLE book ADD created INTEGER;
-    sqlite> ALTER TABLE book ADD updated INTEGER;
-    sqlite> UPDATE book SET created = DATETIME('NOW'), updated = DATETIME('NOW');
-    sqlite> SELECT * FROM book;
-    1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
-    4|Perl Cookbook|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    5|Designing with Web Standards|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    9|TCP/IP Illustrated, Vol 3|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    sqlite> .quit
-    $
-
-This will modify the C<books> table to include the two new fields
-and populate those fields with the current time.
-
-
-=head2 Update DBIx::Class to Automatically Handle the Datetime Columns
-
-Next, we should re-run the DBIC helper to update the Result Classes
-with the new fields:
-
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
-     exists "/root/dev/MyApp/script/../lib/MyApp/Model"
-     exists "/root/dev/MyApp/script/../t"
-    Dumping manual schema for MyApp::Schema to directory /root/dev/MyApp/script/../lib ...
-    Schema dump completed.
-     exists "/root/dev/MyApp/script/../lib/MyApp/Model/DB.pm"
-
-Notice that we modified our use of the helper slightly: we told
-it to include the L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp>
-in the C<load_components> line of the Result Classes.
-
-If you open C<lib/MyApp/Schema/Result/Book.pm> in your editor you
-should see that the C<created> and C<updated> fields are now included
-in the call to C<add_columns()>, but our relationship information below
-the "C<# DO NOT MODIFY...>" line was automatically preserved.
-
-While we have this file open, let's update it with some additional
-information to have DBIC automatically handle the updating of these
-two fields for us.  Insert the following code at the bottom of the
-file (it B<must> be B<below> the "C<# DO NOT MODIFY...>" line and
-B<above> the C<1;> on the last line):
-
-    #
-    # Enable automatic date handling
-    #
-    __PACKAGE__->add_columns(
-        "created",
-        { data_type => 'datetime', set_on_create => 1 },
-        "updated",
-        { data_type => 'datetime', set_on_create => 1, set_on_update => 1 },
-    );
-
-This will override the definition for these fields that Schema::Loader 
-placed at the top of the file.  The C<set_on_create> and 
-C<set_on_update> options will cause DBIx::Class to automatically 
-update the timestamps in these columns whenever a row is created or 
-modified.
-
-To test this out, restart the development server using the
-C<DBIC_TRACE=1> option:
-
-    DBIC_TRACE=1 script/myapp_server.pl
-
-Then enter the following URL into your web browser:
-
-    http://localhost:3000/books/url_create/TCPIP_Illustrated_Vol-2/5/4
-
-You should get the same "Book Created" screen we saw above.  However,
-if you now use the sqlite3 command-line tool to dump the C<books> table,
-you will see that the new book we added has an appropriate date and
-time entered for it (see the last line in the listing below):
-
-    sqlite3 myapp.db "select * from book"
-    1|CCSP SNRS Exam Certification Guide|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    2|TCP/IP Illustrated, Volume 1|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    3|Internetworking with TCP/IP Vol.1|4|2009-03-08 16:26:35|2009-03-08 16:26:35
-    4|Perl Cookbook|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    5|Designing with Web Standards|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    9|TCP/IP Illustrated, Vol 3|5|2009-03-08 16:26:35|2009-03-08 16:26:35
-    10|TCPIP_Illustrated_Vol-2|5|2009-03-08 16:29:08|2009-03-08 16:29:08
-
-Notice in the debug log that the SQL DBIC generated has changed to
-incorporate the datetime logic:
-
-    INSERT INTO book (created, rating, title, updated) VALUES (?, ?, ?, ?):
-    '2009-03-08 16:29:08', '5', 'TCPIP_Illustrated_Vol-2', '2009-03-08 16:29:08'
-    INSERT INTO book_author (author_id, book_id) VALUES (?, ?): '4', '10'
-
-
-=head2 Create a ResultSet Class
-
-An often overlooked but extremely powerful features of DBIC is that it
-allows you to supply your own subclasses of C<DBIx::Class::ResultSet>.
-It allows you to pull complex and unsightly "query code" out of your
-controllers and encapsulate it in a method of your ResultSet Class.
-These "canned queries" in your ResultSet Class can then be invoked
-via a single call, resulting in much cleaner and easier to read
-controller code.
-
-To illustrate the concept with a fairly simple example, let's create a
-method that returns books added in the last 10 minutes.  Start by
-making a directory where DBIx::Class will look for our ResultSet Class:
-
-    mkdir lib/MyApp/Schema/ResultSet
-
-Then open C<lib/MyApp/Schema/ResultSet/Book.pm> and enter the following:
-
-    package MyApp::Schema::ResultSet::Book;
-
-    use strict;
-    use warnings;
-    use base 'DBIx::Class::ResultSet';
-
-    =head2 created_after
-
-    A predefined search for recently added books
-
-    =cut
-
-    sub created_after {
-        my ($self, $datetime) = @_;
-
-        my $date_str = $self->_source_handle->schema->storage
-                              ->datetime_parser->format_datetime($datetime);
-
-        return $self->search({
-            created => { '>' => $date_str }
-        });
-    }
-
-    1;
-
-Then we need to tell the Result Class to to treat this as a ResultSet
-Class.  Open C<lib/MyApp/Schema/Result/Book.pm> and add the following
-above the "C<1;>" at the bottom of the file:
-
-    #
-    # Set ResultSet Class
-    #
-    __PACKAGE__->resultset_class('MyApp::Schema::ResultSet::Book');
-
-Then add the following method to the C<lib/MyApp/Controller/Books.pm>:
-
-    =head2 list_recent
-
-    List recently created books
-
-    =cut
-
-    sub list_recent :Chained('base') :PathPart('list_recent') :Args(1) {
-        my ($self, $c, $mins) = @_;
-
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template, but only
-        # retrieve books created within the last $min number of minutes
-        $c->stash->{books} = [$c->model('DB::Book')
-                                ->created_after(DateTime->now->subtract(minutes => $mins))];
-
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods (action methods respond to user input in
-        # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
-    }
-
-Now start the development server with C<DBIC_TRACE=1> and try
-different values for the minutes argument (the final number value) for
-the URL C<http://localhost:3000/books/list_recent/10>.  For example,
-this would list all books added in the last fifteen minutes:
-
-    http://localhost:3000/books/list_recent/15
-
-Depending on how recently you added books, you might want to
-try a higher or lower value.
-
-
-=head2 Chaining ResultSets
-
-One of the most helpful and powerful features in DBIx::Class is that 
-it allows you to "chain together" a series of queries (note that this 
-has nothing to do with the "Chained Dispatch" for Catalyst that we 
-were discussing above).  Because each ResultSet returns another 
-ResultSet, you can take an initial query and immediately feed that 
-into a second query (and so on for as many queries you need). Note 
-that no matter how many ResultSets you chain together, the database 
-itself will not be hit until you use a method that attempts to access 
-the data. And, because this technique carries over to the ResultSet 
-Class feature we implemented in the previous section for our "canned 
-search", we can combine the two capabilities.  For example, let's add 
-an action to our C<Books> controller that lists books that are both 
-recent I<and> have "TCP" in the title.  Open up 
-C<lib/MyApp/Controller/Books.pm> and add the following method:
-
-    =head2 list_recent_tcp
-
-    List recently created books
-
-    =cut
-
-    sub list_recent_tcp :Chained('base') :PathPart('list_recent_tcp') :Args(1) {
-        my ($self, $c, $mins) = @_;
-
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template, but only
-        # retrieve books created within the last $min number of minutes
-        # AND that have 'TCP' in the title
-        $c->stash->{books} = [$c->model('DB::Book')
-                                ->created_after(DateTime->now->subtract(minutes => $mins))
-                                ->search({title => {'like', '%TCP%'}})
-                             ];
-
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods (action methods respond to user input in
-        # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
-    }
-
-To try this out, restart the development server with:
-
-    DBIC_TRACE=1 script/myapp_server.pl
-
-And enter the following URL into your browser:
-
-    http://localhost:3000/books/list_recent_tcp/100
-
-And you should get a list of books added in the last 100 minutes that
-contain the string "TCP" in the title.  However, if you look at all
-books within the last 100 minutes, you should get a longer list
-(again, you might have to adjust the number of minutes depending on
-how recently you added books to your database):
-
-    http://localhost:3000/books/list_recent/100
-
-Take a look at the DBIC_TRACE output in the development server log for
-the first URL and you should see something similar to the following:
-
-    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me
-    WHERE ( ( ( title LIKE ? ) AND ( created > ? ) ) ): '%TCP%', '2009-03-08 14:52:54'
-
-However, let's not pollute our controller code with this raw "TCP"
-query -- it would be cleaner to encapsulate that code in a method on
-our ResultSet Class.  To do this, open
-C<lib/MyApp/Schema/ResultSet/Book.pm> and add the following method:
-
-    =head2 title_like
-
-    A predefined search for books with a 'LIKE' search in the string
-
-    =cut
-
-    sub title_like {
-        my ($self, $title_str) = @_;
-
-        return $self->search({
-            title => { 'like' => "%$title_str%" }
-        });
-    }
-
-We defined the search string as C<$title_str> to make the method more
-flexible.  Now update the C<list_recent_tcp> method in
-C<lib/MyApp/Controller/Books.pm> to match the following (we have
-replaced the C<-E<gt>search> line with the C<-E<gt>title_like> line
-shown here -- the rest of the method should be the same):
-
-    =head2 list_recent_tcp
-
-    List recently created books
-
-    =cut
-
-    sub list_recent_tcp :Chained('base') :PathPart('list_recent_tcp') :Args(1) {
-        my ($self, $c, $mins) = @_;
-
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template, but only
-        # retrieve books created within the last $min number of minutes
-        # AND that have 'TCP' in the title
-        $c->stash->{books} = [$c->model('DB::Book')
-                                ->created_after(DateTime->now->subtract(minutes => $mins))
-                                ->title_like('TCP')
-                             ];
-
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods (action methods respond to user input in
-        # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
-    }
-
-Then restart the development server and try out the C<list_recent_tcp>
-and C<list_recent> URL as we did above.  It should work just the same,
-but our code is obviously cleaner and more modular, while also being
-more flexible at the same time.
-
-
-=head2 Adding Methods to Result Classes
-
-In the previous two sections we saw a good example of how we could use 
-DBIx::Class ResultSet Classes to clean up our code for an entire query 
-(for example, our "canned searches" that filtered the entire query). 
-We can do a similar improvement when working with individual rows as 
-well.  Whereas the ResultSet construct is used in DBIC to correspond 
-to an entire query, the Result Class construct is used to represent a 
-row. Therefore, we can add row-specific "helper methods" to our Result 
-Classes stored in C<lib/MyApp/Schema/Result/>. For example, open 
-C<lib/MyApp/Schema/Result/Author.pm> and add the following method (as 
-always, it must be above the closing "C<1;>"):
-
-    #
-    # Helper methods
-    #
-    sub full_name {
-        my ($self) = @_;
-
-        return $self->first_name . ' ' . $self->last_name;
-    }
-
-This will allow us to conveniently retrieve both the first and last
-name for an author in one shot.  Now open C<root/src/books/list.tt2>
-and change the definition of C<tt_authors> from this:
-
-    ...
-      [% tt_authors = [ ];
-         tt_authors.push(author.last_name) FOREACH author = book.author %]
-    ...
-
-to:
-
-    ...
-      [% tt_authors = [ ];
-         tt_authors.push(author.full_name) FOREACH author = book.author %]
-    ...
-
-(Only C<author.last_name> was changed to C<author.full_name> -- the
-rest of the file should remain the same.)
-
-Now restart the development server and go to the standard book list
-URL:
-
-    http://localhost:3000/books/list
-
-The "Author(s)" column will now contain both the first and last name.
-And, because the concatenation logic was encapsulated inside our
-Result Class, it keeps the code inside our .tt template nice and clean
-(remember, we want the templates to be as close to pure HTML markup as
-possible). Obviously, this capability becomes even more useful as you
-use to to remove even more complicated row-specific logic from your
-templates!
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/CatalystBasics.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,462 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::CatalystBasics - Catalyst Tutorial - Chapter 2: Catalyst Application Development Basics
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 2 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-B<Catalyst Basics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-In this chapter of the tutorial, we will create a very basic Catalyst 
-web application, demonstrating a number of powerful capabilities, such 
-as:
-
-=over 4
-
-=item * Helper Scripts
-
-Catalyst helper scripts that can be used to rapidly bootstrap the
-skeletal structure of an application.
-
-=item * MVC
-
-Model/View/Controller (MVC) provides an architecture that facilitates a
-clean "separation of control" between the different portions of your
-application. Given that many other documents cover this subject in
-detail, MVC will not be discussed in depth here (for an excellent
-introduction to MVC and general Catalyst concepts, please see
-L<Catalyst::Manual::About|Catalyst::Manual::About>). In short:
-
-=over 4
-
-=item * Model
-
-The model usually represents a data store. In most applications, the
-model equates to the objects that are created from and saved to your SQL
-database.
-
-=item * View
-
-The view takes model objects and renders them into something for the end
-user to look at. Normally this involves a template-generation tool that
-creates HTML for the user's web browser, but it could easily be code
-that generates other forms such as PDF documents, e-mails, spreadsheets, 
-or even "behind the scenes" formats such as XML and JSON.
-
-=item * Controller
-
-As suggested by its name, the controller takes user requests and routes
-them to the necessary model and view.
-
-=back
-
-=item * ORM
-
-The use of Object-Relational Mapping (ORM) technology for database
-access. Specifically, ORM provides an automated and standardized means
-to persist and restore objects to/from a relational database.
-
-=back
-
-You can checkout the source code for this example from the catalyst
-subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
-
-
-=head1 CREATE A CATALYST PROJECT
-
-Catalyst provides a number of helper scripts that can be used to 
-quickly flesh out the basic structure of your application. All 
-Catalyst projects begin with the C<catalyst.pl> helper (see 
-L<Catalyst::Helper|Catalyst::Helper> for more information on helpers). 
-Also note that as of Catalyst 5.7000, you will not have the helper 
-scripts unless you install both L<Catalyst::Runtime|Catalyst::Runtime> 
-and L<Catalyst::Devel|Catalyst::Devel>.
-
-In this first chapter of the tutorial, use the Catalyst C<catalyst.pl> 
-script to initialize the framework for an application called C<Hello>:
-
-    $ catalyst.pl Hello
-    created "Hello"
-    created "Hello/script"
-    created "Hello/lib"
-    created "Hello/root"
-    ...
-    created "Hello/script/hello_create.pl"
-    $ cd Hello
-
-The C<catalyst.pl> helper script will display the names of the
-directories and files it creates:
-
-    Changes               # Record of application changes
-    lib                   # Lib directory for your app's Perl modules
-        Hello             # Application main code directory
-            Controller    # Directory for Controller modules 
-            Model         # Directory for Models
-            View          # Directory for Views
-        Hello.pm          # Base application module
-    Makefile.PL           # Makefile to build application
-    hello.conf            # Application configuration file
-    README                # README file
-    root                  # Equiv of htdocs, dir for templates, css, javascript
-        favicon.ico
-        static            # Directory for static files
-            images        # Directory for image files used in welcome screen
-    script                # Directory for Perl scripts
-        hello_cgi.pl      # To run your app as a cgi (not recommended)
-        hello_create.pl   # To create models, views, controllers
-        hello_fastcgi.pl  # To run app as a fastcgi program
-        hello_server.pl   # The normal development server
-        hello_test.pl     # Test your app from the command line
-    t                     # Directory for tests
-        01app.t           # Test scaffold       
-        02pod.t           
-        03podcoverage.t 
-
-
-Catalyst will "auto-discover" modules in the Controller, Model, and 
-View directories. When you use the hello_create.pl script it will 
-create Perl module scaffolds in those directories, plus test files in 
-the "t" directory. The default location for templates is in the "root" 
-directory. The scripts in the script directory will always start with 
-the lowercased version of your application name. If your app is 
-MaiTai, then the create script would be "maitai_create.pl".
-
-Though it's too early for any significant celebration, we already have 
-a functioning application. We can use the Catalyst supplied script to 
-start up a development server and view the default Catalyst page in 
-your browser. All scripts in the script directory should be run from 
-the base directory of your application, so change to the Hello 
-directory.
-
-Run the following command to start up the built-in development web 
-server (make sure you didn't forget the "C<cd Hello>" from the 
-previous step):
-
-    $ script/hello_server.pl
-    [debug] Debug messages enabled
-    [debug] Statistics enabled
-    [debug] Loaded plugins:
-    .----------------------------------------------------------------------------.
-    | Catalyst::Plugin::ConfigLoader  0.20                                       |
-    | Catalyst::Plugin::Static::Simple  0.20                                     |
-    '----------------------------------------------------------------------------'
-    
-    [debug] Loaded dispatcher "Catalyst::Dispatcher"
-    [debug] Loaded engine "Catalyst::Engine::HTTP"
-    [debug] Found home "/home/me/Hello"
-    [debug] Loaded Config "/home/me/Hello/hello.conf"
-    [debug] Loaded components:
-    .-----------------------------------------------------------------+----------.
-    | Class                                                           | Type     |
-    +-----------------------------------------------------------------+----------+
-    | Hello::Controller::Root                                         | instance |
-    '-----------------------------------------------------------------+----------'
-    
-    [debug] Loaded Private actions:
-    .----------------------+--------------------------------------+--------------.
-    | Private              | Class                                | Method       |
-    +----------------------+--------------------------------------+--------------+
-    | /default             | Hello::Controller::Root              | default      |
-    | /end                 | Hello::Controller::Root              | end          |
-    | /index               | Hello::Controller::Root              | index        |
-    '----------------------+--------------------------------------+--------------'
-    
-    [debug] Loaded Path actions:
-    .-------------------------------------+--------------------------------------.
-    | Path                                | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /                                   | /default                             |
-    | /                                   | /index                               |
-    '-------------------------------------+--------------------------------------'
-    
-    [info] Hello powered by Catalyst 5.80003
-    You can connect to your server at http://debian:3000
-
-Point your web browser to L<http://localhost:3000> (substituting a 
-different hostname or IP address as appropriate) and you should be 
-greeted by the Catalyst welcome screen (if you get some other welcome 
-screen or an "Index" screen, you probably forgot to specify port 3000 
-in your URL).  Information similar to the following should be appended 
-to the logging output of the development server:
-
-    [info] *** Request 1 (0.005/s) [20712] [Sun Mar  8 15:49:09 2009] ***
-    [debug] "GET" request for "/" from "1.1.1.98"
-    [info] Request took 0.007342s (136.203/s)
-    .----------------------------------------------------------------+-----------.
-    | Action                                                         | Time      |
-    +----------------------------------------------------------------+-----------+
-    | /index                                                         | 0.000491s |
-    | /end                                                           | 0.000595s |
-    '----------------------------------------------------------------+-----------'
-
-Press Ctrl-C to break out of the development server.
-
-
-=head1 HELLO WORLD
-
-=head2 The Simplest Way
-
-The Root.pm controller is a place to put global actions that usually 
-execute on the root URL. Open the C<lib/Hello/Controller/Root.pm> file in 
-your editor. You will see the "index" subroutine, which is 
-responsible for displaying the welcome screen that you just saw in 
-your browser. Later on you'll want to change that to something more 
-reasonable, such as a "404" message or a redirect, but for now just 
-leave it alone.
-
-    sub index :Path :Args(0) {
-        my ( $self, $c ) = @_;
-        
-        # Hello World
-        $c->response->body( $c->welcome_message );
-    }
-
-The "C<$c>" here refers to the Catalyst context, which is used to 
-access the Catalyst application. In addition to many other things, 
-the Catalyst context provides access to "response" and "request" 
-objects. (See L<Catalyst|Catalyst>, 
-L<Catalyst::Response|Catalyst::Response>, and 
-L<Catalyst::Request|Catalyst::Request>) 
-
-C<$c-E<gt>response-E<gt>body> sets the HTTP response (see 
-L<Catalyst::Response|Catalyst::Response>), while C<$c-E<gt>welcome_message> 
-is a special method that returns the welcome message that you saw in 
-your browser.
-
-The ":Path :Args(0)" after the method name are attributes which determine 
-which URLs will be dispatched to this method. (Depending on your version of 
-Catalyst, it used to say "Private" but using that with 'default' or 'index' 
-is currently deprecated.)
-
-Some MVC frameworks handle dispatching in a central place. Catalyst, 
-by policy, prefers to handle URL dispatching with attributes on 
-controller methods. There is a lot of flexibility in specifying which 
-URLs to match.  This particular method will match all URLs, because it 
-doesn't specify the path (nothing comes after "Path"), but will only 
-accept a single args because of the ":Args(0)". 
-
-The default is to map URLs to controller names, and because of 
-the way that Perl handles namespaces through package names, 
-it is simple to create hierarchical structures in 
-Catalyst. This means that you can create controllers with deeply 
-nested actions in a clean and logical way. 
-
-For example, the URL C<http://hello.com/admin/articles/create> maps 
-to the package C<Hello::Controller::Admin::Articles>, and the C<create>
-method. 
-
-Add the following subroutine to your C<lib/Hello/Controller/Root.pm> 
-file:
-
-    sub hello : Global {
-        my ( $self, $c ) = @_;
-        
-        $c->response->body("Hello, World!");
-    }
-
-B<TIP>: See Appendix 1 for tips on removing the leading spaces when
-cutting and pasting example code from POD-based documents.
-
-Here you're sending your own string to the webpage.
-
-Save the file, start the server (stop and restart it if it's still 
-up), and go to L<http://localhost:3000/hello> to 
-see "Hello, World!"
-
-
-=head2 Hello, World! Using a View and a Template
-
-In the Catalyst world  a "View" is not a page of XHTML or a template 
-designed to present a page to a browser. It is the module that 
-determines the I<type> of view -- HTML, pdf, XML, etc. For the 
-thing that generates the I<content> of that view, (such as the 
-default Toolkit Template) the actual templates go under the 
-"root" directory.
-
-To create a TT view, run:
-
-    $ script/hello_create.pl view TT TT
-
-This creates the C<lib/Hello/View/TT.pm> module, which is a subclass of 
-C<Catalyst::View::TT>. 
-
-=over 4
-
-=item *
-
-The "view" keyword tells the create script that you are creating a view.
-
-=item *
-
-The first "TT" tells the script to name the View module "TT.pm", which is a
-commonly used name for TT views.  (You can name it anything you want, such as
-"HTML.pm".)
-
-=item *
-
-The final "TT" tells it that you are creating a Template Toolkit view.
-
-=back
-
-If you look at C<lib/Hello/View/TT.pm> you will find that it only contains a
-config statement to set the TT extension to ".tt".
-
-Now that the TT.pm "View" exists, Catalyst will autodiscover it and be 
-able to use it to display the view templates, using the "process" 
-method that it inherits from the C<Catalyst::View::TT class>.
-
-Template Toolkit is a very full featured template facility, with 
-excellent documentation at L<http://template-toolkit.org/>, 
-but since this is not a TT tutorial, we'll stick to only basic TT 
-usage here (and explore some of the more common TT features in later 
-chapters of the tutorial).
-
-Create a C<root/hello.tt> template file (put it in the C<root> under 
-the C<Hello> directory that is the base of your application). Here is 
-a simple sample:
-  
-    <p>
-        This is a TT view template, called '[% template.name %]'.
-    </p>
-
-[% and %] are markers for the TT parts of the template. Inside you can 
-access Perl variables and classes, and use TT directives. In this 
-case, we're using a special TT variable that defines the name of the 
-template file (C<hello.tt>).  The rest of the template is normal HTML. 
-
-Change the hello method in C<lib/Hello/Controller/Root.pm> to the 
-following:
-
-    sub hello : Global {
-        my ( $self, $c ) = @_;
-        
-        $c->stash->{template} = 'hello.tt';
-    }
-
-This time, instead of doing C<$c-E<gt>response-E<gt>body()>, you are setting 
-the value of the "template" hash key in the Catalyst "stash", an area 
-for putting information to share with other parts of your application. 
-The "template" key determines which template will be displayed at the 
-end of the method. Catalyst controllers have a default "end" action 
-for all methods which causes the first (or default) view to be 
-rendered (unless there's a C<$c-E<gt>response-E<gt>body()> statement). So your 
-template will be magically displayed at the end of your method.
-
-After saving the file, restart the development server, and look at 
-L<http://localhost:3000/hello> again. You should 
-see the template that you just made.
-
-
-=head1 CREATE A SIMPLE CONTROLLER AND AN ACTION
-
-Create a controller named "Site" by executing the create script:
-
-    $ script/hello_create.pl controller Site
-
-This will create a C<lib/Hello/Controller/Site.pm> file (and a test 
-file). Bring Site.pm up in your editor, and you can see that there's 
-not much there. Most people probably don't bother to use the create 
-script to make controllers after they're used to using Catalyst.
-
-In C<lib/Hello/Controller/Site.pm>, add the following method:
-
-    sub test : Local {
-        my ( $self, $c ) = @_;
-    
-        $c->stash->{username} = "John";
-        $c->stash->{template} = 'site/test.tt';
-    }
-
-Notice the "Local" attribute on the C<test> method. This will cause 
-the C<test> action (now that we have assigned an action type to the 
-method it appears as a controller "action" to Catalyst) to be executed 
-on the "controller/method" URL, or, in this case, "site/test".  We 
-will see additional information on controller actions throughout the 
-rest of the tutorial, but if you are curious take a look at 
-L<Catalyst::Manual::Intro/Actions>.
-
-It's not actually necessary to set the template value as we do here. 
-By default TT will attempt to render a template that follows the 
-naming pattern "controller/method.tt", and we're following that 
-pattern here. However, in other situations you will need to specify 
-the template (such as if you've "forwarded" to the method, or if it 
-doesn't follow the default naming convention).
-
-We've also put the variable "username" into the stash, for use in the 
-template.
-
-Make a subdirectory "site" in the "root" directory. Copy the hello.tt 
-file into the directory as C<root/site/test.tt>, or create a new 
-template file at that location. Include a line like: 
-
-    <p>Hello, [% username %]!</p>
-
-Bring up or restart the server.  Notice in the server output that 
-C</site/test> is listed in the Loaded Path actions. Go to 
-L<http://localhost:3000/site/test> in your browser.
-
-You should see your test.tt file displayed, including the name "John"
-that you set in the controller.
-
-
-=head1 AUTHORS
-
-Gerda Shank, C<gerda.shank at gmail.com>
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark & Gerda Shank, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Debugging.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,380 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::Debugging - Catalyst Tutorial - Chapter 7: Debugging
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 7 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-B<Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This chapter of the tutorial takes a brief look at the primary options 
-available for troubleshooting Catalyst applications.
-
-Note that when it comes to debugging and troubleshooting, there are two
-camps:
-
-=over 4
-
-=item * 
-
-Fans of C<log> and C<print> statements embedded in the code.
-
-=item * 
-
-Fans of interactive debuggers.
-
-=back
-
-Catalyst is able to easily accommodate both styles of debugging.
-
-
-=head1 LOG STATEMENTS
-
-Folks in the former group can use Catalyst's C<$c-E<gt>log> facility. 
-(See L<Catalyst::Log|Catalyst::Log> for more detail.) For example, if 
-you add the following code to a controller action method:
-
-    $c->log->info("Starting the foreach loop here");
-
-    $c->log->debug("Value of \$id is: ".$id);
-
-Then the Catalyst development server will display your message along
-with the other debug output. To accomplish the same thing in a TT
-template view use:
-
-    [% c.log.debug("This is a test log message") %]
-
-As with many other logging facilities, you a method is defined for
-each of the following "logging levels" (in increasing order of
-severity/importance):
-
-    $c->log->debug
-    $c->log->info
-    $c->log->warn
-    $c->log->error
-    $c->log->fatal
-
-You can also use L<Data::Dumper|Data::Dumper> in both Catalyst code 
-(C<use Data::Dumper; $c-E<gt>log-E<gt>debug("\$var is: ".Dumper($var));)>) 
-and TT templates (C<[% Dumper.dump(book) %]>.
-
-
-=head1 RUNNING CATALYST UNDER THE PERL DEBUGGER
-
-Members of the interactive-debugger fan club will also be at home with
-Catalyst applications.  One approach to this style of Perl debugging is
-to embed breakpoints in your code.  For example, open
-C<lib/MyApp/Controller/Books.pm> in your editor and add the
-C<DB::single=1> line as follows inside the C<list> method (I like to
-"left-justify" my debug statements so I don't forget to remove them, but
-you can obviously indent them if you prefer):
-
-    sub list : Local {
-        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
-        # 'Context' that's used to 'glue together' the various components
-        # that make up the application
-        my ($self, $c) = @_;
-    
-    $DB::single=1;
-            
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
-            
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods.
-        $c->stash->{template} = 'books/list.tt2';
-    }
-
-This causes the Perl Debugger to enter "single step mode" when this command is 
-encountered (it has no effect when Perl is run without the C<-d> flag).
-
-B<NOTE:> The C<DB> here is the Perl Debugger, not the DB model.
-
-If you haven't done it already, enable SQL logging as before:
-
-    $ export DBIC_TRACE=1
-
-To now run the Catalyst development server under the Perl debugger, simply 
-prepend C<perl -d> to the front of C<script/myapp_server.pl>:
-
-    $ perl -d script/myapp_server.pl
-
-This will start the interactive debugger and produce output similar to:
-
-    $ perl -d script/myapp_server.pl  
-    
-    Loading DB routines from perl5db.pl version 1.3
-    Editor support available.
-    
-    Enter h or `h h' for help, or `man perldebug' for more help.
-    
-    main::(script/myapp_server.pl:16):      my $debug         = 0;
-    
-      DB<1> 
-
-Press the C<c> key and hit C<Enter> to continue executing the Catalyst
-development server under the debugger.  Although execution speed will be
-slightly slower than normal, you should soon see the usual Catalyst
-startup debug information.
-
-Now point your browser to L<http://localhost:3000/books/list> and log
-in.  Once the breakpoint is encountered in the
-C<MyApp::Controller::list> method, the console session running the
-development server will drop to the Perl debugger prompt:
-
-    MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:48):
-    48:         $c->stash->{books} = [$c->model('DB::Book')->all];
-    
-      DB<1>
-
-You now have the full Perl debugger at your disposal.  First use the
-C<next> feature by typing C<n> to execute the C<all> method on the Book
-model (C<n> jumps over method/subroutine calls; you can also use C<s> to
-C<single-step> into methods/subroutines):
-
-      DB<1> n
-    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
-    MyApp::Controller::Books::list(/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm:53):
-    53:         $c->stash->{template} = 'books/list.tt2';
-    
-      DB<1>
-
-This takes you to the next line of code where the template name is set.
-Notice that because we enabled C<DBIC_TRACE=1> earlier, SQL debug 
-output also shows up in the development server debug information.
-
-Next, list the methods available on our C<Book> model:
-
-      DB<1> m $c->model('DB::Book')
-    ()
-    (0+
-    (bool
-    __result_class_accessor
-    __source_handle_accessor
-    _add_alias
-    __bool
-    _build_unique_query
-    _calculate_score
-    _collapse_cond
-    <lines removed for brevity>
-    
-      DB<2>
-
-We can also play with the model directly:
-
-      DB<2> x ($c->model('DB::Book')->all)[1]->title
-    SELECT me.id, me.title, me.rating, me.created, me.updated FROM book me:
-    0  'TCP/IP Illustrated, Volume 1'
-
-This uses the Perl debugger C<x> command to display the title of a book.
-
-Next we inspect the C<books> element of the Catalyst C<stash> (the C<4>
-argument to the C<x> command limits the depth of the dump to 4 levels):
-
-      DB<3> x 4 $c->stash->{books}
-    0  ARRAY(0xa8f3b7c)
-       0  MyApp::Model::DB::Book=HASH(0xb8e702c)
-          '_column_data' => HASH(0xb8e5e2c)
-             'created' => '2009-05-08 10:19:46'
-             'id' => 1
-             'rating' => 5
-             'title' => 'CCSP SNRS Exam Certification Guide'
-             'updated' => '2009-05-08 10:19:46'
-          '_in_storage' => 1
-    <lines removed for brevity>
-
-Then enter the C<c> command to continue processing until the next
-breakpoint is hit (or the application exits):
-
-      DB<4> c
-    SELECT author.id, author.first_name, author.last_name FROM ...
-
-Finally, press C<Ctrl+C> to break out of the development server.
-Because we are running inside the Perl debugger, you will drop to the
-debugger prompt.  
-
-    ^CCatalyst::Engine::HTTP::run(/usr/local/share/perl/5.10.0/Catalyst/Engine/HTTP.pm:260):
-    260:            while ( accept( Remote, $daemon ) ) {
-
-    DB<4>
-
-Finally, press C<q> to exit the debugger and return to your OS
-shell prompt:
-
-      DB<4> q
-    $
-
-For more information on using the Perl debugger, please see C<perldebug>
-and C<perldebtut>.  For those daring souls out there, you can dive down
-even deeper into the magical depths of this fine debugger by checking
-out C<perldebguts>.
-
-You can also type C<h> or C<h h> at the debugger prompt to view the
-built-in help screens.
-
-For an excellent book covering all aspects of the Perl debugger, we highly
-recommend reading 'Pro Perl Debugging' by Richard Foley.
-
-Oh yeah, before you forget, be sure to remove the C<DB::single=1> line you
-added above in C<lib/MyApp/Controller/Books.pm>.
-
-=head1 DEBUGGING MODULES FROM CPAN
-
-Although the techniques discussed above work well for code you are 
-writing, what if you want to use print/log/warn messages or set 
-breakpoints in code that you have installed from CPAN (or in module that 
-ship with Perl)?  One helpful approach is to place a copy of the module 
-inside the C<lib> directory of your Catalyst project.  When Catalyst 
-loads, it will load from inside your C<lib> directory first, only 
-turning to the global modules if a local copy cannot be found.  You can 
-then make modifications such as adding a C<$DB::single=1> to the local 
-copy of the module without risking the copy in the original location. 
-This can also be a great way to "locally override" bugs in modules while 
-you wait for a fix on CPAN.
-
-
-Matt Trout has suggested the following shortcut to create a local
-copy of an installed module:
-
-    mkdir -p lib/Module; cp `perldoc -l Module::Name` lib/Module/
-
-Note: If you are following along in Debian 5 or Ubuntu, you will
-need to install the C<perl-doc> package to use the C<perldoc> command.  
-Use C<sudo aptitude install perl-doc> to do that.
-
-For example, you could make a copy of 
-L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>
-with the following command:
-
-    mkdir -p lib/Catalyst/Plugin; cp \
-        `perldoc -l Catalyst::Plugin::Authentication` lib/Catalyst/Plugin
-
-You can then use the local copy inside your project to place logging
-messages and/or breakpoints for further study of that module.
-
-B<Note:> Matt has also suggested the following tips for Perl 
-debugging:
-
-=over 4
-
-=item * 
-
-Check the version of an installed module:
-
-    perl -ME<lt>mod_nameE<gt> -e '"print $E<lt>mod_nameE<gt>::VERSION\n"'
-
-For example:
-
-    $ perl -MCatalyst::Plugin::Authentication -e \
-        'print $Catalyst::Plugin::Authentication::VERSION;'
-    0.07
-
-and if you are using bash aliases:
-
-    alias pmver="perl -le '\$m = shift; eval qq(require \$m) \
-        or die qq(module \"\$m\" is not installed\\n); \
-        print \$m->VERSION'"
-
-=item * 
-
-Check if a modules contains a given method:
-
-    perl -MModule::Name -e 'print Module::Name->can("method");'
-
-For example:
-
-    $ perl -MCatalyst::Plugin::Authentication -e \
-        'print Catalyst::Plugin::Authentication->can("user");'
-    CODE(0x9c8db2c)
-
-If the method exists, the Perl C<can> method returns a coderef.
-Otherwise, it returns undef and nothing will be printed.
-
-=back
-
-
-=head1 TT DEBUGGING
-
-If you run into issues during the rendering of your template, it might 
-be helpful to enable TT C<DEBUG> options.  You can do this in a Catalyst 
-environment by adding a C<DEBUG> line to the C<__PACKAGE__->config> 
-declaration in C<lib/MyApp/View/TT.pm>:
-
-    __PACKAGE__->config({
-        TEMPLATE_EXTENSION => '.tt2',
-        DEBUG              => 'undef',
-    });
-
-There are a variety of options you can use, such as 'undef', 'all', 
-'service', 'context', 'parser' and 'provider'.  See 
-L<Template::Constants|Template::Constants> for more information 
-(remove the C<DEBUG_> portion of the name shown in the TT docs and 
-convert to lower case for use inside Catalyst).
-
-B<NOTE:> B<Please be sure to disable TT debug options before continuing 
-with the tutorial> (especially the 'undef' option -- leaving this 
-enabled will conflict with several of the conventions used by this 
-tutorial to leave some variables undefined on purpose).
-
-Happy debugging.
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Intro.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Intro.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Intro.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,642 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::Intro - Catalyst Tutorial - Chapter 1: Introduction
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 1 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-B<Introduction>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This tutorial provides a multi-part introduction to the Catalyst web
-framework. It seeks to provide a rapid overview of many of its most
-commonly used features. The focus is on the real-world best practices
-required in the construction of nearly all Catalyst applications.
-
-Although the primary target of the tutorial is users new to the Catalyst
-framework, experienced users may wish to review specific sections (for
-example, how to use DBIC for their model classes, how to add
-authentication and authorization to an existing application, or form
-management).
-
-You can obtain the code for all the tutorial examples from the
-catalyst subversion repository by issuing the command:
-
-    svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/ CatalystTutorial
-
-This will download the most recent tarball for each chapter of the 
-tutorial into the CatalystTutorial directory on your machine. 
-
-B<These reference implementations are provided so that when you follow
-the tutorial, you can use the code from the subversion repository to
-ensure that your system is set up correctly, and that you have not
-inadvertently made any typographic errors, or accidentally skipped
-part of the tutorial.>
-
-B<NOTE: You can use any Perl-supported OS and environment to run 
-Catalyst.> It should make little or no difference to Catalyst's 
-operation, B<but this tutorial has been written using the Debian 5 
-live CD> because that represents a quick and easy for most people to 
-try out Catalyst with virtually zero setup time and hassles.  Also, 
-the tutorial has been tested to work correctly with the versions of 
-Catalyst and all the supporting modules in Debian 5 (see "VERSIONS 
-AND CONVENTIONS USED IN THIS TUTORIAL" below for the specific versions 
-for some of the key modules), so B<if you think you might be running 
-into an issue related to versions> (for example, a module changed its 
-behavior in a newer version or a bug was introduced), B<it might be 
-worth giving Debian 5 a try>.  See the "CATALYST INSTALLATION" 
-section below for more information.
-
-If you're reading this manual online, you can download the example 
-program and all the necessary dependencies to your local machine by 
-installing the C<Task::Catalyst::Tutorial> distribution from CPAN:
-
-     cpan Task::Catalyst::Tutorial
-
-This will also test to make sure the dependencies are working.  If you
-have trouble installing these, please ask for help on the #catalyst
-IRC channel, or the Catalyst mailing list.
-
-Subjects covered by the tutorial include:
-
-=over 4
-
-=item * 
-
-A simple application that lists and adds books.
-
-=item *
-
-The use of L<DBIx::Class|DBIx::Class> (DBIC) for the model (including 
-some of the more advanced techniques you will probably want to use in 
-your applications).
-
-=item * 
-
-How to write CRUD (Create, Read, Update, and Delete) operations in
-Catalyst.
-
-=item *
-
-Authentication ("auth").
-
-=item * 
-
-Role-based authorization ("authz").
-
-=item * 
-
-Attempts to provide an example showing current (5.8XXX) Catalyst
-practices. For example, the use of 
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>,
-DBIC, L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader> 
-with C<myapp.conf>, the use of C<lib/MyApp/Controller/Root.pm> 
-vs. C<lib/MyApp.pm>, etc.
-
-=item * 
-
-The use of Template Toolkit (TT).
-
-=item * 
-
-Useful techniques for troubleshooting and debugging Catalyst
-applications.
-
-=item * 
-
-The use of SQLite as a database (with code also provided for MySQL and
-PostgreSQL).
-
-=item * 
-
-The use of L<HTML::FormFu|HTML::FormFu> for automated form processing 
-and validation.
-
-=back
-
-This tutorial makes the learning process its main priority.  For
-example, the level of comments in the code found here would likely be
-considered excessive in a "normal project."  Because of their contextual
-value, this tutorial will generally favor inline comments over a
-separate discussion in the text.  It also deliberately tries to
-demonstrate multiple approaches to various features (in general, you
-should try to be as consistent as possible with your own production
-code).
-
-Furthermore, this tutorial tries to minimize the number of controllers,
-models, TT templates, and database tables.  Although this does result in
-things being a bit contrived at times, the concepts should be applicable
-to more complex environments.  More complete and complicated example
-applications can be found in the C<examples> area of the Catalyst
-Subversion repository at
-L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/>.
-
-
-=head1 VERSIONS AND CONVENTIONS USED IN THIS TUTORIAL
-
-This tutorial was built using the following resources. Please note that
-you may need to make adjustments for different environments and
-versions:
-
-=over 4
-
-=item * 
-
-Debian 5 (Lenny)
-
-=item * 
-
-Catalyst v5.80004
-
-=item *
-
-Catalyst::Devel v1.10
-
-=item * 
-
-DBIx::Class v0.08102
-
-=item * 
-
-Catalyst Plugins
-
-The plugins used in this tutorial all have sufficiently stable APIs that
-you shouldn't need to worry about versions. However, there could be
-cases where the tutorial is affected by what version of plugins you
-use. This tutorial has been tested against the following set of plugins:
-
-=over 4
-
-=item * 
-
-Catalyst::Plugin::Authentication -- v0.10011
-
-=item *
-
-Catalyst::Plugin::Authorization::Roles -- v0.07
-
-=item *
-
-Catalyst::Plugin::ConfigLoader -- v0.22
-
-=item *
-
-Catalyst::Plugin::Session -- v0.20
-
-=item *
-
-Catalyst::Plugin::Session::State::Cookie -- v0.10
-
-=item *
-
-Catalyst::Plugin::Session::Store::FastMmap -- v0.07
-
-=item *
-
-Catalyst::Plugin::StackTrace -- v0.09
-
-=item *
-
-Catalyst::Plugin::Static::Simple -- v0.21
-
-=back
-
-=item * 
-
-B<NOTE:> You can check the versions you have installed with the
-following command:
-
-    perl -M<_mod_name_> -e '"print $<_mod_name_>::VERSION\n"'
-
-For example:
-    perl -MCatalyst::Plugin::StackTrace -e 'print "$Catalyst::Plugin::StackTrace::VERSION\n"'
-
-Since the web browser is being used on the same box where Perl and the
-Catalyst development server is running, the URL of
-C<http://localhost:3000> will be used (the Catalyst development server
-defaults to port 3000).  If you are running Perl on a different box than
-where your web browser is located (or using a different port number via
-the C<-p> I<port_number> option to the development server), then you
-will need to update the URL you use accordingly.
-
-=item * 
-
-Depending on the web browser you are using, you might need to hit 
-C<Shift+Reload> or C<Ctrl+Reload> to pull a fresh page when testing 
-your application at various points (see 
-L<http://en.wikipedia.org/wiki/Bypass_your_cache> for a comprehensive
-list of options for each browser).  Also, the C<-k> keepalive option 
-to the development server can be necessary with some browsers 
-(especially Internet Explorer).
-
-=back
-
-
-=head1 CATALYST INSTALLATION
-
-Although Catalyst installation has been a challenge in the past, the 
-good news is that there are a growing number of options to eliminate 
-(or at least dramatically simplify) this concern.  Although a 
-compelling strength of Catalyst is that it makes use of many of the 
-modules in the vast repository that is CPAN, this can complicate the 
-installation process if you approach it in the wrong way.  Consider 
-the following suggestions on the most common ways to get started with 
-a Catalyst development environment:
-
-=over 4
-
-=item *
-
-Debian
-
-The Debian 5 live CD represents a great way for newcomers to 
-experiment with Catalyst.  As a "live CD," you can simple boot from 
-the CD, run a few commands, and in a matter of minutes you should have 
-a fully function environment in which do this tutorial. B<The tutorial 
-was fully tested to work under Debian 5.  Although it SHOULD work 
-under any Catalyst installation method you might choose, it can be 
-hard to guarantee this.>
-
-=over 4
-
-=item * 
-
-Download one of the ISO files from 
-L<http://cdimage.debian.org/cdimage/release/current-live/i386/iso-cd/>. 
-You can pick any one of the live CD variations will work, but 
-you may wish to consider the following points:
-
-=over 4
-
-=item *
-
-"C<debian-live-500-i386-rescue.iso>" is probably the best all-around 
-option for most people because it includes many extra tools such as 
-the GCC compiler, therefore saving RAM (every package you need to 
-install when running from live CD consumes memory because RAM disk is 
-being used in lieu of real disk space).  When initially booting under 
-this image, you may see some cryptic warning messages having to do 
-with various diagnostic tools it tries to load or enable, but you 
-should be able to safely ignore these.
-
-=item *
-
-"C<debian-live-500-i386-standard.iso>" is a great option because of 
-its compact size, but you will probably need approximately 1 GB of RAM 
-in the computer where you will run the tutorial.  Because the 
-"standard" live CD comes with with a minimal set of tools, we will 
-have to install extra packages (such as the GCC compiler), all of 
-which will require RAM when running from a live CD. 
-
-=item *
-
-The other ISO images include different flavors of X-Windows desktop 
-managers.  You can select one of these if you don't mind the larger 
-download size and prefer a graphical environment.  Be aware that these 
-disks do not come with the extra tools found on the "rescue" image, so 
-you will need adequate RAM to be able to install them just as you 
-would under the "standard" image. B<Use one of the "graphical" ISO 
-images if you want a graphical web browser on the same machine as 
-where you will run the tutorial.>  (If you are using one of the non-
-graphical images discussed above, you can still use a graphical web 
-browser from another machine and point it to your Catalyst development 
-machine.)
-
-=back
-
-=item *
-
-Boot off the CD.
-
-=item *
-
-Select "C<Live>" from the initial boot menu.
-
-=item *
-
-Once the system has booted to a "C<user at debian:~$>" prompt, enter the 
-following command to add the more current "unstable" package 
-repository:
-
-    sudo vi /etc/apt/sources.list
-
-Add the following line to the bottom of this file:
-
-    deb http://ftp.us.debian.org/debian/ unstable main
-
-If you are not familiar with VI, you can move to the bottom of this 
-file and press the "o" key to insert a new line and type the line 
-above.  Then press the "Esc" key followed by a colon (":"), the 
-letters "wq" and then the "Enter" key.  The rest of the tutorial will 
-assume that you know how to use some editor that is available from the 
-Linux command-line environment.
-
-=item *
-
-Install Catalyst:
-
-    sudo aptitude update
-    sudo aptitude -y install sqlite3 libdbd-sqlite3-perl libcatalyst-perl \
-        libcatalyst-modules-perl libconfig-general-perl libsql-translator-perl \
-        libdatetime-perl libdatetime-format-mysql-perl libio-all-perl \
-        libperl6-junction-perl libmoosex-emulate-class-accessor-fast-perl
-
-Let it install (normally about a 30-second operaton) and you are 
-done.  
-
-If you are using an image other than the "rescue" ISO, you will also need
-to run the following command to install additional packages:
-
-    sudo aptitude -y install gcc make libc6-dev
-
-If you are running from the Live CD, you probably also want to free up 
-some RAM disk space with the following:
-
-    sudo aptitude clean
-
-NOTE: While the instructions above mention the Live CD because that 
-makes it easy for people new to Linux, you can obviously pick a 
-different Debian ISO image and install it to your hard drive. 
-Although there are many different ways to download and install Debian, 
-the "netinst" ISO image (such as "C<debian-500-i386-netinst.iso>" 
-represents a great option because it keeps your initial download small 
-(but still let's you install anything you want "over the network").
-
-Here are some tips if you are running from a live CD and are running
-out of disk space (which really means you are running out of RAM):
-
-=over 4
-
-=item *
-
-Always run "C<aptitude clean>" after you install new packages to 
-delete the original .deb files (the files installed B<by> the .deb 
-package B<will> remain available, just the .deb package itself is 
-deleted).
-
-=item *
-
-If you are installing modules from CPAN, you can free up some space 
-with "C<rm -rf /root/.cpan/*>".
-
-=item *
-
-If necessary, you can remove the cached package information with the 
-command "C<rm -f /var/lib/apt/lists/*>".  You can later pull this 
-information again via the command "C<aptitude update>".
-
-=item * 
-
-You can save a small amount of space by commenting out the lines in 
-C</etc/apt/sources.list> that reference "deb-src" and 
-"security.debian.org".  If you have already done an "C<aptitude 
-update>" with these repositories enabled, you can use the tip in the 
-previous bullet to free the space up (and then do another "C<aptitude 
-update>").
-
-=item *
-
-Although you can free up space by removing packages you installed 
-since you last booted (check out "C<aptitude remove _pkg_name>"), 
-don't bother trying to remove packages already available at the time 
-of boot. Instead of freeing up space, it will actual I<consume> some 
-space. (The live CD uses these "burn in" packages right from the CD 
-disk vs. first loading them on the virtual RAM disk. However, if you 
-remove them, the system has to update various files, something that 
-I<does> consume some space on the virtual RAM disk.)
-
-=back
-
-=back
-
-=item *
-
-Ubuntu
-
-Ubuntu is an extremely popular offshoot of Debian.  It provides 
-cutting edge versions of many common tools, application and libraries 
-in an easy-to-run live CD configuration (and because a single download 
-option can be used for both live CD and install-to-disk usage, it 
-keeps your download options nice and simple).  As with Debian 5, you 
-should be able to generate a fully function Catalyst environment in a 
-matter of minutes.  Here are quick instructions on how to use Ubuntu 
-to prepare for the tutorial:
-
-=over 4
-
-=item * 
-
-Download the Ubuntu Desktop edition and boot from the CD and/or image 
-file, select your language, and then "Try Ubuntu without any changes 
-to your computer."
-
-=item *
-
-Open a terminal session (click "Applications" in the upper-left 
-corner, then "Accessories," then "Terminal").
-
-=item *
-
-Add the 'universe' repositories:
-
-    sudo gedit /etc/apt/sources.list
-
-And remove the comments from the lines under the comments about the
-'universe' repositories.
-
-=item *
-
-Install Catalyst:
-
-    sudo aptitude update
-    sudo aptitude install libdbd-sqlite3-perl libcatalyst-perl libcatalyst-modules-perl libconfig-general-perl
-
-Accept all of the dependencies.  Done.  
-
-If you are running from the Live CD, you probably also want to free up 
-some disk space with the following:
-
-    sudo aptitude clean
-
-NOTE: While the instructions above mention the live CD because that 
-makes it easy for people new to Linux, you can obviously also use one 
-of the options to install Ubuntu on your drive.
-
-=back
-
-=item * 
-
-Matt Trout's C<cat-install>
-
-Available at L<http://www.shadowcatsystems.co.uk/static/cat-install>, 
-C<cat-install> can be a fairly painless way to get Catalyst up and 
-running.  Just download the script from the link above and type C<perl 
-cat-install>.  Depending on the speed of your Internet connection and 
-your computer, it will probably take 30 to 60 minutes to install because 
-it downloads, makes, compiles, and tests every module.  But this is an 
-excellent way to automate the installation of all the latest modules 
-used by Catalyst from CPAN.
-
-
-=item * 
-
-Other Possibilities
-
-=over 4
-
-=item *
-
-OpenBSD Packages
-
-The 2008 Advent Day 4 entry has more information on using OpenBSD 
-packages to quickly build a system: 
-L<http://www.catalystframework.org/calendar/2008/4>.
-
-=item *
-
-NetBSD Package Collection on Solaris
-
-The 2008 Advent Day 15 entry has more information on using C<pkgsrc> and 
-NetBSD packages on Solaris: 
-L<http://www.catalystframework.org/calendar/2008/15>.
-
-=item * 
-
-CatInABox
-
-You can get more information at 
-L<http://www.catalystframework.org/calendar/2008/7>
-or L<Perl::Dist::CatInABox|Perl::Dist::CatInABox>.
-
-=item * 
-
-Frank Speiser's Amazon EC2 Catalyst SDK
-
-There are currently two flavors of publicly available Amazon Machine
-Images (AMI) that include all the elements you'd need to begin
-developing in a fully functional Catalyst environment within minutes.
-See L<Catalyst::Manual::Installation|Catalyst::Manual::Installation>
-for more details.
-
-=back
-
-=back
-
-For additional information and recommendations on Catalyst installation,
-please refer to 
-L<Catalyst::Manual::Installation|Catalyst::Manual::Installation>.
-
-
-=head1 DATABASES
-
-This tutorial will primarily focus on SQLite because of its simplicity
-of installation and use; however, modifications in the script required
-to support MySQL and PostgreSQL will be presented in Appendix.
-
-B<Note:> One of the advantages of the MVC design patterns is that
-applications become much more database independent.  As such, you will
-notice that only the C<.sql> files used to initialize the database
-change between database systems: the Catalyst code generally remains the
-same.
-
-
-=head1 WHERE TO GET WORKING CODE
-
-Each chapter of the tutorial has complete code available as a tarball in 
-the main Catalyst Subversion repository (see the note at the beginning 
-of each part for the appropriate svn command to use).
-
-B<NOTE:> You can run the test cases for the final code through Chapter 8 
-with the following commands:
-
-    sudo cpan Catalyst::Model::DBIC::Schema Time::Warp DBICx::TestDatabase \
-        DBIx::Class::DynamicDefault DBIx::Class::TimeStamp DBIx::Class::EncodedColumn
-    wget http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial/MyApp_Chapter8.tgz
-    tar zxvf MyApp_Chapter8.tgz
-    cd MyApp
-    CATALYST_DEBUG=0 prove --lib lib t
-
-If you wish to include the L<HTML::FormFu|HTML::FormFu> section in 
-your tests, substitute C<MyApp_Chapter9_FormFu.tgz> for 
-C<MyApp_Chapter8.tgz> in the URL above.  However, you will also need to 
-run the following additional commands:
-
-    sudo aptitude -y install libhtml-formfu-perl libmoose-perl \
-        libregexp-assemble-perl libhtml-formfu-model-dbic-perl
-    sudo aptitude clean
-    sudo cpan Catalyst::Component::InstancePerContext Catalyst::Controller::HTML::FormFu
-
-You can also fire up the application under the development server that is conveniently
-built in to Catalyst.  Just issue this command from the C<MyApp> directory where you
-ran the test suite above:
-
-    script/myapp_server.pl
-
-And the application will start.  You can try out the application by 
-pulling up C<http://localhost:3000> in your web browser (as mentioned 
-earlier, change C<localhost> to a different IP address or DNS name if 
-you are running your web browser and your Catalyst development on 
-different boxes).  We will obviously see more about how to use the 
-application as we go through the remaining chapters of the tutorial, but 
-for now you can log in using the username "test01" and a password of 
-"mypass".
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/MoreCatalystBasics.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,1498 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::MoreCatalystBasics - Catalyst Tutorial - Chapter 3: More Catalyst Application Development Basics
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 3 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-B<More Catalyst Basics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-L<Testing|Catalyst::Manual::Tutorial::Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-This chapter of the tutorial builds on the work done in Chapter 2 to 
-explore some features that are more typical of "real world" web 
-applications. From this chapter of the tutorial onward, we will be 
-building a simple book database application.  Although the application 
-will be too limited to be of use to anyone, it should provide a basic 
-environment where we can explore a variety of features used in 
-virtually all web applications.
-
-You can check out the source code for this example from the Catalyst
-Subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
-
-Please take a look at 
-L<Catalyst::Manual::Tutorial::Intro/CATALYST INSTALLATION> before 
-doing the rest of this tutorial.  Although the tutorial should work 
-correctly under most any recent version of Perl running on any 
-operating system, the tutorial has been written using Debian 5 and 
-tested to be sure it runs correctly in this environment.  
-
-
-=head1 CREATE A NEW APPLICATION
-
-The remainder of the tutorial will build an application called C<MyApp>.
-First use the Catalyst C<catalyst.pl> script to initialize the framework
-for the C<MyApp> application (make sure you aren't still inside the
-directory of the C<Hello> application from the previous chapter of the
-tutorial or in a directory that already has a "MyApp" subdirectory):
-
-    $ catalyst.pl MyApp
-    created "MyApp"
-    created "MyApp/script"
-    created "MyApp/lib"
-    created "MyApp/root"
-    ...
-    created "MyApp/script/myapp_create.pl"
-    $ cd MyApp
-
-This creates a similar skeletal structure to what we saw in Chapter 2 of
-the tutorial, except with C<MyApp> and C<myapp> substituted for
-C<Hello> and C<hello>.
-
-
-=head1 EDIT THE LIST OF CATALYST PLUGINS
-
-One of the greatest benefits of Catalyst is that it has such a large
-library of plugins and base classes available.  Plugins are used to
-seamlessly integrate existing Perl modules into the overall Catalyst
-framework.  In general, they do this by adding additional methods to the
-C<context> object (generally written as C<$c>) that Catalyst passes to
-every component throughout the framework.
-
-By default, Catalyst enables three plugins/flags:
-
-=over 4
-
-=item *
-
-C<-Debug> Flag
-
-Enables the Catalyst debug output you saw when we started the
-C<script/myapp_server.pl> development server earlier.  You can remove
-this item when you place your application into production.
-
-As you may have noticed, C<-Debug> is not a plugin, but a I<flag>. 
-Although most of the items specified on the C<__PACKAGE__-E<gt>setup> 
-line of your application class will be plugins, Catalyst supports a 
-limited number of flag options (of these, C<-Debug> is the most 
-common).  See the documentation for C<Catalyst.pm> to get details on 
-other flags (currently C<-Engine>, C<-Home>, and C<-Log>).
-
-If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
-messages.
-
-B<TIP>: Depending on your needs, it can be helpful to permanently
-remove C<-Debug> from C<lib/MyApp.pm> and then use the C<-d> option
-to C<script/myapp_server.pl> to re-enable it just for the development
-server.  We will not be using that approach in the tutorial, but feel
-free to make use of it in your own projects.
-
-=item *
-
-L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
-
-C<ConfigLoader> provides an automatic way to load configurable
-parameters for your application from a central
-L<Config::General|Config::General> file (versus having the values
-hard-coded inside your Perl modules).  Config::General uses syntax
-very similar to Apache configuration files.  We will see how to use
-this feature of Catalyst during the authentication and authorization
-sections (Chapter 5 and Chapter 6).
-
-B<IMPORTANT NOTE:> If you are using a version of 
-L<Catalyst::Devel|Catalyst::Devel> prior to version 1.06, be aware 
-that Catalyst changed the default format from YAML to the more 
-straightforward C<Config::General> style.  This tutorial uses the 
-newer C<myapp.conf> file for C<Config::General>. However, Catalyst 
-supports both formats and will automatically use either C<myapp.conf> 
-or C<myapp.yml> (or any other format supported by 
-L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader> and 
-L<Config::Any|Config::Any>).  If you are using a version of 
-Catalyst::Devel prior to 1.06, you can convert to the newer format by 
-simply creating the C<myapp.conf> file manually and deleting 
-C<myapp.yml>.  The default contents of the C<myapp.conf> you create 
-should only consist of one line: 
-
-    name MyApp
-
-B<TIP>: This script can be useful for converting between configuration
-formats:
-
-    perl -Ilib -e 'use MyApp; use Config::General;
-        Config::General->new->save_file("myapp.conf", MyApp->config);'
-
-=item *
-
-L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
-
-C<Static::Simple> provides an easy way to serve static content, such
-as images and CSS files, from the development server.
-
-=back
-
-For our application, we want to add one new plugin into the mix.  To 
-do this, edit C<lib/MyApp.pm> (this file is generally referred to as 
-your I<application class>) and delete the lines with:
-
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple/;
-
-Then replace it with:
-
-    # Load plugins
-    use Catalyst qw/-Debug
-                    ConfigLoader
-                    Static::Simple
-                
-                    StackTrace
-                    /;
-
-B<Note:> Recent versions of C<Catalyst::Devel> have used a variety of 
-techniques to load these plugins/flags.  For example, you might see
-the following:
-
-    __PACKAGE__->setup(qw/-Debug ConfigLoader Static::Simple/);
-
-Don't let these variations confuse you -- they all accomplish the same 
-result.
-
-This tells Catalyst to start using one new plugin, 
-L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>, to add a 
-stack trace to the standard Catalyst "debug screen" (the screen 
-Catalyst sends to your browser when an error occurs). Be aware that 
-L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your 
-browser, not in the console window from which you're running your 
-application, which is where logging output usually goes.
-
-Make sure that when adding new plugins that you include them as a new
-dependancies within the Makefile.PL file. For example, after adding
-the StackTrace plugin the Makefile.PL should include the following
-line:
-
-    requires 'Catalyst::Plugin::StackTrace';
-
-
-B<Notes:> 
-
-=over 4
-
-=item *
-
-C<__PACKAGE__> is just a shorthand way of referencing the name of the 
-package where it is used.  Therefore, in C<MyApp.pm>, C<__PACKAGE__> 
-is equivalent to C<MyApp>.
-
-=item *
-
-You will want to disable L<StackTrace|Catalyst::Plugin::StackTrace> 
-before you put your application into production, but it can be helpful 
-during development.
-
-=item *
-
-When specifying plugins on the C<__PACKAGE__-E<gt>setup> line, you can 
-omit C<Catalyst::Plugin::> from the name.  Additionally, you can 
-spread the plugin names across multiple lines as shown here, or place 
-them all on one (or more) lines as with the default configuration.
-
-=back
-
-
-=head1 CREATE A CATALYST CONTROLLER
-
-As discussed earlier, controllers are where you write methods that
-interact with user input.  Typically, controller methods respond to
-C<GET> and C<POST> requests from the user's web browser.
-
-Use the Catalyst C<create> script to add a controller for book-related
-actions:
-
-    $ script/myapp_create.pl controller Books
-     exists "/home/me/MyApp/script/../lib/MyApp/Controller"
-     exists "/home/me/MyApp/script/../t"
-    created "/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm"
-    created "/home/me/MyApp/script/../t/controller_Books.t"
-
-Then edit C<lib/MyApp/Controller/Books.pm> (as discussed in Chapter 2 of
-the Tutorial, Catalyst has a separate directory under C<lib/MyApp> for
-each of the three parts of MVC: C<Model>, C<View>, and C<Controller>)
-and add the following method to the controller:
-
-    =head2 list
-    
-    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
-    =cut
-    
-    sub list : Local {
-        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
-        # 'Context' that's used to 'glue together' the various components
-        # that make up the application
-        my ($self, $c) = @_;
-    
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
-        # $c->stash->{books} = [$c->model('DB::Book')->all];
-        # But, for now, use this code until we create the model later
-        $c->stash->{books} = '';
-    
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods (action methods respond to user input in
-        # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
-    }
-
-B<TIP>: See Appendix 1 for tips on removing the leading spaces when
-cutting and pasting example code from POD-based documents.
-
-Programmers experienced with object-oriented Perl should recognize 
-C<$self> as a reference to the object where this method was called. 
-On the other hand, C<$c> will be new to many Perl programmers who have 
-not used Catalyst before (it's sometimes written as C<$context>).  The 
-Context object is automatically passed to all Catalyst components.  It 
-is used to pass information between components and provide access to 
-Catalyst and plugin functionality.
-
-Catalyst actions are regular Perl methods, but they make use of 
-attributes (the "C<: Local>" next to the "C<sub list>" in the code 
-above) to provide additional information to the Catalyst dispatcher 
-logic (note that the space between the colon and the attribute name is 
-optional; you will see attributes written both ways).  Most Catalyst 
-Controllers use one of five action types:
-
-=over 4
-
-=item *
-
-B<:Private> -- Use C<:Private> for methods that you want to make into 
-an action, but you do not want Catalyst to directly expose  
-to your users.  Catalyst will not map C<:Private> methods to a URI. 
-Use them for various sorts of "special" methods (the C<begin>, 
-C<auto>, etc. discussed below) or for methods you want to be able to 
-C<forward> or C<detach> to.  (If the method is a plain old "helper 
-method" that you don't want to be an action at all, then just define 
-the method without any attribute -- you can call it in your code, but 
-the Catalyst dispatcher will ignore it.)
-
-There are five types of "special" build-in C<:Private> actions: 
-C<begin>, C<end>, C<default>, C<index>, and C<auto>.
-
-=over 4
-
-=item *
-
-With C<begin>, C<end>, C<default>, C<index> private actions, only the
-most specific action of each type will be called.  For example, if you
-define a C<begin> action in your controller it will I<override> a
-C<begin> action in your application/root controller -- I<only> the
-action in your controller will be called.
-
-=item *
-
-Unlike the other actions where only a single method is called for each
-request, I<every> auto action along the chain of namespaces will be
-called.  Each C<auto> action will be called I<from the application/root
-controller down through the most specific class>.
-
-=back
-
-=item *
-
-B<:Path> -- C<:Path> actions let you map a method to an explicit URI 
-path.  For example, "C<:Path('list')>" in 
-C<lib/MyApp/Controller/Books.pm> would match on the URL 
-C<http://localhost:3000/books/list> but "C<:Path('/list')>" would match 
-on C<http://localhost:3000/list>.  You can use C<:Args()> to specify 
-how many arguments an action should accept.  See 
-L<Catalyst::Manual::Intro/Action_types> for more information and a few 
-examples.
-
-=item *
-
-B<:Local> -- C<:Local> is merely a shorthand for 
-"C<:Path('_name_of_method_')>".  For example, these are equivalent:
-"C<sub create_book :Local {...}>" and 
-"C<sub create_book :Path('create_book') {...}>".
-
-=item *
-
-B<:Global> -- C<:Global> is merely a shorthand for 
-"C<:Path('/_name_of_method_')>".  For example, these are equivalent:
-"C<sub create_book :Global {...}>" and 
-"C<sub create_book :Path('/create_book') {...}>".
-
-=item *
-
-B<:Chained> -- Newer Catalyst applications tend to use the Chained 
-dispatch form of action types because of its power and flexibility.  
-It allows a series of controller methods to be automatically dispatched
-to service a single user request.  See 
-L<Catalyst::Manual::Tutorial::BasicCRUD|Catalyst::Manual::Tutorial::BasicCRUD> 
-and L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained> 
-for more information on chained actions.
-
-=back
-
-You should refer to L<Catalyst::Manual::Intro/Action_types> for 
-additional information and for coverage of some lesser-used action 
-types not discussed here (C<Regex> and C<LocalRegex>).
-
-
-=head1 CATALYST VIEWS
-
-As mentioned in Chapter 2 of the tutorial, views are where you render
-output, typically for display in the user's web browser (but also
-possibly using into output-generation systems, such as PDF or JSON).
-The code in C<lib/MyApp/View> selects the I<type> of view to use, with
-the actual rendering template found in the C<root> directory.  As with
-virtually every aspect of Catalyst, options abound when it comes to the
-specific view technology you adopt inside your application. However,
-most Catalyst applications use the Template Toolkit, known as TT (for
-more information on TT, see L<http://www.template-toolkit.org>). Other
-somewhat popular view technologies include Mason
-(L<http://www.masonhq.com> and L<http://www.masonbook.com>) and
-L<HTML::Template> (L<http://html-template.sourceforge.net>).
-
-
-=head2 Create a Catalyst View
-
-When using TT for the Catalyst view, there are two main helper scripts:
-
-=over 4
-
-=item *
-
-L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
-
-=item *
-
-L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
-
-=back
-
-Both helpers are similar. C<TT> creates the C<lib/MyApp/View/TT.pm>
-file and leaves the creation of any hierarchical template organization
-entirely up to you. (It also creates a C<t/view_TT.t> file for testing;
-test cases will be discussed in Chapter 8.) C<TTSite>, on the other hand, 
-creates a modular and hierarchical view layout with
-separate Template Toolkit (TT) files for common header and footer
-information, configuration values, a CSS stylesheet, and more.
-
-While C<TTSite> was useful to bootstrap a project, its use is now
-deprecated and it should be considered historical.  For most Catalyst
-applications it adds redundant functionality and structure; many in the
-Catalyst community recommend that it's easier to learn both Catalyst and
-Template Toolkit if you use the more basic C<TT> approach.
-Consequently, this tutorial will use "plain old TT."
-
-Enter the following command to enable the C<TT> style of view
-rendering for this tutorial:
-
-    $ script/myapp_create.pl view TT TT
-     exists "/home/me/MyApp/script/../lib/MyApp/View"
-     exists "/home/me/MyApp/script/../t"
-     created "/home/me/MyApp/script/../lib/MyApp/View/TT.pm"
-     created "/home/me/MyApp/script/../t/view_TT.t"
-
-This simply creates a view called C<TT> (the second 'TT' argument) in 
-a file called C<TT.pm> (the first 'TT' argument). It is now up to you 
-to decide how you want to structure your view layout.  For the 
-tutorial, we will start with a very simple TT template to initially 
-demonstrate the concepts, but quickly migrate to a more typical 
-"wrapper page" type of configuration (where the "wrapper" controls the 
-overall "look and feel" of your site from a single file or set of 
-files).
-
-Edit C<lib/MyApp/View/TT.pm> and you should see that the default
-contents contains something similar to the following:
-
-    __PACKAGE__->config(TEMPLATE_EXTENSION => '.tt');
-
-And update it to match:
-
-    __PACKAGE__->config(
-        # Change default TT extension
-        TEMPLATE_EXTENSION => '.tt2',
-        # Set the location for TT files
-        INCLUDE_PATH => [
-                MyApp->path_to( 'root', 'src' ),
-            ],
-    );
-
-B<NOTE:> Make sure to add a comma after '.tt2' outside the single
-quote.
-
-This changes the default extension for Template Toolkit from '.tt' to
-'.tt2' and changes the base directory for your template files from
-C<root> to C<root/src>.  These changes from the default are done mostly
-to facilitate the application we're developing in this tutorial; as with
-most things Perl, there's more than one way to do it...
-
-B<Note:> We will use C<root/src> as the base directory for our 
-template files, which a full naming convention of 
-C<root/src/_controller_name_/_action_name_.tt2>.  Another popular option is to
-use C<root/> as the base (with a full filename pattern of 
-C<root/_controller_name_/_action_name_.tt2>).
-
-
-=head2 Create a TT Template Page
-
-First create a directory for book-related TT templates:
-
-    $ mkdir -p root/src/books
-
-Then create C<root/src/books/list.tt2> in your editor and enter:
-
-    [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
-    [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
-    [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
-    [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
-    
-    [% # Provide a title -%]
-    [% META title = 'Book List' -%]
-    
-    <table>
-    <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
-    [% # Display each book in a table row %]
-    [% FOREACH book IN books -%]
-      <tr>
-        <td>[% book.title %]</td>
-        <td>[% book.rating %]</td>
-        <td></td>
-      </tr>
-    [% END -%]
-    </table>
-
-As indicated by the inline comments above, the C<META title> line uses
-TT's META feature to provide a title to the "wrapper" that we will
-create later. Meanwhile, the C<FOREACH> loop iterates through each
-C<book> model object and prints the C<title> and C<rating> fields.
-
-The C<[%> and C<%]> tags are used to delimit Template Toolkit code.  TT
-supports a wide variety of directives for "calling" other files,
-looping, conditional logic, etc.  In general, TT simplifies the usual
-range of Perl operators down to the single dot (C<.>) operator.  This
-applies to operations as diverse as method calls, hash lookups, and list
-index values (see
-L<http://search.cpan.org/perldoc?Template::Manual::Variables> for
-details and examples).  In addition to the usual C<Template> module Pod
-documentation, you can access the TT manual at
-L<http://search.cpan.org/perldoc?Template::Manual>.
-
-B<TIP:> While you can build all sorts of complex logic into your TT
-templates, you should in general keep the "code" part of your templates
-as simple as possible.  If you need more complex logic, create helper
-methods in your model that abstract out a set of code into a single call
-from your TT template.  (Note that the same is true of your controller
-logic as well -- complex sections of code in your controllers should
-often be pulled out and placed into your model objects.)
-
-
-=head2 Test Run The Application
-
-To test your work so far, first start the development server:
-
-    $ script/myapp_server.pl
-
-Then point your browser to L<http://localhost:3000> and you should
-still get the Catalyst welcome page.  Next, change the URL in your
-browser to L<http://localhost:3000/books/list>.  If you have
-everything working so far, you should see a web page that displays
-nothing other than our column headers for "Title", "Rating", and
-"Author(s)" -- we will not see any books until we get the database and
-model working below.
-
-If you run into problems getting your application to run correctly, it
-might be helpful to refer to some of the debugging techniques covered in
-the L<Debugging|Catalyst::Manual::Tutorial::Debugging> part of the
-tutorial.
-
-
-=head1 CREATE A SQLITE DATABASE
-
-In this step, we make a text file with the required SQL commands to
-create a database table and load some sample data.  We will use SQLite,
-a popular database that is lightweight and easy to use.  Open
-C<myapp01.sql> in your editor and enter:
-
-    --
-    -- Create a very simple database to hold book and author information
-    --
-    CREATE TABLE book (
-            id          INTEGER PRIMARY KEY,
-            title       TEXT ,
-            rating      INTEGER
-    );
-    -- 'book_author' is a many-to-many join table between books & authors
-    CREATE TABLE book_author (
-            book_id     INTEGER,
-            author_id   INTEGER,
-            PRIMARY KEY (book_id, author_id)
-    );
-    CREATE TABLE author (
-            id          INTEGER PRIMARY KEY,
-            first_name  TEXT,
-            last_name   TEXT
-    );
-    ---
-    --- Load some sample data
-    ---
-    INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
-    INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
-    INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
-    INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
-    INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
-    INSERT INTO author VALUES (1, 'Greg', 'Bastien');
-    INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
-    INSERT INTO author VALUES (3, 'Christian', 'Degu');
-    INSERT INTO author VALUES (4, 'Richard', 'Stevens');
-    INSERT INTO author VALUES (5, 'Douglas', 'Comer');
-    INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
-    INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
-    INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
-    INSERT INTO book_author VALUES (1, 1);
-    INSERT INTO book_author VALUES (1, 2);
-    INSERT INTO book_author VALUES (1, 3);
-    INSERT INTO book_author VALUES (2, 4);
-    INSERT INTO book_author VALUES (3, 5);
-    INSERT INTO book_author VALUES (4, 6);
-    INSERT INTO book_author VALUES (4, 7);
-    INSERT INTO book_author VALUES (5, 8);
-
-Then use the following command to build a C<myapp.db> SQLite database:
-
-    $ sqlite3 myapp.db < myapp01.sql
-
-If you need to create the database more than once, you probably want to
-issue the C<rm myapp.db> command to delete the database before you use
-the C<sqlite3 myapp.db E<lt> myapp01.sql> command.
-
-Once the C<myapp.db> database file has been created and initialized, you
-can use the SQLite command line environment to do a quick dump of the
-database contents:
-
-    $ sqlite3 myapp.db
-    SQLite version 3.5.9
-    Enter ".help" for instructions
-    sqlite> select * from book;
-    1|CCSP SNRS Exam Certification Guide|5
-    2|TCP/IP Illustrated, Volume 1|5
-    3|Internetworking with TCP/IP Vol.1|4
-    4|Perl Cookbook|5
-    5|Designing with Web Standards|5
-    sqlite> .q
-    $
-
-Or:
-
-    $ sqlite3 myapp.db "select * from book"
-    1|CCSP SNRS Exam Certification Guide|5
-    2|TCP/IP Illustrated, Volume 1|5
-    3|Internetworking with TCP/IP Vol.1|4
-    4|Perl Cookbook|5
-    5|Designing with Web Standards|5
-
-As with most other SQL tools, if you are using the full "interactive"
-environment you need to terminate your SQL commands with a ";" (it's not
-required if you do a single SQL statement on the command line).  Use
-".q" to exit from SQLite from the SQLite interactive mode and return to
-your OS command prompt.
-
-Please note that here we have chosen to use 'singular' table names. This
-is because the default inflection code for L<DBIx::Class:Schema::Loader>
-does NOT handle plurals. There has been much philosophical discussion
-on whether table names should be plural or singular. There is no one
-correct answer, as long as one makes a choice and remains consistent
-with it. If you prefer plural table names (e.g. they are easier and
-more natural to read) then you will need to pass it an inflect_map 
-option. See L<DBIx::Class:Schema::Loader> for more information.
-
-For using other databases, such as PostgreSQL or MySQL, see 
-L<Appendix 2|Catalyst::Manual::Tutorial::Appendices>.
-
-
-=head1 DATABASE ACCESS WITH DBIx::Class
-
-Catalyst can be used with virtually any form of datastore available 
-via Perl.  For example, L<Catalyst::Model::DBI|Catalyst::Model::DBI> 
-can be used to access databases through the traditional Perl C<DBI> 
-interface or you can use a model to access files of any type on the 
-filesystem.  However, most Catalyst applications use some form of 
-object-relational mapping (ORM) technology to create objects 
-associated with tables in a relational database.  Matt Trout's 
-L<DBIx::Class|DBIx::Class> (abbreviated as "DBIC") has rapidly emerged 
-as the Perl-based ORM technology of choice. Most new Catalyst 
-applications rely on DBIx::Class, as will this tutorial.
-
-Although DBIx::Class has included support for a C<create=dynamic> mode 
-to automatically read the database structure every time the 
-application starts, it's use is no longer recommended.  While it can 
-make for "flashy" demos, the use of the C<create=static> mode we use 
-below can be implemented just as quickly and provides many advantages 
-(such as the ability to add your own methods to the overall DBIC 
-framework, a technique that we see in Chapter 4).
-
-
-=head2 Make Sure You Have a Recent Version of the DBIx::Class Model
-
-First, let's be sure we have a recent version of the DBIC helper,
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>, by
-running this command:
-
-    $ perl -MCatalyst::Model::DBIC::Schema -e \
-        'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
-    0.23
-
-(please note that the '\' above is a line continuation marker and
-should NOT be included as part of the command)
-
-If you don't have version 0.23 or higher, please run this command
-to install it directly from CPAN:
-
-    $ sudo cpan Catalyst::Model::DBIC::Schema
-
-And re-run the version print command to verify that you are now at 
-0.23 or higher.
-
-
-=head2 Create Static DBIx::Class Schema Files
-
-Before you continue, make sure your C<myapp.db> database file is in 
-the application's topmost directory. Now use the model helper with 
-the C<create=static> option to read the database with 
-L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> and 
-automatically build the required files for us:
-
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
-     exists "/home/me/MyApp/script/../lib/MyApp/Model"
-     exists "/home/me/MyApp/script/../t"
-    Dumping manual schema for MyApp::Schema to directory /home/me/MyApp/script/../lib ...
-    Schema dump completed.
-    created "/home/me/MyApp/script/../lib/MyApp/Model/DB.pm"
-    created "/home/me/MyApp/script/../t/model_DB.t"
-
-(please note that the '\' above is a line continuation marker and
-should NOT be included as part of the command)
-
-The C<script/myapp_create.pl> command breaks down like this:
-
-=over 4
-
-=item *
-
-C<DB> is the name of the model class to be created by the helper in 
-C<lib/MyApp/Model>.
-
-=item *
-
-C<DBIC::Schema> is the type of the model to create.
-
-=item *
-
-C<MyApp::Schema> is the name of the DBIC schema file written to
-C<lib/MyApp/Schema.pm>.
-
-=item *
-
-C<create=static> causes 
-L<DBIx::Class::Schema::Loader|DBIx::Class::Schema::Loader> to 
-load the schema as it runs and then write that information out
-into files.
-
-=item *
-
-C<components=TimeStamp> causes the help to include the 
-L<DBIx::Class::TimeStamp|DBIx::Class::TimeStamp> DBIC component.
-
-=item *
-
-And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect string 
-for use with SQLite.
-
-=back
-
-If you look in the C<lib/MyApp/Schema.pm> file, you will find that it 
-only contains a call to the C<load_namespaces> method.  You will also 
-find that C<lib/MyApp> contains a C<Schema> subdirectory, which then 
-has a subdirectory called "Result".  This "Result" subdirectory then 
-has files named according to each of the tables in our simple database 
-(C<Author.pm>, C<BookAuthor.pm>, and C<Book.pm>).  These three 
-files are called "Result Classes" in DBIx::Class nomenclature. Although the 
-Result Class files are named after tables in our database, the classes 
-correspond to the I<row-level data> that is returned by DBIC (more on 
-this later, especially in 
-L<Catalyst::Manual::Tutorial::BasicCRUD/EXPLORING THE POWER OF DBIC>).
-
-The idea with the Result Source files created under 
-C<lib/MyApp/Schema/Result> by the C<create=static> option is to only 
-edit the files below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> 
-warning. If you place all of your changes below that point in the 
-file, you can regenerate the automatically created information at the 
-top of each file should your database structure get updated.
-
-Also note the "flow" of the model information across the various files 
-and directories.  Catalyst will initially load the model from 
-C<lib/MyApp/Model/DB.pm>.  This file contains a reference to 
-C<lib/MyApp/Schema.pm>, so that file is loaded next.  Finally, the 
-call to C<load_namespaces> in C<Schema.pm> will load each of the 
-"Result Class" files from the C<lib/MyApp/Schema/Result> subdirectory. 
-The final outcome is that Catalyst will dynamically create three 
-table-specific Catalyst models every time the application starts (you 
-can see these three model files listed in the debug output generated 
-when you launch the application).
-
-B<NOTE:> Older versions of 
-L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> use the 
-deprecated DBIx::Class C<load_classes> technique instead of the newer 
-C<load_namspaces>.  For new applications, please try to use 
-C<load_namespaces> since it more easily supports a very useful DBIC 
-technique called "ResultSet Classes."  If you need to convert an 
-existing application from "load_classes" to "load_namespaces," you can 
-use this process to automate the migration (but first make sure you 
-have v0.23 C<Catalyst::Model::DBIC::Schema> as discussed above):
-
-    $ # First delete the existing schema file to disable "compatibility" mode
-    $ rm lib/MyApp/Schema.pm
-    $
-    $ # Then re-run the helper to build the files for "load_namespaces"
-    $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
-        create=static components=TimeStamp dbi:SQLite:myapp.db
-    $
-    $ # Note that the '\' above is a line continuation marker and
-    $ # should NOT be included as part of the command
-
-    $
-    $ # Now convert the existing files over
-    $ cd lib/MyApp/Schema
-    $ perl -MIO::All -e 'for (@ARGV) { my $s < io($_); $s =~ s/.*\n\# You can replace.*?\n//s;
-          $s =~ s/'MyApp::Schema::/'MyApp::Schema::Result::/g; my $d < io("Result/$_");
-          $d =~ s/1;\n?//; "$d$s" > io("Result/$_"); }' *.pm
-    $ cd ../../..
-    $
-    $ # And finally delete the old files
-    $ rm lib/MyApp/Schema/*.pm
-
-The "C<perl -MIO::ALL ...>" script will copy all the customized 
-relationship (and other) information below "C<# DO NOT MODIFY>" line 
-from the old files in C<lib/MyApp/Schema> to the new files in 
-C<lib/MyApp/Schema/Result> (we will be starting to add some 
-"customized relationship information in the section below).
-
-
-=head1 ENABLE THE MODEL IN THE CONTROLLER
-
-Open C<lib/MyApp/Controller/Books.pm> and un-comment the model code we 
-left disabled earlier so that your version matches the following (un-
-comment the line containing C<[$c-E<gt>model('DB::Book')-E<gt>all]> 
-and delete the next 2 lines):
-
-    =head2 list
-    
-    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
-    =cut
-    
-    sub list : Local {
-        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
-        # 'Context' that's used to 'glue together' the various components
-        # that make up the application
-        my ($self, $c) = @_;
-    
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
-    
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods (action methods respond to user input in
-        # your controllers).
-        $c->stash->{template} = 'books/list.tt2';
-    }
-
-B<TIP>: You may see the C<$c-E<gt>model('DB::Book')> un-commented 
-above written as C<$c-E<gt>model('DB')-E<gt>resultset('Book')>.  The 
-two are equivalent.  Either way, C<$c-E<gt>model> returns a 
-L<DBIx::Class::ResultSet|DBIx::Class::ResultSet> which handles queries 
-against the database and iterating over the set of results that is 
-returned.
-
-We are using the C<-E<gt>all> to fetch all of the books.  DBIC 
-supports a wide variety of more advanced operations to easily do 
-things like filtering and sorting the results.  For example, the 
-following could be used to sort the results by descending title:
-
-    $c->model('DB::Book')->search({}, {order_by => 'title DESC'});
-
-Some other examples are provided in 
-L<DBIx::Class::Manual::Cookbook/Complex WHERE clauses>, with 
-additional information found at L<DBIx::Class::ResultSet/search>, 
-L<DBIx::Class::Manual::FAQ/Searching>, 
-L<DBIx::Class::Manual::Intro|DBIx::Class::Manual::Intro> 
-and L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema>.
-
-
-=head2 Test Run The Application
-
-First, let's enable an environment variable that causes DBIx::Class to 
-dump the SQL statements used to access the database.  This is a 
-helpful trick when you are trying to debug your database-oriented 
-code:
-
-    $ export DBIC_TRACE=1
-
-This assumes you are using bash as your shell -- adjust accordingly if
-you are using a different shell (for example, under tcsh, use
-C<setenv DBIC_TRACE 1>).
-
-B<NOTE:> You can also set this in your code using
-C<$class-E<gt>storage-E<gt>debug(1);>.  See
-L<DBIx::Class::Manual::Troubleshooting> for details (including options
-to log to a file instead of displaying to the Catalyst development server
-log).
-
-Then launch the Catalyst development server.  The log output should
-display something like:
-
-    $ script/myapp_server.pl
-    [debug] Debug messages enabled
-    [debug] Statistics enabled
-    [debug] Loaded plugins:
-    .----------------------------------------------------------------------------.
-    | Catalyst::Plugin::ConfigLoader  0.23                                       |
-    | Catalyst::Plugin::StackTrace  0.10                                         |
-    | Catalyst::Plugin::Static::Simple  0.21                                     |
-    '----------------------------------------------------------------------------'
-    
-    [debug] Loaded dispatcher "Catalyst::Dispatcher"
-    [debug] Loaded engine "Catalyst::Engine::HTTP"
-    [debug] Found home "/home/me/MyApp"
-    [debug] Loaded Config "/home/me/MyApp/myapp.conf"
-    [debug] Loaded components:
-    .-----------------------------------------------------------------+----------.
-    | Class                                                           | Type     |
-    +-----------------------------------------------------------------+----------+
-    | MyApp::Controller::Books                                        | instance |
-    | MyApp::Controller::Root                                         | instance |
-    | MyApp::Model::DB                                                | instance |
-    | MyApp::Model::DB::Author                                        | class    |
-    | MyApp::Model::DB::Book                                          | class    |
-    | MyApp::Model::DB::BookAuthor                                    | class    |
-    | MyApp::View::TT                                                 | instance |
-    '-----------------------------------------------------------------+----------'
-    
-    [debug] Loaded Private actions:
-    .----------------------+--------------------------------------+--------------.
-    | Private              | Class                                | Method       |
-    +----------------------+--------------------------------------+--------------+
-    | /default             | MyApp::Controller::Root              | default      |
-    | /end                 | MyApp::Controller::Root              | end          |
-    | /index               | MyApp::Controller::Root              | index        |
-    | /books/index         | MyApp::Controller::Books             | index        |
-    | /books/list          | MyApp::Controller::Books             | list         |
-    '----------------------+--------------------------------------+--------------'
-    
-    [debug] Loaded Path actions:
-    .-------------------------------------+--------------------------------------.
-    | Path                                | Private                              |
-    +-------------------------------------+--------------------------------------+
-    | /                                   | /default                             |
-    | /                                   | /index                               |
-    | /books                              | /books/index                         |
-    | /books/list                         | /books/list                          |
-    '-------------------------------------+--------------------------------------'
-    
-    [info] MyApp powered by Catalyst 5.80003
-    You can connect to your server at http://debian:3000
-
-B<NOTE:> Be sure you run the C<script/myapp_server.pl> command from
-the 'base' directory of your application, not inside the C<script>
-directory itself or it will not be able to locate the C<myapp.db>
-database file.  You can use a fully qualified or a relative path to
-locate the database file, but we did not specify that when we ran the
-model helper earlier.
-
-Some things you should note in the output above:
-
-=over 4
-
-=item *
-
-Catalyst::Model::DBIC::Schema dynamically created three model classes,
-one to represent each of the three tables in our database
-(C<MyApp::Model::DB::Author>, C<MyApp::Model::DB::BookAuthor>,
-and C<MyApp::Model::DB::Book>).
-
-=item *
-
-The "list" action in our Books controller showed up with a path of
-C</books/list>.
-
-=back
-
-Point your browser to L<http://localhost:3000> and you should still get
-the Catalyst welcome page.
-
-Next, to view the book list, change the URL in your browser to
-L<http://localhost:3000/books/list>. You should get a list of the five
-books loaded by the C<myapp01.sql> script above without any formatting.
-The rating for each book should appear on each row, but the "Author(s)"
-column will still be blank (we will fill that in later).
-
-Also notice in the output of the C<script/myapp_server.pl> that 
-DBIx::Class used the following SQL to retrieve the data:
-
-    SELECT me.id, me.title, me.rating FROM books me
-
-because we enabled DBIC_TRACE.
-
-You now have the beginnings of a simple but workable web application.
-Continue on to future sections and we will develop the application
-more fully.
-
-
-=head1 CREATE A WRAPPER FOR THE VIEW
-
-When using TT, you can (and should) create a wrapper that will
-literally wrap content around each of your templates.  This is
-certainly useful as you have one main source for changing things that
-will appear across your entire site/application instead of having to
-edit many individual files.
-
-
-=head2 Configure TT.pm For The Wrapper
-
-In order to create a wrapper, you must first edit your TT view and
-tell it where to find your wrapper file. Your TT view is located in
-C<lib/MyApp/View/TT.pm>.
-
-Edit C<lib/MyApp/View/TT.pm> and change it to match the following:
-
-    __PACKAGE__->config(
-        # Change default TT extension
-        TEMPLATE_EXTENSION => '.tt2',
-        # Set the location for TT files
-        INCLUDE_PATH => [
-                MyApp->path_to( 'root', 'src' ),
-            ],
-        # Set to 1 for detailed timer stats in your HTML as comments
-        TIMER              => 0,
-        # This is your wrapper template located in the 'root/src'
-        WRAPPER => 'wrapper.tt2',
-    );
-
-
-=head2 Create the Wrapper Template File and Stylesheet
-
-Next you need to set up your wrapper template.  Basically, you'll want
-to take the overall layout of your site and put it into this file.
-For the tutorial, open C<root/src/wrapper.tt2> and input the following:
-
-    <?xml version="1.0" encoding="UTF-8"?>
-    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-    <head>
-    <title>[% template.title or "My Catalyst App!" %]</title>
-    <link rel="stylesheet" href="[% c.uri_for('/static/css/main.css') %]" />
-    </head>
-    
-    <body>
-    <div id="outer">
-    <div id="header">
-        [%# Your logo could go here -%]
-        <img src="[% c.uri_for('/static/images/btn_88x31_powered.png') %]" />
-        [%# Insert the page title -%]
-        <h1>[% template.title or site.title %]</h1>
-    </div>
-    
-    <div id="bodyblock">
-    <div id="menu">
-        Navigation:
-        <ul>
-            <li><a href="[% c.uri_for('/books/list') %]">Home</a></li>
-            <li><a href="[% c.uri_for('/') %]" title="Catalyst Welcome Page">Welcome</a></li>
-        </ul>
-    </div><!-- end menu -->
-    
-    <div id="content">
-        [%# Status and error messages %]
-        <span class="message">[% status_msg %]</span>
-        <span class="error">[% error_msg %]</span>
-        [%# This is where TT will stick all of your template's contents. -%]
-        [% content %]
-    </div><!-- end content -->
-    </div><!-- end bodyblock -->
-    
-    <div id="footer">Copyright (c) your name goes here</div>
-    </div><!-- end outer -->
-    
-    </body>
-    </html>
-
-Notice the status and error message sections in the code above:
-
-    <span class="status">[% status_msg %]</span>
-    <span class="error">[% error_msg %]</span>
-
-If we set either message in the Catalyst stash (e.g.,
-C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it
-will be displayed whenever any view used by that request is rendered.
-The C<message> and C<error> CSS styles can be customized to suit your
-needs in the C<root/static/css/main.css> file we create below.
-
-B<Notes:> 
-
-=over 4
-
-=item *
-
-The Catalyst stash only lasts for a single HTTP request.  If
-you need to retain information across requests you can use
-L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
-Catalyst sessions in the Authentication chapter of the tutorial).
-
-=item *
-
-Although it is beyond the scope of this tutorial, you may wish to use
-a JavaScript or AJAX tool such as jQuery (L<http://www.jquery.com>) or
-Dojo (L<http://www.dojotoolkit.org>).
-
-=back
-
-
-=head3 Create A Basic Stylesheet
-
-First create a central location for stylesheets under the static
-directory:
-
-    $ mkdir root/static/css
-
-Then open the file C<root/static/css/main.css> (the file referenced in
-the stylesheet href link of our wrapper above) and add the following
-content:
-
-    #header {
-        text-align: center;
-    }
-    #header h1 {
-        margin: 0;
-    }
-    #header img {
-        float: right;
-    }
-    #footer {
-        text-align: center;
-        font-style: italic;
-        padding-top: 20px;
-    }
-    #menu {
-        font-weight: bold;
-        background-color: #ddd;
-    }
-    #menu ul {
-        list-style: none;
-        float: left;
-        margin: 0;
-        padding: 0 0 50% 5px;
-        font-weight: normal;
-        background-color: #ddd;
-        width: 100px;
-    }
-    #content {
-        margin-left: 120px;
-    }
-    .message {
-        color: #390;
-    }
-    .error {
-        color: #f00;
-    }
-
-You may wish to check out a "CSS Framework" like Emastic
-(L<http://code.google.com/p/emastic/>) as a way to quickly
-provide lots of high-quality CSS functionality.
-
-
-=head2 Test Run The Application
-
-Restart the development server and hit "Reload" in your web browser
-and you should now see a formatted version of our basic book list.
-Although our wrapper and stylesheet are obviously very simple, you
-should see how it allows us to control the overall look of an entire
-website from two central files.  To add new pages to the site, just
-provide a template that fills in the C<content> section of our wrapper
-template -- the wrapper will provide the overall feel of the page.
-
-
-=head2 Updating the Generated DBIx::Class Result Class Files
-
-Let's manually add some relationship information to the auto-generated 
-Result Class files. (Note: if you are using a database other than 
-SQLite, such as PostgreSQL, then the relationship could have been 
-automatically placed in the Result Class files.  If so, you can skip 
-this step.)  First edit C<lib/MyApp/Schema/Result/Book.pm> and add the 
-following text below the C<# You can replace this text...> comment:
-
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'book_id');
-    
-    # many_to_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of has_many() relationship this many_to_many() is shortcut for
-    #     3) Name of belongs_to() relationship in model class of has_many() above
-    #   You must already have the has_many() defined to use a many_to_many().
-    __PACKAGE__->many_to_many(author => 'book_author', 'author');
-
-
-B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
-file.  As with any Perl package, we need to end the last line with
-a statement that evaluates to C<true>.  This is customarily done with
-C<1;> on a line by itself.
-
-This code defines both a C<has_many> and a C<many_to_many> 
-relationship. The C<many_to_many> relationship is optional, but it 
-makes it easier to map a book to its collection of authors.  Without 
-it, we would have to "walk" though the C<book_author> table as in 
-C<$book-E<gt>book_author-E<gt>first-E<gt>author-E<gt>last_name> (we 
-will see examples on how to use DBIx::Class objects in your code soon, 
-but note that because C<$book-E<gt>book_author> can return multiple 
-authors, we have to use C<first> to display a single author). 
-C<many_to_many> allows us to use the shorter C<$book-E<gt>author-
-E<gt>first-E<gt>last_name>. Note that you cannot define a 
-C<many_to_many> relationship without also having the C<has_many> 
-relationship in place.
-
-Then edit C<lib/MyApp/Schema/Result/Author.pm> and add relationship
-information as follows (again, be careful to put in above the C<1;> but
-below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
-
-    #
-    # Set relationships:
-    #
-    
-    # has_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create an accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *foreign* table (aka, foreign key in peer table)
-    __PACKAGE__->has_many(book_author => 'MyApp::Schema::Result::BookAuthor', 'author_id');
-    
-    # many_to_many():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of has_many() relationship this many_to_many() is shortcut for
-    #     3) Name of belongs_to() relationship in model class of has_many() above
-    #   You must already have the has_many() defined to use a many_to_many().
-    __PACKAGE__->many_to_many(book => 'book_author', 'book');
-
-Finally, do the same for the "join table,"
-C<lib/MyApp/Schema/Result/BookAuthor.pm>:
-
-    #
-    # Set relationships:
-    #
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(book => 'MyApp::Schema::Result::Book', 'book_id');
-    
-    # belongs_to():
-    #   args:
-    #     1) Name of relationship, DBIC will create accessor with this name
-    #     2) Name of the model class referenced by this relationship
-    #     3) Column name in *this* table
-    __PACKAGE__->belongs_to(author => 'MyApp::Schema::Result::Author', 'author_id');
-
-
-=head2 Run The Application
-
-Run the Catalyst development server script with the C<DBIC_TRACE> option
-(it might still be enabled from earlier in the tutorial, but here is an
-alternate way to specify the option just in case):
-
-    $ DBIC_TRACE=1 script/myapp_server.pl
-
-Make sure that the application loads correctly and that you see the
-three dynamically created model class (one for each of the
-Result Classes we created).
-
-Then hit the URL L<http://localhost:3000/books/list> with your browser 
-and be sure that the book list is displayed via the relationships 
-established above. You can leave the development server running for 
-the next step if you wish.
-
-B<Note:> You will not see the authors yet because the view does not yet 
-use the new relations. Read on to the next section where we update the 
-template to do that.
-
-
-=head1 UPDATING THE VIEW
-
-Let's add a new column to our book list page that takes advantage of 
-the relationship information we manually added to our schema files in 
-the previous section.  Edit C<root/src/books/list.tt2> and replace
-the "empty" table cell "<td></td>" with the following:
-
-    ...
-    <td>
-      [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
-      [% # loop in 'side effect notation' to load just the last names of the     -%]
-      [% # authors into the list. Note that the 'push' TT vmethod does not print -%]
-      [% # a value, so nothing will be printed here.  But, if you have something -%]
-      [% # in TT that does return a method and you don't want it printed, you    -%]
-      [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to     -%]
-      [% # call it and discard the return value.                                 -%]
-      [% tt_authors = [ ];
-         tt_authors.push(author.last_name) FOREACH author = book.authors %]
-      [% # Now use a TT 'virtual method' to display the author count in parens   -%]
-      [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
-      ([% tt_authors.size | html %])
-      [% # Use another TT vmethod to join & print the names & comma separators   -%]
-      [% tt_authors.join(', ') | html %]
-    </td>
-    ...
-
-Then hit "Reload" in your browser (note that you don't need to reload 
-the development server or use the C<-r> option when updating TT 
-templates) and you should now see the number of authors each book has 
-along with a comma-separated list of the authors' last names.  (If you 
-didn't leave the development server running from the previous step, 
-you will obviously need to start it before you can refresh your 
-browser window.)
-
-If you are still running the development server with C<DBIC_TRACE>
-enabled, you should also now see five more C<SELECT> statements in the
-debug output (one for each book as the authors are being retrieved by
-DBIx::Class):
-
-    SELECT me.id, me.title, me.rating FROM books me:
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '1'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '2'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '3'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '4'
-    SELECT author.id, author.first_name, author.last_name FROM book_author me  
-    JOIN author author ON ( author.id = me.author_id ) WHERE ( me.book_id = ? ): '5'
-
-Also note in C<root/src/books/list.tt2> that we are using "| html", a 
-type of TT filter, to escape characters such as E<lt> and E<gt> to &lt; 
-and &gt; and avoid various types of dangerous hacks against your 
-application.  In a real application, you would probably want to put 
-"| html" at the end of every field where a user has control over the 
-information that can appear in that field (and can therefore inject 
-markup or code if you don't "neutralize" those fields).  In addition to 
-"| html", Template Toolkit has a variety of other useful filters that 
-can found in the documentation for 
-L<Template::Filters|Template::Filters>.
-
-
-=head1 RUNNING THE APPLICATION FROM THE COMMAND LINE
-
-In some situations, it can be useful to run your application and
-display a page without using a browser.  Catalyst lets you do this
-using the C<scripts/myapp_test.pl> script.  Just supply the URL you
-wish to display and it will run that request through the normal
-controller dispatch logic and use the appropriate view to render the
-output (obviously, complex pages may dump a lot of text to your
-terminal window).  For example, if you type:
-
-    $ script/myapp_test.pl "/books/list"
-
-You should get the same text as if you visited
-L<http://localhost:3000/books/list> with the normal development server
-and asked your browser to view the page source.
-
-
-=head1 OPTIONAL INFORMATION
-
-B<NOTE: The rest of this chapter of the tutorial is optional.  You can
-skip to Chapter 4, L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>,
-if you wish.>
-
-
-=head2 Using 'RenderView' for the Default View
-
-Once your controller logic has processed the request from a user, it
-forwards processing to your view in order to generate the appropriate
-response output.  Catalyst uses
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> by
-default to automatically perform this operation.  If you look in
-C<lib/MyApp/Controller/Root.pm>, you should see the empty
-definition for the C<sub end> method:
-
-    sub end : ActionClass('RenderView') {}
-
-The following bullet points provide a quick overview of the
-C<RenderView> process:
-
-=over 4
-
-=item *
-
-C<Root.pm> is designed to hold application-wide logic.
-
-=item *
-
-At the end of a given user request, Catalyst will call the most specific
-C<end> method that's appropriate.  For example, if the controller for a
-request has an C<end> method defined, it will be called.  However, if
-the controller does not define a controller-specific C<end> method, the
-"global" C<end> method in C<Root.pm> will be called.
-
-=item *
-
-Because the definition includes an C<ActionClass> attribute, the
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
-will be executed B<after> any code inside the definition of C<sub end>
-is run.  See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
-for more information on C<ActionClass>.
-
-=item *
-
-Because C<sub end> is empty, this effectively just runs the default
-logic in C<RenderView>.  However, you can easily extend the
-C<RenderView> logic by adding your own code inside the empty method body
-(C<{}>) created by the Catalyst Helpers when we first ran the
-C<catalyst.pl> to initialize our application.  See
-L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more
-detailed information on how to extend C<RenderView> in C<sub end>.
-
-=back
-
-
-=head2 Using The Default Template Name
-
-By default, C<Catalyst::View::TT> will look for a template that uses the
-same name as your controller action, allowing you to save the step of
-manually specifying the template name in each action.  For example, this
-would allow us to remove the
-C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our
-C<list> action in the Books controller.  Open
-C<lib/MyApp/Controller/Books.pm> in your editor and comment out this line
-to match the following (only the C<$c-E<gt>stash-E<gt>{template}> line
-has changed):
-
-    =head2 list
-    
-    Fetch all book objects and pass to books/list.tt2 in stash to be displayed
-    
-    =cut
-    
-    sub list : Local {
-        # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
-        # 'Context' that's used to 'glue together' the various components
-        # that make up the application
-        my ($self, $c) = @_;
-    
-        # Retrieve all of the book records as book model objects and store in the
-        # stash where they can be accessed by the TT template
-        $c->stash->{books} = [$c->model('DB::Book')->all];
-    
-        # Set the TT template to use.  You will almost always want to do this
-        # in your action methods (actions methods respond to user input in
-        # your controllers).
-        #$c->stash->{template} = 'books/list.tt2';
-    }
-
-
-You should now be able to restart the development server as per the
-previous section and access the L<http://localhost:3000/books/list>
-as before.
-
-B<NOTE:> Please note that if you use the default template technique,
-you will B<not> be able to use either the C<$c-E<gt>forward> or
-the C<$c-E<gt>detach> mechanisms (these are discussed in Chapter 2 and
-Chapter 9 of the Tutorial).
-
-B<IMPORTANT:> Make sure that you do NOT skip the following section
-before continuing to the next chapter 4 Basic CRUD.
-
-=head2 Return To A Manually Specified Template
-
-In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
-later in the tutorial, you should remove the comment from the
-statement in C<sub list> in C<lib/MyApp/Controller/Books.pm>:
-
-    $c->stash->{template} = 'books/list.tt2';
-
-Then delete the C<TEMPLATE_EXTENSION> line in
-C<lib/MyApp/View/TT.pm>.
-
-You should then be able to restart the development server and
-access L<http://localhost:3000/books/list> in the same manner as
-with earlier sections.
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).

Deleted: Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod
===================================================================
--- Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod	2009-05-24 22:09:09 UTC (rev 10276)
+++ Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/Testing.pod	2009-05-24 22:30:47 UTC (rev 10277)
@@ -1,406 +0,0 @@
-=head1 NAME
-
-Catalyst::Manual::Tutorial::Testing - Catalyst Tutorial - Chapter 8: Testing
-
-
-=head1 OVERVIEW
-
-This is B<Chapter 8 of 10> for the Catalyst tutorial.
-
-L<Tutorial Overview|Catalyst::Manual::Tutorial>
-
-=over 4
-
-=item 1
-
-L<Introduction|Catalyst::Manual::Tutorial::Intro>
-
-=item 2
-
-L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
-
-=item 3
-
-L<More Catalyst Basics|Catalyst::Manual::Tutorial::MoreCatalystBasics>
-
-=item 4
-
-L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
-
-=item 5
-
-L<Authentication|Catalyst::Manual::Tutorial::Authentication>
-
-=item 6
-
-L<Authorization|Catalyst::Manual::Tutorial::Authorization>
-
-=item 7
-
-L<Debugging|Catalyst::Manual::Tutorial::Debugging>
-
-=item 8
-
-B<Testing>
-
-=item 9
-
-L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
-
-=item 10
-
-L<Appendices|Catalyst::Manual::Tutorial::Appendices>
-
-=back
-
-
-=head1 DESCRIPTION
-
-You may have noticed that the Catalyst Helper scripts automatically 
-create basic C<.t> test scripts under the C<t> directory.  This 
-chapter of the tutorial briefly looks at how these tests can be used 
-not only to ensure that your application is working correctly at the 
-present time, but also provide automated regression testing as you 
-upgrade various pieces of your application over time.
-
-You can check out the source code for this example from the Catalyst
-Subversion repository as per the instructions in
-L<Catalyst::Manual::Tutorial::Intro|Catalyst::Manual::Tutorial::Intro>.
-
-For an excellent introduction to learning the many benefits of testing
-your Perl applications and modules, you might want to read 'Perl Testing: 
-A Developer's Notebook' by Ian Langworth and chromatic.
-
-
-=head1 RUNNING THE "CANNED" CATALYST TESTS
-
-There are a variety of ways to run Catalyst and Perl tests (for example,
-C<perl Makefile.PL> and C<make test>), but one of the easiest is with the
-C<prove> command.  For example, to run all of the tests in the C<t>
-directory, enter:
-
-    $ prove --lib lib t
-
-There will be a lot of output because we have the C<-Debug> flag 
-enabled in C<lib/MyApp.pm> (see the C<CATALYST_DEBUG=0> tip below for 
-a quick and easy way to reduce the clutter).  Look for lines like this 
-for errors:
-
-    #   Failed test 'Request should succeed'
-    #   at t/controller_Books.t line 8.
-    # Looks like you failed 1 test of 3.
-
-The redirection used by the Authentication plugins will cause several 
-failures in the default tests.  You can fix this by making the following
-changes:
-
-1) Change the line in C<t/01app.t> that reads:
-
-    ok( request('/')->is_success, 'Request should succeed' );
-
-to:
-
-    ok( request('/login')->is_success, 'Request should succeed' );
-
-2) Change the line in C<t/controller_Logout.t> that reads:
-
-    ok( request('/logout')->is_success, 'Request should succeed' );
-
-to:
-
-    ok( request('/logout')->is_redirect, 'Request should succeed' );
-
-3) Change the line in C<t/controller_Books.t> that reads:
-
-    ok( request('/books')->is_success, 'Request should succeed' );
-
-to:
-
-    ok( request('/books')->is_redirect, 'Request should succeed' );
-
-4) Add the following statement to the top of C<t/view_TT.t>:
-
-    use MyApp;
-
-As you can see in the C<prove> command line above, the C<--lib> option
-is used to set the location of the Catalyst C<lib> directory.  With this
-command, you will get all of the usual development server debug output,
-something most people prefer to disable while running tests cases.
-Although you can edit the C<lib/MyApp.pm> to comment out the C<-Debug>
-plugin, it's generally easier to simply set the C<CATALYST_DEBUG=0>
-environment variable.  For example:
-
-    $ CATALYST_DEBUG=0 prove --lib lib t
-
-B<Note:> Depending on the versions of various modules you have 
-installed, you might get some C<used only once> warnings -- you can 
-ignore these.  If you want to eliminate the warnings, you can 
-edit C<Template::Base> to disable and then re-enable warnings
-are the C</usr/lib/perl5/Template/Base.pm> line in C<sub new>.
-You can locate where C<Template::Base> is located with the 
-following command (it's probably in a place similar to
-C</usr/lib/perl5/Template/Base.pm>):
-
-    perldoc -l Template::Base
-
-Edit the file and modify C<sub new> to match:
-
-    ...
-    {   no strict qw( refs );
-        # Disable warnings
-        no warnings;
-        $argnames = \@{"$class\::BASEARGS"} || [ ];
-        # Turn warnings back on
-        use warnings;
-    }
-    ...
-
-During the C<t/02pod> and C<t/03podcoverage> tests, you might notice the
-C<all skipped: set TEST_POD to enable this test> warning message.  To
-execute the Pod-related tests, add C<TEST_POD=1> to the C<prove>
-command:
-
-    $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib t
-
-If you omitted the Pod comments from any of the methods that were
-inserted, you might have to go back and fix them to get these tests to
-pass. :-)
-
-Another useful option is the C<verbose> (C<-v>) option to C<prove>.  It
-prints the name of each test case as it is being run:
-
-    $ CATALYST_DEBUG=0 TEST_POD=1 prove --lib lib -v t
-
-
-=head1 RUNNING A SINGLE TEST
-
-You can also run a single script by appending its name to the C<prove>
-command. For example:
-
-    $ CATALYST_DEBUG=0 prove --lib lib t/01app.t
-
-Also note that you can also run tests directly from Perl without C<prove>.
-For example:
-
-    $ CATALYST_DEBUG=0 perl -Ilib t/01app.t
-
-
-=head1 ADDING YOUR OWN TEST SCRIPT
-
-Although the Catalyst helper scripts provide a basic level of checks
-"for free," testing can become significantly more helpful when you write
-your own script to exercise the various parts of your application.  The
-L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst> module 
-is very popular for writing these sorts of test cases.  This module 
-extends L<Test::WWW::Mechanize|Test::WWW::Mechanize> (and therefore 
-L<WWW::Mechanize|WWW::Mechanize>) to allow you to automate the action of
-a user "clicking around" inside your application.  It gives you all the
-benefits of testing on a live system without the messiness of having to
-use an actual web server, and a real person to do the clicking.
-
-To create a sample test case, open the C<t/live_app01.t> file in your
-editor and enter the following:
-
-    #!/usr/bin/perl
-    
-    use strict;
-    use warnings;
-    
-    # Load testing framework and use 'no_plan' to dynamically pick up
-    # all tests. Better to replace "'no_plan'" with "tests => 30" so it
-    # knows exactly how many tests need to be run (and will tell you if
-    # not), but 'no_plan' is nice for quick & dirty tests
-    
-    use Test::More 'no_plan';
-    
-    # Need to specify the name of your app as arg on next line
-    # Can also do:
-    #   use Test::WWW::Mechanize::Catalyst "MyApp";
-    
-    use ok "Test::WWW::Mechanize::Catalyst" => "MyApp";
-        
-    # Create two 'user agents' to simulate two different users ('test01' & 'test02')
-    my $ua1 = Test::WWW::Mechanize::Catalyst->new;
-    my $ua2 = Test::WWW::Mechanize::Catalyst->new;
-    
-    # Use a simplified for loop to do tests that are common to both users
-    # Use get_ok() to make sure we can hit the base URL
-    # Second arg = optional description of test (will be displayed for failed tests)
-    # Note that in test scripts you send everything to 'http://localhost'
-    $_->get_ok("http://localhost/", "Check redirect of base URL") for $ua1, $ua2;
-    # Use title_is() to check the contents of the <title>...</title> tags
-    $_->title_is("Login", "Check for login title") for $ua1, $ua2;
-    # Use content_contains() to match on text in the html body
-    $_->content_contains("You need to log in to use this application",
-        "Check we are NOT logged in") for $ua1, $ua2;
-    
-    # Log in as each user
-    # Specify username and password on the URL
-    $ua1->get_ok("http://localhost/login?username=test01&password=mypass", "Login 'test01'");
-    $ua1->get_ok("http://localhost/login?username=test02&password=mypass", "Login 'test02'");
-    
-    # Go back to the login page and it should show that we are already logged in
-    $_->get_ok("http://localhost/login", "Return to '/login'") for $ua1, $ua2;
-    $_->title_is("Login", "Check for login page") for $ua1, $ua2;
-    $_->content_contains("Please Note: You are already logged in as ",
-        "Check we ARE logged in" ) for $ua1, $ua2;
-    
-    # 'Click' the 'Logout' link (see also 'text_regex' and 'url_regex' options)
-    $_->follow_link_ok({n => 4}, "Logout via first link on page") for $ua1, $ua2;
-    $_->title_is("Login", "Check for login title") for $ua1, $ua2;
-    $_->content_contains("You need to log in to use this application",
-        "Check we are NOT logged in") for $ua1, $ua2;
-    
-    # Log back in
-    $ua1->get_ok("http://localhost/login?username=test01&password=mypass", "Login 'test01'");
-    $ua2->get_ok("http://localhost/login?username=test02&password=mypass", "Login 'test02'");
-    # Should be at the Book List page... do some checks to confirm
-    $_->title_is("Book List", "Check for book list title") for $ua1, $ua2;
-    
-    $ua1->get_ok("http://localhost/books/list", "'test01' book list");
-    $ua1->get_ok("http://localhost/login", "Login Page");
-    $ua1->get_ok("http://localhost/books/list", "'test01' book list");
-    
-    $_->content_contains("Book List", "Check for book list title") for $ua1, $ua2;
-    # Make sure the appropriate logout buttons are displayed
-    $_->content_contains("/logout\">User Logout</a>",
-        "Both users should have a 'User Logout'") for $ua1, $ua2;
-    $ua1->content_contains("/books/form_create\">Create</a>",
-        "Only 'test01' should have a create link");
-    
-    $ua1->get_ok("http://localhost/books/list", "View book list as 'test01'");
-    
-    # User 'test01' should be able to create a book with the "formless create" URL
-    $ua1->get_ok("http://localhost/books/url_create/TestTitle/2/4",
-        "'test01' formless create");
-    $ua1->title_is("Book Created", "Book created title");
-    $ua1->content_contains("Added book 'TestTitle'", "Check title added OK");
-    $ua1->content_contains("by 'Stevens'", "Check author added OK");
-    $ua1->content_contains("with a rating of 2.", "Check rating added");
-    # Try a regular expression to combine the previous 3 checks & account for whitespace
-    $ua1->content_like(qr/Added book 'TestTitle'\s+by 'Stevens'\s+with a rating of 2./, "Regex check");
-    
-    # Make sure the new book shows in the list
-    $ua1->get_ok("http://localhost/books/list", "'test01' book list");
-    $ua1->title_is("Book List", "Check logged in and at book list");
-    $ua1->content_contains("Book List", "Book List page test");
-    $ua1->content_contains("TestTitle", "Look for 'TestTitle'");
-    
-    # Make sure the new book can be deleted
-    # Get all the Delete links on the list page
-    my @delLinks = $ua1->find_all_links(text => 'Delete');
-    # Use the final link to delete the last book
-    $ua1->get_ok($delLinks[$#delLinks]->url, 'Delete last book');
-    # Check that delete worked
-    $ua1->content_contains("Book List", "Book List page test");
-    $ua1->content_contains("Book deleted", "Book was deleted");
-    
-    # User 'test02' should not be able to add a book
-    $ua2->get_ok("http://localhost/books/url_create/TestTitle2/2/5", "'test02' add");
-    $ua2->content_contains("Unauthorized!", "Check 'test02' cannot add");
-
-The C<live_app.t> test cases uses copious comments to explain each step
-of the process.  In addition to the techniques shown here, there are a
-variety of other methods available in 
-L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst> (for 
-example, regex-based matching). Consult the documentation for more
-detail.
-
-B<TIP>: For I<unit tests> vs. the "full application tests" approach used
-by L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst>, see 
-L<Catalyst::Test|Catalyst::Test>.
-
-B<Note:> The test script does not test the C<form_create> and
-C<form_create_do> actions.  That is left as an exercise for the reader
-(you should be able to complete that logic using the existing code as a
-template).
-
-To run the new test script, use a command such as:
-
-    $ CATALYST_DEBUG=0 prove --lib lib -v t/live_app01.t
-
-or
-
-    $ DBIC_TRACE=0 CATALYST_DEBUG=0 prove --lib lib -v t/live_app01.t
-
-Experiment with the C<DBIC_TRACE>, C<CATALYST_DEBUG> and C<-v> 
-settings.  If you find that there are errors, use the techniques 
-discussed in the "Catalyst Debugging" section (Chapter 7) to isolate 
-and fix any problems.
-
-If you want to run the test case under the Perl interactive debugger,
-try a command such as:
-
-    $ DBIC_TRACE=0 CATALYST_DEBUG=0 perl -d -Ilib t/live_app01.t
-
-Note that although this tutorial uses a single custom test case for
-simplicity, you may wish to break your tests into different files for
-better organization.
-
-B<TIP:> If you have a test case that fails, you will receive an error
-similar to the following:
-
-    #   Failed test 'Check we are NOT logged in'
-    #   in t/live_app01.t at line 31.
-    #     searched: "\x{0a}<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Tran"...
-    #   can't find: "You need to log in to use this application."
-
-Unfortunately, this only shows us the first 50 characters of the HTML
-returned by the request -- not enough to determine where the problem
-lies.  A simple technique that can be used in such situations is to 
-temporarily insert a line similar to the following right after the 
-failed test:
-
-    diag $ua1->content;
-
-This will cause the full HTML returned by the request to be displayed.
-
-Another approach to see the full HTML content at the failure point in 
-a series of tests would be to insert a "C<$DB::single=1;> right above 
-the location of the failure and run the test under the perl debugger 
-(with C<-d>) as shown above.  Then you can use the debugger to explore 
-the state of the application right before or after the failure.
-
-
-=head1 SUPPORTING BOTH PRODUCTION AND TEST DATABASES
-
-You may wish to leverage the techniques discussed in this tutorial to
-maintain both a "production database" for your live application and a
-"testing database" for your test cases.  One advantage to
-L<Test::WWW::Mechanize::Catalyst|Test::WWW::Mechanize::Catalyst> is that
-it runs your full application; however, this can complicate things when
-you want to support multiple databases.  One solution is to allow the
-database specification to be overridden with an environment variable.
-For example, open C<lib/MyApp/Model/DB.pm> in your editor and
-change the C<__PACKAGE__-E<gt>config(...> declaration to resemble:
-
-    my $dsn = $ENV{MYAPP_DSN} ||= 'dbi:SQLite:myapp.db';
-    __PACKAGE__->config(
-        schema_class => 'MyApp::Schema',
-        connect_info => [
-            $dsn,
-        ],
-    );
-
-Then, when you run your test case, you can use commands such as:
-
-    $ cp myapp.db myappTEST.db
-    $ CATALYST_DEBUG=0 MYAPP_DSN="dbi:SQLite:myappTEST.db" prove --lib lib -v t/live_app01.t
-
-This will modify the DSN only while the test case is running.  If you
-launch your normal application without the C<MYAPP_DSN> environment
-variable defined, it will default to the same C<dbi:SQLite:myapp.db> as
-before.
-
-
-=head1 AUTHOR
-
-Kennedy Clark, C<hkclark at 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/Catalyst-Manual/5.70/trunk/lib/Catalyst/Manual/Tutorial/>.
-
-Copyright 2006-2008, Kennedy Clark, under Creative Commons License
-(L<http://creativecommons.org/licenses/by-sa/3.0/us/>).
-




More information about the Catalyst-commits mailing list