initial import of new Tutorial stuff from hkclark
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Manual / Tutorial / CatalystBasics.pod
1 =head1 NAME
2
3 Catalyst::Manual::Tutorial::CatalystBasics - Catalyst Tutorial – Part 2: Catalyst Application Development Basics
4
5
6
7 =head1 OVERVIEW
8
9 This is B<Part 2 of 9> for the Catalyst tutorial.
10
11 L<Totorial Overview|Catalyst::Manual::Tutorial>
12
13 =over 4
14
15 =item 1
16
17 L<Introduction|Catalyst::Manual::Tutorial::Intro>
18
19 =item 2
20
21 B<Catalyst Basics>
22
23 =item 3
24
25 L<Basic CRUD|Catalyst::Manual::Tutorial03_BasicCRUD>
26
27 =item 4
28
29 L<Authentication|Catalyst::Manual::Tutorial::Authentication>
30
31 =item 5
32
33 L<Authorization|Catalyst::Manual::Tutorial::Authorization>
34
35 =item 6
36
37 L<Debugging|Catalyst::Manual::Tutorial::Debugging>
38
39 =item 7
40
41 L<Testing|Catalyst::Manual::Tutorial::Testing>
42
43 =item 8
44
45 L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
46
47 =item 9
48
49 L<Appendicies|Catalyst::Manual::Tutorial::Appendicies>
50
51 =back
52
53
54
55 =head1 DESCRIPTION
56
57 In this part of the tutorial, we will create a very basic Catalyst web application.  Though simple in many respects, this section will already demonstrate a number of powerful capabilities such as:
58
59 =over 4
60
61 =item * Helper Scripts
62
63 Catalyst helper scripts that can be used to rapidly bootstrap the skeletal structure of an application.
64
65 =item * MVC
66
67 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:
68
69 =over 4
70
71 =item * Model
72
73 In most applications, the model equates to the objects that are created from and saved to your SQL database.
74
75 =item * View
76
77 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 or Excel spreadsheets.
78
79 =item * Controller
80
81 As suggested by its name, the controller takes user requests and routes them to the necessary model and view.
82
83 =back
84
85 =item * ORM
86
87 The use Object-Relational Mapping (ORM) technology for database access (specifically, ORM provides an automated means to persist and restore objects to/from a relational database).
88
89 =back
90
91 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:
92
93     svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial@###
94     IMPORTANT: Does not work yet.  Will be completed for final version.
95
96
97
98 =head1 CREATE A CATALYST PROJECT
99
100 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.
101
102 In the case of this tutorial, use the Catalyst C<catalyst.pl> script to initialize the framework for an application called C<MyApp>:
103
104     $ catalyst.pl MyApp
105     $ cd MyApp
106
107 The C<catalyst.pl> helper script will display the names of the directories and files it creates.
108
109 Though it's obviously too early for any significant celebration, we already have a functioning application.  Run the following command to run this application with the built-in development web server:
110
111         $ script/myapp_server.pl
112
113 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.
114
115
116
117 =head1 CREATE A SQLITE DATABASE
118
119 In this step, we make a text file with the required SQL commands to create a database table and load some sample data.  Open C<myapp01.sql> in your editor and enter:
120
121     --
122     -- Create a very simple database to hold book and author information
123     --
124     CREATE TABLE books (
125             id          INTEGER PRIMARY KEY,
126             title       TEXT ,
127             rating      INTEGER
128     );
129     -- 'book_authors' is a many-to-many join table between books & authors
130     CREATE TABLE book_authors (
131             book_id     INTEGER,
132             author_id   INTEGER,
133             PRIMARY KEY (book_id, author_id)
134     );
135     CREATE TABLE authors (
136             id          INTEGER PRIMARY KEY,
137             first_name  TEXT,
138             last_name   TEXT
139     );
140     ---
141     --- Load some sample data
142     ---
143     INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
144     INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
145     INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
146     INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
147     INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
148     INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
149     INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
150     INSERT INTO authors VALUES (3, 'Christian', 'Degu');
151     INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
152     INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
153     INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
154     INSERT INTO authors VALUES (7, ' Nathan', 'Torkington');
155     INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
156     INSERT INTO book_authors VALUES (1, 1);
157     INSERT INTO book_authors VALUES (1, 2);
158     INSERT INTO book_authors VALUES (1, 3);
159     INSERT INTO book_authors VALUES (2, 4);
160     INSERT INTO book_authors VALUES (3, 5);
161     INSERT INTO book_authors VALUES (4, 6);
162     INSERT INTO book_authors VALUES (4, 7);
163     INSERT INTO book_authors VALUES (5, 8);
164
165 B<TIP>: See Appendix 1 for tips on removing the leading spaces when cutting and pasting example code from Pod documents.
166
167 Then use the following command to build a C<myapp.db> SQLite database:
168
169     $ sqlite3 myapp.db < myapp01.sql
170
171 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 < myapp01.sql> command.
172
173 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:
174
175     $ sqlite3 myapp.db
176     SQLite version 3.2.2
177     Enter ".help" for instructions
178     sqlite> select * from books;
179     1|CCSP SNRS Exam Certification Guide|5
180     2|TCP/IP Illustrated, Volume 1|5
181     3|Internetworking with TCP/IP Vol.1|4
182     4|Perl Cookbook|5
183     5|Designing with Web Standards|5
184     sqlite> .q
185     $
186
187 Or:
188
189     $ sqlite3 myapp.db "select * from books"
190     1|CCSP SNRS Exam Certification Guide|5
191     2|TCP/IP Illustrated, Volume 1|5
192     3|Internetworking with TCP/IP Vol.1|4
193     4|Perl Cookbook|5
194     5|Designing with Web Standards|5
195
196 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.
197
198
199
200 =head1 EDIT THE LIST OF CATALYST PLUGINS
201
202 One of the greatest benefits of Catalyst is that it has such a large library of plugins 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.
203
204 By default, Catalyst enables three plugins/flags:
205
206 =over 4
207
208 =item * 
209
210 C<-Debug> Flag
211
212 Enables the Catalyst debug output you saw when we started the C<script/myapp_server.pl> development server earlier.  You can remove this plugin when you place your application into production.
213
214 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).  
215
216 If you prefer, you can use the C<$c-E<gt>debug> method to enable debug messages.
217
218 =item *
219
220 L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
221
222 C<ConfigLoader> provides an automatic way to load your configurable parameters for your application from a central YAML file (versus having the values hard-coded inside your Perl modules).  If you have not been exposed to YAML before, it is a human-readable data serialization format that can be used to read (and write) values to/from text files.  We will see how to use this feature of Catalyst during the authentication and authorization sections (Part 4 and Part 5).
223
224
225 =item *
226
227 L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
228
229 C<Static::Simple> provides an easy method of serving static content such as images and CSS files under the development server.
230
231 =back
232
233 To modify the list of plugins, edit C<lib/MyApp.pm> (this file is generally referred to as your I<application class>) and delete the line with:
234
235     use Catalyst qw/-Debug ConfigLoader Static::Simple/;
236
237 Replace it with:
238
239     use Catalyst qw/
240             -Debug
241             ConfigLoader
242             Static::Simple
243             
244             Dumper
245             StackTrace
246             DefaultEnd
247             /;
248
249 This tells Catalyst to start using three new plugins:
250
251 =over 4
252
253 =item * 
254
255 L<Catalyst::Plugin::Dumper|Catalyst::Plugin::Dumper>
256
257 Allows you to easily use L<Data::Dumper|Data::Dumper> to dump variables to the logs, for example:
258
259     $c->log->dumper($myvar);
260
261 When running your application under the development server, the logs will be printed to your screen along with the other debug information generated by the C<-Debug> flag.
262
263 =item * 
264
265 L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>
266
267 Adds a stack trace to the standard Catalyst "debug screen" (this is the screen Catalyst sends to your browser when an error occurs).
268
269 Note: L<Dumper|Catalyst::Plugin::Dumper> output appears on the console/telnet/SSH window where you issue the C<script/myapp_server.pl> command.  L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your browser.
270
271 =item * 
272
273 L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
274
275 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.  
276
277 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.
278
279 =back
280
281 Note that when specifying plugins on the C<use Catalyst> 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.
282
283
284
285 =head1 DATABASE ACCESS WITH C<DBIx::Class>
286
287 Catalyst can be used with virtually any form of persistent datastore available via Perl.  For example, L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to easily access databases through the traditional Perl 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|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.
288
289 Note: See L<Catalyst::Model::CDBI| Catalyst:: Model::CDBI > for more information on using Catalyst with L<Class::DBI|Class::DBI>.  Catalyst can also be used with "plain old DBI"; see L<Catalyst::Model::DBI| Catalyst::Model::DBI>.
290
291
292 =head2 Create a DBIC Schema File
293
294 DBIx::Class uses a schema file to load other classes that represent the tables in your database (DBIC refers to these "table objects" as "result sources," see L<DBIx::Class::ResultSource|DBIx::Class::ResultSource>).  In this case, we want to load the model object for the C<books>, C<book_authors>, and C<authors> tables created in the previous step.
295
296 Open C<lib/MyAppDB.pm> in your editor and insert:
297
298     package MyAppDB;
299     
300     =head1 NAME 
301     
302     MyAppDB -- DBIC Schema Class
303     
304     =cut
305     
306     # Our schema needs to inherit from 'DBIx::Class::Schema'
307     use base qw/DBIx::Class::Schema/;
308     
309     # Need to load the DB Model classes here.
310     # You can use this syntax if you want:
311     #    __PACKAGE__->load_classes(qw/Book BookAuthor Author/);
312     # Also, if you simply want to load all of the classes in a directory
313     # of the same name as your schema class (as we do here) you can use:
314     #    __PACKAGE__->load_classes(qw//);
315     # But the variation below is more flexible in that it can be used to 
316     # load from multiple namespaces.
317     __PACKAGE__->load_classes({
318         MyAppDB => [qw/Book BookAuthor Author/]
319     });
320     
321     1;
322
323 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>
324
325
326 =head2 Create the DBIC "Result Source" Files
327
328 In this step, we create "table classes" (again, these are called a "result source" classes in DBIC) that acts as model objects for the C<books>, C<book_authors>, and C<authors> tables in our database.
329
330 First, create a directory to hold the class:
331
332     $ mkdir lib/MyAppDB
333
334 Then open C<lib/MyAppDB/Book.pm> in your editor and enter:
335
336     package MyAppDB::Book;
337     
338     use base qw/DBIx::Class/;  
339     
340     # Load required DBIC stuff
341     __PACKAGE__->load_components(qw/PK::Auto Core/);
342     # Set the table name
343     __PACKAGE__->table('books');
344     # Set columns in table
345     __PACKAGE__->add_columns(qw/id title rating/);
346     # Set the primary key for the table
347     __PACKAGE__->set_primary_key(qw/id/);
348     
349     #
350     # Set relationships:
351     #
352     
353     # has_many():
354     #   args:
355     #     1) Name of relationship, DBIC will create accessor with this name
356     #     2) Name of the model class referenced by this relationship
357     #     3) Column name in *foreign* table
358     __PACKAGE__->has_many(book_authors => 'MyAppDB::BookAuthor', 'book_id');
359     
360     # many_to_many():
361     #   args:
362     #     1) Name of relationship, DBIC will create accessor with this name
363     #     2) Name of has_many() relationship this many_to_many() is shortcut for
364     #     3) Name of belongs_to() relationship in model class of has_many() above 
365     #   You must already have the has_many() defined to use a many_to_many().
366     __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
367     
368     
369     =head1 NAME
370     
371     MyAppDB::Book - A model object representing a book.
372     
373     =head1 DESCRIPTION
374     
375     This is an object that represents a row in the 'books' table of your application
376     database.  It uses DBIx::Class (aka, DBIC) to do ORM.
377     
378     For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
379     Offline utilities may wish to use this class directly.
380     
381     =cut
382     
383     1;
384
385 This 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_authors> table as in C<$book-E<gt>book_authors-E<gt>first-E<gt>author-E<gt>last_name> (we will see examples on how to use DBIC objects in your code soon, but note that because C<$book-E<gt>book_authors> 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>authors-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.
386
387 Next, open C<lib/MyAppDB/Author.pm> in your editor and enter:
388
389     package MyAppDB::Author;
390     
391     use base qw/DBIx::Class/;
392     
393     # Load required DBIC stuff
394     __PACKAGE__->load_components(qw/PK::Auto Core/);
395     # Set the table name
396     __PACKAGE__->table('authors');
397     # Set columns in table
398     __PACKAGE__->add_columns(qw/id first_name last_name/);
399     # Set the primary key for the table
400     __PACKAGE__->set_primary_key(qw/id/);
401
402     #
403     # Set relationships:
404     #
405     
406     # has_many():
407     #   args:
408     #     1) Name of relationship, DBIC will create accessor with this name
409     #     2) Name of the model class referenced by this relationship
410     #     3) Column name in *foreign* table
411     __PACKAGE__->has_many(book_author => 'MyAppDB::BookAuthor', 'author_id');
412     
413     # many_to_many():
414     #   args:
415     #     1) Name of relationship, DBIC will create accessor with this name
416     #     2) Name of has_many() relationship this many_to_many() is shortcut for
417     #     3) Name of belongs_to() relationship in model class of has_many() above 
418     #   You must already have the has_many() defined to use a many_to_many().
419     __PACKAGE__->many_to_many(books => 'book_author', 'book');
420     
421     
422     =head1 NAME
423     
424     MyAppDB::Author - A model object representing an author of a book (if a book has 
425     multiple authors, each will be represented be separate Author object).
426     
427     =head1 DESCRIPTION
428     
429     This is an object that represents a row in the 'authors' table of your application
430     database.  It uses DBIx::Class (aka, DBIC) to do ORM.
431     
432     For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
433     Offline utilities may wish to use this class directly.
434     
435     =cut
436     
437     1;
438
439 Finally, open C<lib/MyAppDB/BookAuthor.pm> in your editor and enter:
440
441     package MyAppDB::BookAuthor;
442     
443     use base qw/DBIx::Class/;
444     
445     # Load required DBIC stuff
446     __PACKAGE__->load_components(qw/PK::Auto Core/);
447     # Set the table name
448     __PACKAGE__->table('book_authors');
449     # Set columns in table
450     __PACKAGE__->add_columns(qw/book_id author_id/);
451     # Set the primary key for the table
452     __PACKAGE__->set_primary_key(qw/book_id author_id/);
453     
454     #
455     # Set relationships:
456     #
457     
458     # belongs_to():
459     #   args:
460     #     1) Name of relationship, DBIC will create accessor with this name
461     #     2) Name of the model class referenced by this relationship
462     #     3) Column name in *this* table
463     __PACKAGE__->belongs_to(book => 'MyAppDB::Book', 'book_id');
464
465     # belongs_to():
466     #   args:
467     #     1) Name of relationship, DBIC will create accessor with this name
468     #     2) Name of the model class referenced by this relationship
469     #     3) Column name in *this* table
470     __PACKAGE__->belongs_to(author => 'MyAppDB::Author', 'author_id');
471     
472     
473     =head1 NAME
474     
475     MyAppDB::BookAuthor - A model object representing the JOIN between an author and 
476     a book.
477     
478     =head1 DESCRIPTION
479     
480     This is an object that represents a row in the 'book_authors' table of your 
481     application database.  It uses DBIx::Class (aka, DBIC) to do ORM.
482
483     You probably won't need to use this class directly -- it will be automatically
484     used by DBIC where joins are needed.
485     
486     For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
487     Offline utilities may wish to use this class directly.
488     
489     =cut
490     
491     1;
492
493 B<Note:> This sample application uses a plural form for the database tables (e.g., C<books> and C<authors>) and a singular form for the model objects (e.g., C<Book> and C<Author>); however, Catalyst places no restrictions on the naming conventions you wish to use.
494
495
496 =head2 Use C<Catalyst::Model::DBIC::Schema> To Load The Model Class
497
498 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.
499
500 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>.
501
502 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:
503
504     $ script/myapp_create.pl model MyAppDB DBIC::Schema MyAppDB dbi:SQLite:myapp.db '' '' '{ AutoCommit => 1 }'
505
506 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 existing schema file we created (in C<lib/MyAppDB.pm>).  You can see that the helper creates a model file under C<lib/MyApp/Model> (Catalyst has a separate directory under C<lib/MyApp> for each of the three parts of MVC: C<Model>, C<View>, and C<Controller> [although older Catalyst applications often use the directories C<M>, C<V>, and C<C>]).
507
508
509
510 =head1 CREATE A CATALYST CONTROLLER
511
512 Controllers are where you write methods that respond to C<GET> and C<POST> messages from the user's web browser.
513
514 Use the Catalyst C<create> script to add a controller for book-related actions:
515
516     $ script/myapp_create.pl controller Books
517
518 Then edit C<lib/MyApp/Controller/Books.pm> and add the following method to the controller:
519
520     =head2 list
521     
522     Fetch all book objects and pass to books/list.tt2 in stash to be displayed
523     
524     =cut
525      
526     sub list : Local {
527         # Retrieve the usual perl OO '$self' for this object. $c is the Catalyst
528         # 'Context' that's used to 'glue together' the various components
529         # that make up the application
530         my ($self, $c) = @_;
531     
532         # Retrieve all of the book records as book model objects and store in the
533         # stash where they can be accessed by the TT template
534         $c->stash->{books} = [$c->model('MyAppDB::Book')->all];
535         
536         # Set the TT template to use.  You will almost always want to do this
537         # in your action methods.
538         $c->stash->{template} = 'books/list.tt2';
539     }
540
541 B<Note:> 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.
542
543 B<TIP>: You may see the C<$c-E<gt>model('MyAppDB::Book')> used above written as C<$c-E<gt>model('MyAppDB')-E<gt>resultset('Book)>.  The two are equivalent.
544
545 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.
546
547
548 =head1 CATALYST VIEWS
549
550 Views are where you render output for display in the user's web browser (or possibly using other display technology).  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 include Mason (L<http://www.masonhq.com> and L<http://www.masonbook.com>) and L<HTML::Template|HTML::Template> (L<http://html-template.sourceforge.net>).
551
552
553 =head2 Create a Catalyst View Using C<TTSITE>
554
555 When using TT for the Catalyst view, there are two main helper scripts:
556
557 =over 4
558
559 =item *
560
561 L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
562
563 =item *
564
565 L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
566
567 =back
568
569 Both are similar, but C<TT> merely 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 Part 7).  Conversely, the C<TTSite> helper creates a modular and hierarchical view layout with separate Template Toolkit (TT) files for common header and footer information, configuration values, a CSS stylesheet, etc.
570
571 Enter the following command to enable the C<TTSite> style of view rendering for the tutorial:
572
573     $ script/myapp_create.pl view TT TTSite
574
575 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 application.  Also take a look at C<lib/MyApp/View/TT.pm> for config values set by the C<TTSite> helper.
576
577 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 context object in templates from its usual C<c> to C<Catalyst>.  Also keep this in mind when looking at other Catalyst examples (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... it simply outputs blanks for that bogus logic.  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 change back to the "default" behavior be removing the C<CATALYST_VAR> line from C<lib/MyApp/View/TT.pm>, but you will also have to edit C<root/lib/config/main> and C<root/lib/config/url>.  If you do this, be careful not to have a collision between your own C<c> variable and the Catalyst C<c> variable.)
578
579
580
581 =head2 Globally Customize Every View
582
583 When using TTSite, files in the subdirectories of C<root/lib> can be used to make changes that will appear in every view.  For example, to display optional status and error messages in every view, edit C<root/lib/site/layout> update it to match the following (the two HTML C<span> elements are new):
584
585     <div id="header">[% PROCESS site/header %]</div>
586     
587     <div id="content">
588     <span class="message">[% status_msg %]</span>
589     <span class="error">[% error_msg %]</span>
590     [% content %]
591     </div>
592     
593     <div id="footer">[% PROCESS site/footer %]</div>
594
595 If we set either message in the Catalyst stash (e.g., C<$c-E<gt>stash-E<gt>{status_msg} = 'Hello world'>) it will be displayed whenever any view used by that request is rendered.  The C<message> and C<error> CSS styles are automatically defined in C<root/src/ttsite.css> and can be customized to suit your needs.
596
597 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|Catalyst::Plugin::Session> (we will use Catalyst sessions in the Authentication part).
598
599
600 =head2 Create a TT Template Page
601
602 To add a new page of content to the TTSite view hierarchy, just create a new C<.tt2> file in C<root/src>.  Only include HTML markup that goes inside the HTML <body> and </body> tags, TTSite will use the contents of C<root/lib/site> to add the top and bottom.
603
604 First create a directory for book-related TT templates:
605
606     $ mkdir root/src/books
607
608 Then open C<root/src/books/list.tt2> in your editor and enter:
609
610     [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
611     [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
612     [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
613     [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
614     
615     [% # Provide a title to root/lib/site/header -%]
616     [% META title = 'Book List' -%]
617     
618     <table>
619     <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
620     [% # Display each book in a table row %]
621     [% FOREACH book IN books -%]
622       <tr>
623         <td>[% book.title %]</td>
624         <td>[% book.rating %]</td>
625         <td>
626           [% # Print author count in parens. 'book.authors' uses the 'many_to_many' -%]
627           [% # relationship to retrieve all of the authors of a book. 'size' is a   -%]
628           [% # TT VMethod to get the number of elements in a list.                  -%]
629           ([% book.authors.size %])
630           [% # Use an alternate form of a FOREACH loop to display authors.          -%]
631           [% # _ below is the TT string concatenation operator.                     -%]
632           [% author.last_name _' ' FOREACH author = book.authors %]
633           [% # Note: if many_to_many relationship not used in Authors.pm, you could -%]
634           [% # have used the following to 'walk' through the 'join table objects'   -%]
635           [% # bk_author.author.last_name _' ' FOREACH bk_author = book.book_authors %]
636         </td>
637       </tr>
638     [% END -%]
639     </table>
640
641 As indicated by the inline comments above, the C<META title> line uses 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).  
642
643 If you are new to TT, the [% and %] tags are used to delimit "variable text".  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://www.template-toolkit.org/docs/default/Manual/Variables.html> for details and examples).  In addition to the usual C<Template> module Pod documentation, you can access the TT manual at L<http://www.template-toolkit.org/docs/default/>.
644
645 B<NOTE>: The C<TTSite> helper creates several TT files using an extension of C<.tt2>. Most other Catalyst and TT examples use an extension of C<.tt>.  You can use either extension (or no extension at all) with TTSite and TT, just be sure to use the appropriate extension for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} = ...> line in your controller.  This document will use C<.tt2> for consistency with the files already created by the C<TTSite> helper.
646
647
648
649 =head1 RUN THE APPLICATION
650
651 First, let's enable an environment variable option that causes DBIx::Class to dump the SQL statements it's using to access the database (this option can provide extremely helpful troubleshooting information):
652
653     $ export DBIX_CLASS_STORAGE_DBI_DEBUG=1
654
655 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|DBIx::Class::Manual::Troubleshooting> for details (including options to log to file vs. the Catalyst development server log.
656
657 Then run the Catalyst "demo server" script:    
658
659     $ script/myapp_server.pl
660
661 You should get something like this:
662
663     $ script/myapp_server.pl
664     [Tue May 16 12:51:33 2006] [catalyst] [debug] Debug messages enabled
665     [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded plugins:
666     .------------------------------------------------------------------------------.
667     | Catalyst::Plugin::ConfigLoader 0.07                                          |
668     | Catalyst::Plugin::Static::Simple 0.14                                        |
669     | Catalyst::Plugin::Dumper 0.000002                                            |
670     | Catalyst::Plugin::StackTrace 0.04                                            |
671     | Catalyst::Plugin::DefaultEnd 0.06                                            |
672     '------------------------------------------------------------------------------'
673     
674     [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
675     [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
676     [Tue May 16 12:51:33 2006] [catalyst] [debug] Found home "/home/me/MyApp"
677     [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded components:
678     .-------------------------------------------------------------------+----------.
679     | Class                                                             | Type     |
680     +-------------------------------------------------------------------+----------+
681     | MyApp::Controller::Books                                          | instance |
682     | MyApp::Controller::Root                                           | instance |
683     | MyApp::Model::MyAppDB                                             | instance |
684     | MyApp::Model::MyAppDB::Author                                     | class    |
685     | MyApp::Model::MyAppDB::Book                                       | class    |
686     | MyApp::Model::MyAppDB::BookAuthor                                 | class    |
687     | MyApp::View::TT                                                   | instance |
688     '-------------------------------------------------------------------+----------'
689     
690     [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded Private actions:
691     .----------------------+----------------------------------------+--------------.
692     | Private              | Class                                  | Method       |
693     +----------------------+----------------------------------------+--------------+
694     | /default             | MyApp::Controller::Root                | default      |
695     | /end                 | MyApp                                  | end          |
696     | /books/list          | MyApp::Controller::Books               | list         |
697     '----------------------+----------------------------------------+--------------'
698     
699     [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded Path actions:
700     .--------------------------------------+---------------------------------------.
701     | Path                                 | Private                               |
702     +--------------------------------------+---------------------------------------+
703     | /books/list                          | /books/list                           |
704     '--------------------------------------+---------------------------------------'
705     
706     [Tue May 16 12:51:37 2006] [catalyst] [info] MyApp powered by Catalyst 5.6902
707     You can connect to your server at http://localhost:3000
708
709 Some things you should note in the output above:
710
711 =over 4
712
713 =item * 
714
715 Catalyst::Model::DBIC::Schema took our C<MyAppDB::Book> and made it C<MyApp::Model::MyAppDB::Book> (and similar actions were performed on C<MyAppDB::Author> and C<MyAppDB::BookAuthor>).
716
717 =item * 
718
719 The "list" action in our Books controller showed up with a path of C</books/list>.
720
721 =back
722
723
724 Point your browser to L<http://localhost:3000> and you should still get the Catalyst welcome page.
725
726 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, with TTSite providing the formatting for the very simple output we generated in our template.  The count and space-separated list of author last names appear on the end of each row.
727
728 Also notice in the output of the C<script/myapp_server.pl> that DBIC used the following SQL to retrieve the data:
729
730     SELECT me.id, me.title, me.rating FROM books me
731
732 Along with a list of the following commands to retrieve the authors for each book (the lines have been "word wrapped" here to improve legibility):
733
734     SELECT author.id, author.first_name, author.last_name 
735         FROM book_authors me  
736         JOIN authors author ON ( author.id = me.author_id ) 
737         WHERE ( me.book_id = ? ): `1'
738
739 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).
740
741
742
743 =head1 AUTHOR
744
745 Kennedy Clark, C<hkclark@gmail.com>
746
747 Please report any errors, issues or suggestions to the author.
748
749 Copyright 2006, Kennedy Clark, under Creative Commons License (L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
750
751 Version: .94
752