=item 9
-L<Appendices|Catalyst::Manual::Tutorial::Appendicies>
+L<Appendices|Catalyst::Manual::Tutorial::Appendices>
=back
+
=head1 DESCRIPTION
In this part of the tutorial, we will create a very basic Catalyst web
pulled from the Catalyst Subversion repository in one step with the
following command:
- svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial@###
- IMPORTANT: Does not work yet. Will be completed for final version.
+ svn co http://dev.catalyst.perl.org/repos/Catalyst/tags/examples/Tutorial/MyApp/5.7/CatalystBasics MyApp
=head1 CREATE A CATALYST PROJECT
initialize the framework for an application called C<MyApp>:
$ catalyst.pl MyApp
+ created "MyApp"
+ created "MyApp/script"
+ created "MyApp/lib"
+ created "MyApp/root"
+ ...
+ created "MyApp/script/myapp_create.pl"
$ cd MyApp
The C<catalyst.pl> helper script will display the names of the
functioning application. Run the following command to run this
application with the built-in development web server:
- $ script/myapp_server.pl
+ $ script/myapp_server.pl
+ [debug] Debug messages enabled
+ [debug] Loaded plugins:
+ .----------------------------------------------------------------------------.
+ | Catalyst::Plugin::ConfigLoader 0.06 |
+ | Catalyst::Plugin::Static::Simple 0.14 |
+ '----------------------------------------------------------------------------'
+
+ [debug] Loaded dispatcher "Catalyst::Dispatcher"
+ [debug] Loaded engine "Catalyst::Engine::HTTP"
+ [debug] Found home "/root/dev/MyApp"
+ [debug] Loaded components:
+ .-----------------------------------------------------------------+----------.
+ | Class | Type |
+ +-----------------------------------------------------------------+----------+
+ | MyApp::Controller::Root | instance |
+ '-----------------------------------------------------------------+----------'
+
+ [debug] Loaded Private actions:
+ .----------------------+--------------------------------------+--------------.
+ | Private | Class | Method |
+ +----------------------+--------------------------------------+--------------+
+ | /default | MyApp::Controller::Root | default |
+ | /end | MyApp::Controller::Root | end |
+ '----------------------+--------------------------------------+--------------'
+
+ [info] MyApp powered by Catalyst 5.7000
+ You can connect to your server at http://localhost.localdomain: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. Information similar to the
+following should be appended to the logging output of the development
+server:
+
+ [info] *** Request 1 (0.043/s) [6003] [Fri Jul 7 13:32:53 2006] ***
+ [debug] "GET" request for "/" from "127.0.0.1"
+ [info] Request took 0.067675s (14.777/s)
+ .----------------------------------------------------------------+-----------.
+ | Action | Time |
+ +----------------------------------------------------------------+-----------+
+ | /default | 0.002844s |
+ | /end | 0.000207s |
+ '----------------------------------------------------------------+-----------'
+
+Press Ctrl-C to break out of the development server.
-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. Press Ctrl-C to break out of
-the development server.
=head1 CREATE A SQLITE DATABASE
INSERT INTO book_authors VALUES (5, 8);
B<TIP>: See Appendix 1 for tips on removing the leading spaces when
-cutting and pasting example code from POD documents.
+cutting and pasting example code from POD-based documents.
Then use the following command to build a C<myapp.db> SQLite database:
As you may have noticed, C<-Debug> is not a plugin, but a I<flag>.
Although most of the items specified on the C<use Catalyst> line of your
application class will be plugins, Catalyst supports a limited number of
-flag options (of these, C<-Debug> is the most common).
+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.
=item *
-L<Catalyst::Plugin::Static::Simple>
+L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
C<Static::Simple> provides an easy method of serving static content such
as images and CSS files under the development server.
Static::Simple
StackTrace
- DefaultEnd
/;
-This tells Catalyst to start using three new plugins:
+This tells Catalyst to start using one new plugin:
=over 4
browser, not in the console window from which you're running your
application, which is where logging output usually goes.
-=item *
-
-L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
-
-Automatically provides a Catalyst "end action" that invokes your view at
-the end of each request. Also allows you to add "dump_info=1" (precede
-with "?" or "&" depending on where it is in the URL) to I<force> the
-debug screen at the end of the Catalyst request processing cycle.
-
-B<TIP>: Many Catalyst-related documents predate
-L<DefaultEnd|Catalyst::Plugin::DefaultEnd> and suggest that you add an
-C<end> action to your application class (C<MyApp.pm>) or Root.pm
-(C<MyApp/Controller/Root.pm>). In most of these cases, you can convert
-to L<DefaultEnd|Catalyst::Plugin::DefaultEnd> by deleting the C<end>
-action and using the plugin instead. There are certainly cases when
-you'd want to write your own custom C<end> action, but for most
-circumstances, DefaultEnd will be exactly what you want.
-
=back
Note that when specifying plugins on the C<use Catalyst> line, you can
the plugin names across multiple lines as shown here, or place them all
on one (or more) lines as with the default configuration.
+B<TIP:> You may see examples that include the
+L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
+plugins. As of Catalyst 5.7000, C<DefaultEnd> has been
+deprecated in favor of
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
+(as the name of the package suggests, C<RenderView> is not
+a plugin, but an action). The purpose of both is essentially the same:
+forward processing to the view to be rendered. Applications generated
+under 5.7000 should automatically use C<RenderView> and "just work"
+for most applications. For more information on C<RenderView> and
+the various options for forwarding to your view logic, please refer
+to the "Using RenderView for the Default View" section under
+"CATALYST VIEWS" below.
+
+
=head1 DATABASE ACCESS WITH C<DBIx::Class>
Catalyst can be used with virtually any form of persistent datastore
-available via Perl. For example, L<Catalyst::Model::DBI> can be used to
-easily access databases through the traditional Perl L<DBI> interface.
+available via Perl. For example,
+L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to
+easily access databases through the traditional Perl C<DBI> interface.
However, most Catalyst applications use some form of ORM technology to
automatically create and save model objects as they are used. Although
-Tony Bowden's L<Class::DBI> has been the traditional Perl ORM engine,
-Matt Trout's L<DBIx::Class> (abbreviated as "DBIC") has rapidly emerged
-as the Perl-based ORM technology of choice. Most new Catalyst
-applications rely on DBIC, as will this tutorial.
+Tony Bowden's L<Class::DBI|Class::DBI> has been the traditional
+Perl ORM engine, 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 DBIC, as will this tutorial.
-Note: See L<Catalyst:: Model::CDBI > for more information on using
-Catalyst with L<Class::DBI>.
+Note: See L<Catalyst:: Model::CDBI> for more information on using
+Catalyst with L<Class::DBI|Class::DBI>.
=head2 Create a DBIC Schema File
B<Note:> C<__PACKAGE__> is just a shorthand way of referencing the name
of the package where it is used. Therefore, in C<MyAppDB.pm>,
-C<__PACKAGE__> is equivalent to C<MyAppDB>
+C<__PACKAGE__> is equivalent to C<MyAppDB>.
=head2 Create the DBIC "Result Source" Files
__PACKAGE__->add_columns(qw/id first_name last_name/);
# Set the primary key for the table
__PACKAGE__->set_primary_key(qw/id/);
-
+
#
# Set relationships:
#
# 2) Name of the model class referenced by this relationship
# 3) Column name in *this* table
__PACKAGE__->belongs_to(book => 'MyAppDB::Book', 'book_id');
-
+
# belongs_to():
# args:
# 1) Name of relationship, DBIC will create accessor with this name
This is an object that represents a row in the 'book_authors' table of your
application database. It uses DBIx::Class (aka, DBIC) to do ORM.
-
+
You probably won't need to use this class directly -- it will be automatically
used by DBIC where joins are needed.
=head2 Use C<Catalyst::Model::DBIC::Schema> To Load The Model Class
-When L<Catalyst::Model::DBIC::Schema> is
+When L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> is
in use, Catalyst essentially reads an existing copy of your database
model and creates a new set of objects under C<MyApp::Model> for use
inside of Catalyst.
-B<Note:> With L<Catalyst::Model::DBIC::Schema> you essentially end up
-with two sets of model classes (only one of which you write... the other
-set is created automatically in memory when your Catalyst application
-initializes). For this tutorial application, the important points to
-remember are: you write the I<result source> files in C<MyAppDB>, but
-I<within Catalyst> you use the I<automatically created model classes> in
-C<MyApp::Model>.
+B<Note:> With
+L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> you
+essentially end up with two sets of model classes (only one of which
+you write... the other set is created automatically in memory when
+your Catalyst application initializes). For this tutorial application,
+the important points to remember are: you write the I<result source>
+files in C<MyAppDB>, but I<within Catalyst> you use the I<automatically
+created model classes> in C<MyApp::Model>.
-Use the L<Catalyst::Helper::Model::DBIC::Schema > helper script to
-create the model class that loads up the model we created in the
-previous step:
+Use the
+L<Catalyst::Helper::Model::DBIC::Schema|Catalyst::Helper::Model::DBIC::Schema>
+helper script to create the model class that loads up the model we
+created in the previous step:
$ script/myapp_create.pl model MyAppDB DBIC::Schema MyAppDB dbi:SQLite:myapp.db '' '' '{ AutoCommit => 1 }'
+ exists "/root/dev/MyApp/script/../lib/MyApp/Model"
+ exists "/root/dev/MyApp/script/../t"
+ created "/root/dev/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
+ created "/root/dev/MyApp/script/../t/model_MyAppDB.t"
+
Where the first C<MyAppDB> is the name of the class to be created by the
helper in C<lib/MyApp/Model> and the second C<MyAppDB> is the name of
actions:
$ script/myapp_create.pl controller Books
+ exists "/root/dev/MyApp/script/../lib/MyApp/Controller"
+ exists "/root/dev/MyApp/script/../t"
+ created "/root/dev/MyApp/script/../lib/MyApp/Controller/Books.pm"
+ created "/root/dev/MyApp/script/../t/controller_Books.t"
Then edit C<lib/MyApp/Controller/Books.pm> and add the following method
to the controller:
are equivalent.
B<Note:> Catalyst actions are regular Perl methods, but they make use of
-Nicholas Clark's C<attributes> module to provide additional information
-to the Catalyst dispatcher logic.
+Nicholas Clark's C<attributes> module (that's the C<: Local> next to the
+C<sub list> in the code above) to provide additional information to the
+Catalyst dispatcher logic.
+
=head1 CATALYST VIEWS
Views are where you render output, typically for display in the user's
-web browser, but also possibly using other display our output-generation
+web browser, but also possibly using other display output-generation
systems. 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 popular View technologies
+L<http://www.template-toolkit.org>). Other popular view technologies
include Mason (L<http://www.masonhq.com> and
-L<http://www.masonbook.com>) and L<HTML::Template>
+L<http://www.masonbook.com>) and L<HTML::Template|HTML::Template>
(L<http://html-template.sourceforge.net>).
=head2 Create a Catalyst View Using C<TTSITE>
=item *
-L<Catalyst::Helper::View::TT>
+L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
=item *
-L<Catalyst::Helper::View::TTSite>
+L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
=back
rendering for this tutorial:
$ script/myapp_create.pl view TT TTSite
+ exists "/root/dev/MyApp/script/../lib/MyApp/View"
+ exists "/root/dev/MyApp/script/../t"
+ created "/root/dev/MyApp/script/../lib/MyApp/View/TT.pm"
+ created "/root/dev/MyApp/script/../root/lib"
+ ...
+ created "/root/dev/MyApp/script/../root/src/ttsite.css"
This puts a number of files in the C<root/lib> and C<root/src>
directories that can be used to customize the look and feel of your
values set by the C<TTSite> helper.
B<TIP>: Note that TTSite does one thing that could confuse people who
-are used to the normal C<TT> Catalyst View: it redefines the Catalyst
+are used to the normal C<TT> Catalyst view: it redefines the Catalyst
context object in templates from its usual C<c> to C<Catalyst>. When
looking at other Catalyst examples, remember that they almost always use
C<c>. Note that Catalyst and TT I<do not complain> when you use the
wrong name to access the context object...TT simply outputs blanks for
-that bogus logic. Finally, be aware that this change in name I<only>
+that bogus logic (see next tip to change this behavior with TT C<DEBUG>
+options). Finally, be aware that this change in name I<only>
applies to how the context object is accessed inside your TT templates;
your controllers will continue to use C<$c> (or whatever name you use
when fetching the reference from C<@_> inside your methods). (You can
careful not to have a collision between your own C<c> variable and the
Catalyst C<c> variable.)
+B<TIP>: When troubleshooting TT it can be helpful to enable variable
+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<MyApp/View/TT.pm>:
+
+ __PACKAGE__->config({
+ CATALYST_VAR => 'Catalyst',
+ ...
+ DEBUG => 'undef',
+ ...
+ });
+
+There are a variety of options you can use, such as 'undef', 'all',
+'service', 'context', 'parser', 'provider', and 'service'. See
+L<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).
+
+
+=head2 Using C<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 v5.7000 ships with a new mechanism,
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>, that
+automatically performs this operation. If you look in
+C<lib/MyApp/Controller/Root.pm>, you should see the this 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 extended C<RenderView> in C<sub end>.
+
+=back
+
+
+=head3 The History Leading Up To C<RenderView>
+
+Although C<RenderView> strikes a nice balance between default
+behavior and easy extensibility, it is a new feature that won't
+appear in most existing Catalyst examples. This section provides
+some brief background on the evolution of default view rendering
+logic with an eye to how they can be migrated to C<RenderView>:
+
+=over 4
+
+=item *
+
+Private C<end> Action in Application Class
+
+Older Catalyst-related documents often suggest that you add a "private
+end action" to your application class (C<MyApp.pm>) or Root.pm
+(C<MyApp/Controller/Root.pm>). These examples should be easily
+converted to L<RenderView|Catalyst::Action::RenderView> by simply adding
+C<ActionClass('RenderView')> to the C<sub end> definition. If end sub is
+defined in your application class (C<MyApp.pm>), you should also migrate
+it to C<MyApp/Controller/Root.pm>.
+
+=item *
+
+L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
+
+C<DefaultEnd> represented the "next step" in passing processing from
+your controller to your view. It has the advantage of only requiring
+that C<DefaultEnd> be added to the list of plugins in C<lib/MyApp.pm>.
+It also allowed you to add "dump_info=1" (precede with "?" or "&"
+depending on where it is in the URL) to I<force> the debug screen at the
+end of the Catalyst request processing cycle. However, it was more
+difficult to extend than the C<RenderView> mechanism, and is now
+deprecated.
+
+=item *
+
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
+
+As discussed above, the current recommended approach to handling your
+view logic relies on
+L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>. Although
+similar in first appearance to the "private end action" approach, it
+utilizes Catalyst's "ActionClass" mechanism to provide both automatic
+default behavior (you don't have to include a plugin as with
+C<DefaultEnd>) and easy extensibility. As with C<DefaultEnd>, it allows
+you to add "dump_info=1" (precede with "?" or "&" depending on where it
+is in the URL) to I<force> the debug screen at the end of the Catalyst
+request processing cycle.
+
+=back
+
+It is recommended that all Catalyst applications use or migrate to
+the C<RenderView> approach.
+
+
=head2 Globally Customize Every View
When using TTSite, files in the subdirectories of C<root/lib> can be
B<Note:> 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> (we will use
-Catalyst sessions in the Authentication part).
+L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
+Catalyst sessions in the Authentication part of the tutorial).
=head2 Create a TT Template Page
<td>[% book.title %]</td>
<td>[% book.rating %]</td>
<td>
- [% # Print author count in parens. 'book.authors' uses the 'many_to_many' -%]
- [% # relationship to retrieve all of the authors of a book. 'size' is a -%]
- [% # TT VMethod to get the number of elements in a list. -%]
- ([% book.authors.size %])
- [% # Use an alternate form of a FOREACH loop to display authors. -%]
- [% # _ below is the TT string concatenation operator. -%]
- [% author.last_name _' ' FOREACH author = book.authors %]
- [% # Note: if many_to_many relationship not used in Authors.pm, you could -%]
- [% # have used the following to 'walk' through the 'join table objects' -%]
- [% # bk_author.author.last_name _' ' FOREACH bk_author = book.book_authors %]
+ [% # 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 -%]
+ [% # 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 -%]
+ ([% tt_authors.size %])
+ [% # Use another TT vmethod to join & print the names & comma separators -%]
+ [% tt_authors.join(', ') %]
</td>
</tr>
[% END -%]
TT's META feature to provide a title to C<root/lib/site/header>.
Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
object and prints the C<title> and C<rating> fields. An inner
-C<FOREACH> loop prints the last name of each author in a single table
-cell (a simple space is used between the names; in reality you would
-probably want to modify the code to use a comma as a separator).
+C<FOREACH> loop prints the last name of each author in a comma-separated
+list within a single table cell.
If you are new to TT, the C<[%> and C<%]> tags are used to delimit TT
code. TT supports a wide variety of directives for "calling" other
$ export DBIX_CLASS_STORAGE_DBI_DEBUG=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 DBIX_CLASS_STORAGE_DBI_DEBUG 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
$ script/myapp_server.pl
-You should get something like this:
+Your development server log output should display something like:
$ script/myapp_server.pl
- [Tue May 16 12:51:33 2006] [catalyst] [debug] Debug messages enabled
- [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded plugins:
- .------------------------------------------------------------------------------.
- | Catalyst::Plugin::ConfigLoader 0.07 |
- | Catalyst::Plugin::Static::Simple 0.14 |
- | Catalyst::Plugin::StackTrace 0.04 |
- | Catalyst::Plugin::DefaultEnd 0.06 |
- '------------------------------------------------------------------------------'
-
- [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
- [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
- [Tue May 16 12:51:33 2006] [catalyst] [debug] Found home "/home/me/MyApp"
- [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded components:
- .-------------------------------------------------------------------+----------.
- | Class | Type |
- +-------------------------------------------------------------------+----------+
- | MyApp::Controller::Books | instance |
- | MyApp::Controller::Root | instance |
- | MyApp::Model::MyAppDB | instance |
- | MyApp::Model::MyAppDB::Author | class |
- | MyApp::Model::MyAppDB::Book | class |
- | MyApp::Model::MyAppDB::BookAuthor | class |
- | MyApp::View::TT | instance |
- '-------------------------------------------------------------------+----------'
-
- [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded Private actions:
- .----------------------+----------------------------------------+--------------.
- | Private | Class | Method |
- +----------------------+----------------------------------------+--------------+
- | /default | MyApp::Controller::Root | default |
- | /end | MyApp | end |
- | /books/list | MyApp::Controller::Books | list |
- '----------------------+----------------------------------------+--------------'
-
- [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded Path actions:
- .--------------------------------------+---------------------------------------.
- | Path | Private |
- +--------------------------------------+---------------------------------------+
- | /books/list | /books/list |
- '--------------------------------------+---------------------------------------'
-
- [Tue May 16 12:51:37 2006] [catalyst] [info] MyApp powered by Catalyst 5.6902
- You can connect to your server at http://localhost:3000
+ [debug] Debug messages enabled
+ [debug] Loaded plugins:
+ .----------------------------------------------------------------------------.
+ | Catalyst::Plugin::ConfigLoader 0.06 |
+ | Catalyst::Plugin::StackTrace 0.04 |
+ | Catalyst::Plugin::Static::Simple 0.14 |
+ '----------------------------------------------------------------------------'
+
+ [debug] Loaded dispatcher "Catalyst::Dispatcher"
+ [debug] Loaded engine "Catalyst::Engine::HTTP"
+ [debug] Found home "/home/me/MyApp"
+ [debug] Loaded components:
+ .-----------------------------------------------------------------+----------.
+ | Class | Type |
+ +-----------------------------------------------------------------+----------+
+ | MyApp::Controller::Books | instance |
+ | MyApp::Controller::Root | instance |
+ | MyApp::Model::MyAppDB | instance |
+ | MyApp::Model::MyAppDB::Author | class |
+ | MyApp::Model::MyAppDB::Book | class |
+ | MyApp::Model::MyAppDB::BookAuthor | class |
+ | MyApp::View::TT | instance |
+ '-----------------------------------------------------------------+----------'
+
+ [debug] Loaded Private actions:
+ .----------------------+--------------------------------------+--------------.
+ | Private | Class | Method |
+ +----------------------+--------------------------------------+--------------+
+ | /default | MyApp::Controller::Root | default |
+ | /end | MyApp::Controller::Root | end |
+ | /books/index | MyApp::Controller::Books | index |
+ | /books/list | MyApp::Controller::Books | list |
+ '----------------------+--------------------------------------+--------------'
+
+ [debug] Loaded Path actions:
+ .-------------------------------------+--------------------------------------.
+ | Path | Private |
+ +-------------------------------------+--------------------------------------+
+ | /books/list | /books/list |
+ '-------------------------------------+--------------------------------------'
+
+ [info] MyApp powered by Catalyst 5.7000
+ You can connect to your server at http://localhost.localdomain:3000
Some things you should note in the output above:
JOIN authors author ON ( author.id = me.author_id )
WHERE ( me.book_id = ? ): `1'
-You should see 10 such lines of debug output, two for each of the five
-author_id values (it pulls the data once for the count logic and another
-time to actually display the list).
+You should see 5 such lines of debug output as DBIC fetches the author
+information for each book.
=head1 AUTHOR
Kennedy Clark, C<hkclark@gmail.com>
-Please report any errors, issues or suggestions to the author.
+Please report any errors, issues or suggestions to the author. The
+most recent version of the Catalyst Tutorial can be found at
+L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Runtime/lib/Catalyst/Manual/Tutorial/>.
Copyright 2006, Kennedy Clark, under Creative Commons License
(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
-Version: .94
-