=item 9
-L<Appendices|Catalyst::Manual::Tutorial::Appendicies>
+L<Appendices|Catalyst::Manual::Tutorial::Appendices>
=back
=back
-B<TIP>: Note that all of the code for this part of the tutorial can be
-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.
-
+You can checkout the source code for this example from the catalyst
+subversion repository as per the instructions in
+L<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.
+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 the case of this tutorial, use the Catalyst C<catalyst.pl> script to
initialize the framework for an application called C<MyApp>:
[debug] Debug messages enabled
[debug] Loaded plugins:
.----------------------------------------------------------------------------.
- | Catalyst::Plugin::ConfigLoader 0.06 |
+ | Catalyst::Plugin::ConfigLoader 0.13 |
| Catalyst::Plugin::Static::Simple 0.14 |
'----------------------------------------------------------------------------'
[debug] Loaded dispatcher "Catalyst::Dispatcher"
[debug] Loaded engine "Catalyst::Engine::HTTP"
- [debug] Found home "/root/dev/MyApp"
+ [debug] Found home "/home/me/MyApp"
+ [debug] Loaded Config "/home/me/myapp.yml"
[debug] Loaded components:
.-----------------------------------------------------------------+----------.
| Class | Type |
| /end | MyApp::Controller::Root | end |
'----------------------+--------------------------------------+--------------'
- [info] MyApp powered by Catalyst 5.70_03
- You can connect to your server at http://localhost.localdomain:3000
+ [info] MyApp powered by Catalyst 5.7002
+ You can connect to your server at http://localhost: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. It doesn't make a difference at this point, but it will as soon
+as we get the database going in the next section.
Point your web browser to L<http://localhost:3000> (substituting a
different hostname or IP address as appropriate) and you should be
following should be appended to the logging output of the development
server:
- [info] *** Request 1 (0.008/s) [2822] [Mon Jul 3 12:42:43 2006] ***
+ [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.154781s (6.461/s)
+ [info] Request took 0.067675s (14.777/s)
.----------------------------------------------------------------+-----------.
| Action | Time |
+----------------------------------------------------------------+-----------+
- | /default | 0.000006s |
- | /end | 0.000007s |
+ | /default | 0.002844s |
+ | /end | 0.000207s |
'----------------------------------------------------------------+-----------'
Press Ctrl-C to break out of the development server.
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 (7, 'Nathan', 'Torkington');
INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
INSERT INTO book_authors VALUES (1, 1);
INSERT INTO book_authors VALUES (1, 2);
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
+Note: See L<Catalyst::Model::CDBI> for more information on using
Catalyst with L<Class::DBI|Class::DBI>.
=head2 Create a DBIC Schema File
load the model object for the C<books>, C<book_authors>, and C<authors>
tables created in the previous step.
-Open C<lib/MyAppDB.pm> in your editor and insert:
+Create C<lib/MyAppDB.pm> in your editor and insert:
package MyAppDB;
of the package where it is used. Therefore, in C<MyAppDB.pm>,
C<__PACKAGE__> is equivalent to C<MyAppDB>.
+B<Note:> 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 as shown above.
+
=head2 Create the DBIC "Result Source" Files
$ mkdir lib/MyAppDB
-Then open C<lib/MyAppDB/Book.pm> in your editor and enter:
+Then create C<lib/MyAppDB/Book.pm> in your editor and enter:
package MyAppDB::Book;
Note that you cannot define a C<many_to_many> relationship without also
having the C<has_many> relationship in place.
-Next, open C<lib/MyAppDB/Author.pm> in your editor and enter:
+Next, create C<lib/MyAppDB/Author.pm> in your editor and enter:
package MyAppDB::Author;
1;
-Finally, open C<lib/MyAppDB/BookAuthor.pm> in your editor and enter:
+Finally, create C<lib/MyAppDB/BookAuthor.pm> in your editor and enter:
package MyAppDB::BookAuthor;
$c->stash->{books} = [$c->model('MyAppDB::Book')->all];
# Set the TT template to use. You will almost always want to do this
- # in your action methods.
+ # in your action methods (action methods respond to user input in
+ # your controllers).
$c->stash->{template} = 'books/list.tt2';
}
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>
+=head2 Create a Catalyst View Using C<TTSite>
When using TT for the Catalyst view, there are two main helper scripts:
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>:
+C<lib/MyApp/View/TT.pm>:
__PACKAGE__->config({
CATALYST_VAR => 'Catalyst',
portion of the name shown in the TT docs and convert to lower case
for use inside Catalyst).
+B<NOTE:> Please be sure to disable TT debug options before
+continuing the tutorial (especially the 'undef' option -- leaving
+this enabled will conflict with several of the conventions used
+by this tutorial and TTSite to leave some variables undefined
+on purpose).
+
=head2 Using C<RenderView> for the Default View
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
+C<lib/MyApp/Controller/Root.pm>, you should see the empty
definition for the C<sub end> method:
sub end : ActionClass('RenderView') {}
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>.
+the attribute 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 *
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 the C<RenderView> mechanism, and is now deprecated.
+difficult to extend than the C<RenderView> mechanism, and is now
+deprecated.
=item *
$ mkdir root/src/books
-Then open C<root/src/books/list.tt2> in your editor and enter:
+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 -%]
<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 we make a bogus assignment to the -%]
- [% # 'unused' vbl to avoid printing the size of the list after each push. -%]
+ [% # 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 = [ ];
- unused = tt_authors.push(author.last_name) FOREACH author = book.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 vmethod to join & print the names with comma separators -%]
+ [% # Use another TT vmethod to join & print the names & comma separators -%]
[% tt_authors.join(', ') %]
</td>
</tr>
DBIx::Class to dump the SQL statements it's using to access the database
(this option can provide extremely helpful troubleshooting information):
- $ export DBIX_CLASS_STORAGE_DBI_DEBUG=1
+ $ export DBIC_TRACE=1
+
+B<NOTE>: You can also use the older
+C<export DBIX_CLASS_STORAGE_DBI_DEBUG=1>, that that's a lot more to
+type.
This assumes you are using BASH as your shell -- adjust accordingly if
you are using a different shell (for example, under tcsh, use
[debug] Debug messages enabled
[debug] Loaded plugins:
.----------------------------------------------------------------------------.
- | Catalyst::Plugin::ConfigLoader 0.06 |
- | Catalyst::Plugin::StackTrace 0.04 |
+ | Catalyst::Plugin::ConfigLoader 0.13 |
+ | Catalyst::Plugin::StackTrace 0.06 |
| 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 Config "/home/me/myapp.yml"
[debug] Loaded components:
.-----------------------------------------------------------------+----------.
| Class | Type |
| /books/list | /books/list |
'-------------------------------------+--------------------------------------'
- [info] MyApp powered by Catalyst 5.7000
- You can connect to your server at http://localhost.localdomain:3000
+ [info] MyApp powered by Catalyst 5.7002
+ You can connect to your server at http://localhost:3000
Some things you should note in the output above:
information for each book.
+=head1 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('MyAppDB::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';
+ }
+
+C<Catalyst::View::TT> defaults to looking for a template with no
+extension. In our case, we need to override this to look for an
+extension of C<.tt2>. Open C<lib/MyApp/View/TT.pm> and add the
+C<TEMPLATE_EXTENSION> definition as follows:
+
+ __PACKAGE__->config({
+ CATALYST_VAR => 'Catalyst',
+ INCLUDE_PATH => [
+ MyApp->path_to( 'root', 'src' ),
+ MyApp->path_to( 'root', 'lib' )
+ ],
+ PRE_PROCESS => 'config/main',
+ WRAPPER => 'site/wrapper',
+ ERROR => 'error.tt2',
+ TIMER => 0,
+ TEMPLATE_EXTENSION => '.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 Part 2 and
+Part 8 of the Tutorial).
+
+
+=head1 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>:
+
+ $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@gmail.com>
Please report any errors, issues or suggestions to the author. The
-most recent version of the Catlayst Tutorial can be found at
+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