Minor update to sync with 5.7002
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Manual / Tutorial / CatalystBasics.pod
CommitLineData
4d583dd8 1=head1 NAME
2
64ccd8a8 3Catalyst::Manual::Tutorial::CatalystBasics - Catalyst Tutorial - Part 2: Catalyst Application Development Basics
4d583dd8 4
5
4d583dd8 6=head1 OVERVIEW
7
8This is B<Part 2 of 9> for the Catalyst tutorial.
9
64ccd8a8 10L<Tutorial Overview|Catalyst::Manual::Tutorial>
4d583dd8 11
12=over 4
13
14=item 1
15
16L<Introduction|Catalyst::Manual::Tutorial::Intro>
17
18=item 2
19
20B<Catalyst Basics>
21
22=item 3
23
653f4595 24L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
4d583dd8 25
26=item 4
27
28L<Authentication|Catalyst::Manual::Tutorial::Authentication>
29
30=item 5
31
32L<Authorization|Catalyst::Manual::Tutorial::Authorization>
33
34=item 6
35
36L<Debugging|Catalyst::Manual::Tutorial::Debugging>
37
38=item 7
39
40L<Testing|Catalyst::Manual::Tutorial::Testing>
41
42=item 8
43
653f4595 44L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
4d583dd8 45
46=item 9
47
7d310f12 48L<Appendices|Catalyst::Manual::Tutorial::Appendices>
4d583dd8 49
50=back
51
208513f1 52
4d583dd8 53=head1 DESCRIPTION
54
64ccd8a8 55In this part of the tutorial, we will create a very basic Catalyst web
56application. Though simple in many respects, this section will already
57demonstrate a number of powerful capabilities such as:
4d583dd8 58
59=over 4
60
61=item * Helper Scripts
62
64ccd8a8 63Catalyst helper scripts that can be used to rapidly bootstrap the
64skeletal structure of an application.
4d583dd8 65
66=item * MVC
67
64ccd8a8 68Model/View/Controller (MVC) provides an architecture that facilitates a
69clean "separation of control" between the different portions of your
653f4595 70application. Given that many other documents cover this subject in
64ccd8a8 71detail, MVC will not be discussed in depth here (for an excellent
72introduction to MVC and general Catalyst concepts, please see
653f4595 73L<Catalyst::Manual::About>. In short:
4d583dd8 74
75=over 4
76
77=item * Model
78
653f4595 79The model usually represents a data store. In most applications, the
80model equates to the objects that are created from and saved to your SQL
81database.
4d583dd8 82
83=item * View
84
64ccd8a8 85The view takes model objects and renders them into something for the end
653f4595 86user to look at. Normally this involves a template-generation tool that
64ccd8a8 87creates HTML for the user's web browser, but it could easily be code
653f4595 88that generates other forms such as PDF documents, e-mails, or Excel
89spreadsheets.
4d583dd8 90
91=item * Controller
92
64ccd8a8 93As suggested by its name, the controller takes user requests and routes
94them to the necessary model and view.
4d583dd8 95
96=back
97
98=item * ORM
99
653f4595 100The use of Object-Relational Mapping (ORM) technology for database
101access. Specifically, ORM provides an automated and standardized means
102to persist and restore objects to/from a relational database.
4d583dd8 103
104=back
105
936a5dd5 106You can checkout the source code for this example from the catalyst
107subversion repository as per the instructions in
108L<Catalyst::Manual::Tutorial::Intro>
4d583dd8 109
4d583dd8 110=head1 CREATE A CATALYST PROJECT
111
64ccd8a8 112Catalyst provides a number of helper scripts that can be used to quickly
653f4595 113flesh out the basic structure of your application. All Catalyst projects
8112f931 114begin with the C<catalyst.pl> helper (see L<Catalyst::Helper|Catalyst::Helper>
115for more information on helpers). Also note that as of Catalyst 5.7000,
116you will not have the helper scripts unless you install both
117L<Catalyst::Runtime|Catalyst::Runtime> and L<Catalyst::Devel|Catalyst::Devel>.
4d583dd8 118
64ccd8a8 119In the case of this tutorial, use the Catalyst C<catalyst.pl> script to
120initialize the framework for an application called C<MyApp>:
4d583dd8 121
122 $ catalyst.pl MyApp
208513f1 123 created "MyApp"
124 created "MyApp/script"
125 created "MyApp/lib"
126 created "MyApp/root"
127 ...
128 created "MyApp/script/myapp_create.pl"
4d583dd8 129 $ cd MyApp
130
64ccd8a8 131The C<catalyst.pl> helper script will display the names of the
132directories and files it creates.
4d583dd8 133
653f4595 134Though it's too early for any significant celebration, we already have a
135functioning application. Run the following command to run this
136application with the built-in development web server:
4d583dd8 137
208513f1 138 $ script/myapp_server.pl
139 [debug] Debug messages enabled
140 [debug] Loaded plugins:
141 .----------------------------------------------------------------------------.
b2dd9167 142 | Catalyst::Plugin::ConfigLoader 0.13 |
208513f1 143 | Catalyst::Plugin::Static::Simple 0.14 |
144 '----------------------------------------------------------------------------'
145
146 [debug] Loaded dispatcher "Catalyst::Dispatcher"
147 [debug] Loaded engine "Catalyst::Engine::HTTP"
b2dd9167 148 [debug] Found home "/home/me/MyApp"
149 [debug] Loaded Config "/home/me/myapp.yml"
208513f1 150 [debug] Loaded components:
151 .-----------------------------------------------------------------+----------.
152 | Class | Type |
153 +-----------------------------------------------------------------+----------+
154 | MyApp::Controller::Root | instance |
155 '-----------------------------------------------------------------+----------'
156
157 [debug] Loaded Private actions:
158 .----------------------+--------------------------------------+--------------.
159 | Private | Class | Method |
160 +----------------------+--------------------------------------+--------------+
161 | /default | MyApp::Controller::Root | default |
162 | /end | MyApp::Controller::Root | end |
163 '----------------------+--------------------------------------+--------------'
164
b2dd9167 165 [info] MyApp powered by Catalyst 5.7002
208513f1 166 You can connect to your server at http://localhost.localdomain:3000
167
f5ca9e89 168B<NOTE>: Be sure you run the C<script/myapp_server.pl> command from the
169'base' directory of your application, not inside the C<script> directory
170itself. It doesn't make a difference at this point, but it will as soon
171as we get the database going in the next section.
172
208513f1 173Point your web browser to L<http://localhost:3000> (substituting a
174different hostname or IP address as appropriate) and you should be
175greeted by the Catalyst welcome screen. Information similar to the
176following should be appended to the logging output of the development
177server:
178
7d310f12 179 [info] *** Request 1 (0.043/s) [6003] [Fri Jul 7 13:32:53 2006] ***
208513f1 180 [debug] "GET" request for "/" from "127.0.0.1"
7d310f12 181 [info] Request took 0.067675s (14.777/s)
208513f1 182 .----------------------------------------------------------------+-----------.
183 | Action | Time |
184 +----------------------------------------------------------------+-----------+
7d310f12 185 | /default | 0.002844s |
186 | /end | 0.000207s |
208513f1 187 '----------------------------------------------------------------+-----------'
188
189Press Ctrl-C to break out of the development server.
4d583dd8 190
4d583dd8 191
4d583dd8 192=head1 CREATE A SQLITE DATABASE
193
64ccd8a8 194In this step, we make a text file with the required SQL commands to
195create a database table and load some sample data. Open C<myapp01.sql>
196in your editor and enter:
4d583dd8 197
198 --
199 -- Create a very simple database to hold book and author information
200 --
201 CREATE TABLE books (
202 id INTEGER PRIMARY KEY,
203 title TEXT ,
204 rating INTEGER
205 );
206 -- 'book_authors' is a many-to-many join table between books & authors
207 CREATE TABLE book_authors (
208 book_id INTEGER,
209 author_id INTEGER,
210 PRIMARY KEY (book_id, author_id)
211 );
212 CREATE TABLE authors (
213 id INTEGER PRIMARY KEY,
214 first_name TEXT,
215 last_name TEXT
216 );
217 ---
218 --- Load some sample data
219 ---
220 INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
221 INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
222 INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
223 INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
224 INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
225 INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
226 INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
227 INSERT INTO authors VALUES (3, 'Christian', 'Degu');
228 INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
229 INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
230 INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
231 INSERT INTO authors VALUES (7, ' Nathan', 'Torkington');
232 INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
233 INSERT INTO book_authors VALUES (1, 1);
234 INSERT INTO book_authors VALUES (1, 2);
235 INSERT INTO book_authors VALUES (1, 3);
236 INSERT INTO book_authors VALUES (2, 4);
237 INSERT INTO book_authors VALUES (3, 5);
238 INSERT INTO book_authors VALUES (4, 6);
239 INSERT INTO book_authors VALUES (4, 7);
240 INSERT INTO book_authors VALUES (5, 8);
241
64ccd8a8 242B<TIP>: See Appendix 1 for tips on removing the leading spaces when
c608fae5 243cutting and pasting example code from POD-based documents.
4d583dd8 244
245Then use the following command to build a C<myapp.db> SQLite database:
246
247 $ sqlite3 myapp.db < myapp01.sql
248
64ccd8a8 249If you need to create the database more than once, you probably want to
250issue the C<rm myapp.db> command to delete the database before you use
251the C<sqlite3 myapp.db < myapp01.sql> command.
4d583dd8 252
64ccd8a8 253Once the C<myapp.db> database file has been created and initialized, you
254can use the SQLite command line environment to do a quick dump of the
255database contents:
4d583dd8 256
257 $ sqlite3 myapp.db
258 SQLite version 3.2.2
259 Enter ".help" for instructions
260 sqlite> select * from books;
261 1|CCSP SNRS Exam Certification Guide|5
262 2|TCP/IP Illustrated, Volume 1|5
263 3|Internetworking with TCP/IP Vol.1|4
264 4|Perl Cookbook|5
265 5|Designing with Web Standards|5
266 sqlite> .q
267 $
268
269Or:
270
271 $ sqlite3 myapp.db "select * from books"
272 1|CCSP SNRS Exam Certification Guide|5
273 2|TCP/IP Illustrated, Volume 1|5
274 3|Internetworking with TCP/IP Vol.1|4
275 4|Perl Cookbook|5
276 5|Designing with Web Standards|5
277
64ccd8a8 278As with most other SQL tools, if you are using the full "interactive"
279environment you need to terminate your SQL commands with a ";" (it's not
280required if you do a single SQL statement on the command line). Use
281".q" to exit from SQLite from the SQLite interactive mode and return to
282your OS command prompt.
4d583dd8 283
284
4d583dd8 285=head1 EDIT THE LIST OF CATALYST PLUGINS
286
64ccd8a8 287One of the greatest benefits of Catalyst is that it has such a large
288library of plugins available. Plugins are used to seamlessly integrate
289existing Perl modules into the overall Catalyst framework. In general,
290they do this by adding additional methods to the C<context> object
291(generally written as C<$c>) that Catalyst passes to every component
292throughout the framework.
4d583dd8 293
294By default, Catalyst enables three plugins/flags:
295
296=over 4
297
298=item *
299
300C<-Debug> Flag
301
64ccd8a8 302Enables the Catalyst debug output you saw when we started the
303C<script/myapp_server.pl> development server earlier. You can remove
304this plugin when you place your application into production.
4d583dd8 305
64ccd8a8 306As you may have noticed, C<-Debug> is not a plugin, but a I<flag>.
307Although most of the items specified on the C<use Catalyst> line of your
308application class will be plugins, Catalyst supports a limited number of
14e6feb0 309flag options (of these, C<-Debug> is the most common). See the
310documentation for C<Catalyst.pm> to get details on other flags
311(currently C<-Engine>, C<-Home>, and C<-Log>).
4d583dd8 312
64ccd8a8 313If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
314messages.
4d583dd8 315
316=item *
317
318L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
319
653f4595 320C<ConfigLoader> provides an automatic way to load configurable
64ccd8a8 321parameters for your application from a central YAML file (versus having
322the values hard-coded inside your Perl modules). If you have not been
323exposed to YAML before, it is a human-readable data serialization format
324that can be used to read (and write) values to/from text files. We will
325see how to use this feature of Catalyst during the authentication and
326authorization sections (Part 4 and Part 5).
4d583dd8 327
4d583dd8 328=item *
329
14e6feb0 330L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
4d583dd8 331
64ccd8a8 332C<Static::Simple> provides an easy method of serving static content such
333as images and CSS files under the development server.
4d583dd8 334
335=back
336
64ccd8a8 337To modify the list of plugins, edit C<lib/MyApp.pm> (this file is
338generally referred to as your I<application class>) and delete the line
339with:
4d583dd8 340
341 use Catalyst qw/-Debug ConfigLoader Static::Simple/;
342
343Replace it with:
344
345 use Catalyst qw/
346 -Debug
347 ConfigLoader
348 Static::Simple
349
4d583dd8 350 StackTrace
4d583dd8 351 /;
352
c608fae5 353This tells Catalyst to start using one new plugin:
4d583dd8 354
355=over 4
356
357=item *
358
4d583dd8 359L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>
360
64ccd8a8 361Adds a stack trace to the standard Catalyst "debug screen" (this is the
362screen Catalyst sends to your browser when an error occurs).
4d583dd8 363
c19d127e 364Note: L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your
365browser, not in the console window from which you're running your
366application, which is where logging output usually goes.
4d583dd8 367
4d583dd8 368=back
369
64ccd8a8 370Note that when specifying plugins on the C<use Catalyst> line, you can
71dedf57 371omit C<Catalyst::Plugin::> from the name. Additionally, you can spread
64ccd8a8 372the plugin names across multiple lines as shown here, or place them all
373on one (or more) lines as with the default configuration.
4d583dd8 374
c608fae5 375B<TIP:> You may see examples that include the
376L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
8e956464 377plugins. As of Catalyst 5.7000, C<DefaultEnd> has been
c608fae5 378deprecated in favor of
379L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
380(as the name of the package suggests, C<RenderView> is not
381a plugin, but an action). The purpose of both is essentially the same:
208513f1 382forward processing to the view to be rendered. Applications generated
8e956464 383under 5.7000 should automatically use C<RenderView> and "just work"
208513f1 384for most applications. For more information on C<RenderView> and
385the various options for forwarding to your view logic, please refer
386to the "Using RenderView for the Default View" section under
387"CATALYST VIEWS" below.
c608fae5 388
389
4d583dd8 390=head1 DATABASE ACCESS WITH C<DBIx::Class>
391
64ccd8a8 392Catalyst can be used with virtually any form of persistent datastore
14e6feb0 393available via Perl. For example,
394L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to
395easily access databases through the traditional Perl C<DBI> interface.
71dedf57 396However, most Catalyst applications use some form of ORM technology to
64ccd8a8 397automatically create and save model objects as they are used. Although
14e6feb0 398Tony Bowden's L<Class::DBI|Class::DBI> has been the traditional
399Perl ORM engine, Matt Trout's L<DBIx::Class|DBIx::Class> (abbreviated
400as "DBIC") has rapidly emerged as the Perl-based ORM technology of choice.
401Most new Catalyst applications rely on DBIC, as will this tutorial.
4d583dd8 402
094ea1a0 403Note: See L<Catalyst::Model::CDBI> for more information on using
14e6feb0 404Catalyst with L<Class::DBI|Class::DBI>.
4d583dd8 405
406=head2 Create a DBIC Schema File
407
64ccd8a8 408DBIx::Class uses a schema file to load other classes that represent the
409tables in your database (DBIC refers to these "table objects" as "result
71dedf57 410sources"; see L<DBIx::Class::ResultSource>). In this case, we want to
411load the model object for the C<books>, C<book_authors>, and C<authors>
412tables created in the previous step.
4d583dd8 413
414Open C<lib/MyAppDB.pm> in your editor and insert:
415
416 package MyAppDB;
417
418 =head1 NAME
419
71dedf57 420 MyAppDB - DBIC Schema Class
4d583dd8 421
422 =cut
423
424 # Our schema needs to inherit from 'DBIx::Class::Schema'
425 use base qw/DBIx::Class::Schema/;
426
427 # Need to load the DB Model classes here.
428 # You can use this syntax if you want:
429 # __PACKAGE__->load_classes(qw/Book BookAuthor Author/);
430 # Also, if you simply want to load all of the classes in a directory
431 # of the same name as your schema class (as we do here) you can use:
432 # __PACKAGE__->load_classes(qw//);
433 # But the variation below is more flexible in that it can be used to
434 # load from multiple namespaces.
435 __PACKAGE__->load_classes({
436 MyAppDB => [qw/Book BookAuthor Author/]
437 });
438
439 1;
440
64ccd8a8 441B<Note:> C<__PACKAGE__> is just a shorthand way of referencing the name
442of the package where it is used. Therefore, in C<MyAppDB.pm>,
14e6feb0 443C<__PACKAGE__> is equivalent to C<MyAppDB>.
4d583dd8 444
445
446=head2 Create the DBIC "Result Source" Files
447
64ccd8a8 448In this step, we create "table classes" (again, these are called a
71dedf57 449"result source" classes in DBIC) that act as model objects for the
64ccd8a8 450C<books>, C<book_authors>, and C<authors> tables in our database.
4d583dd8 451
452First, create a directory to hold the class:
453
454 $ mkdir lib/MyAppDB
455
456Then open C<lib/MyAppDB/Book.pm> in your editor and enter:
457
458 package MyAppDB::Book;
459
460 use base qw/DBIx::Class/;
461
462 # Load required DBIC stuff
463 __PACKAGE__->load_components(qw/PK::Auto Core/);
464 # Set the table name
465 __PACKAGE__->table('books');
466 # Set columns in table
467 __PACKAGE__->add_columns(qw/id title rating/);
468 # Set the primary key for the table
469 __PACKAGE__->set_primary_key(qw/id/);
470
471 #
472 # Set relationships:
473 #
474
475 # has_many():
476 # args:
477 # 1) Name of relationship, DBIC will create accessor with this name
478 # 2) Name of the model class referenced by this relationship
479 # 3) Column name in *foreign* table
480 __PACKAGE__->has_many(book_authors => 'MyAppDB::BookAuthor', 'book_id');
481
482 # many_to_many():
483 # args:
484 # 1) Name of relationship, DBIC will create accessor with this name
485 # 2) Name of has_many() relationship this many_to_many() is shortcut for
486 # 3) Name of belongs_to() relationship in model class of has_many() above
487 # You must already have the has_many() defined to use a many_to_many().
488 __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
489
490
491 =head1 NAME
492
493 MyAppDB::Book - A model object representing a book.
494
495 =head1 DESCRIPTION
496
497 This is an object that represents a row in the 'books' table of your application
498 database. It uses DBIx::Class (aka, DBIC) to do ORM.
499
500 For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
501 Offline utilities may wish to use this class directly.
502
503 =cut
504
505 1;
506
64ccd8a8 507This defines both a C<has_many> and a C<many_to_many> relationship. The
508C<many_to_many> relationship is optional, but it makes it easier to map
509a book to its collection of authors. Without it, we would have to
510"walk" though the C<book_authors> table as in
511C<$book-E<gt>book_authors-E<gt>first-E<gt>author-E<gt>last_name> (we
512will see examples on how to use DBIC objects in your code soon, but note
513that because C<$book-E<gt>book_authors> can return multiple authors, we
71dedf57 514have to use C<first> to display a single author). C<many_to_many> allows
515us to use the shorter C<$book-E<gt>authors-E<gt>first-E<gt>last_name>.
516Note that you cannot define a C<many_to_many> relationship without also
517having the C<has_many> relationship in place.
4d583dd8 518
519Next, open C<lib/MyAppDB/Author.pm> in your editor and enter:
520
521 package MyAppDB::Author;
522
523 use base qw/DBIx::Class/;
524
525 # Load required DBIC stuff
526 __PACKAGE__->load_components(qw/PK::Auto Core/);
527 # Set the table name
528 __PACKAGE__->table('authors');
529 # Set columns in table
530 __PACKAGE__->add_columns(qw/id first_name last_name/);
531 # Set the primary key for the table
532 __PACKAGE__->set_primary_key(qw/id/);
208513f1 533
4d583dd8 534 #
535 # Set relationships:
536 #
537
538 # has_many():
539 # args:
540 # 1) Name of relationship, DBIC will create accessor with this name
541 # 2) Name of the model class referenced by this relationship
542 # 3) Column name in *foreign* table
543 __PACKAGE__->has_many(book_author => 'MyAppDB::BookAuthor', 'author_id');
544
545 # many_to_many():
546 # args:
547 # 1) Name of relationship, DBIC will create accessor with this name
548 # 2) Name of has_many() relationship this many_to_many() is shortcut for
549 # 3) Name of belongs_to() relationship in model class of has_many() above
550 # You must already have the has_many() defined to use a many_to_many().
551 __PACKAGE__->many_to_many(books => 'book_author', 'book');
552
553
554 =head1 NAME
555
556 MyAppDB::Author - A model object representing an author of a book (if a book has
557 multiple authors, each will be represented be separate Author object).
558
559 =head1 DESCRIPTION
560
561 This is an object that represents a row in the 'authors' table of your application
562 database. It uses DBIx::Class (aka, DBIC) to do ORM.
563
564 For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
565 Offline utilities may wish to use this class directly.
566
567 =cut
568
569 1;
570
571Finally, open C<lib/MyAppDB/BookAuthor.pm> in your editor and enter:
572
573 package MyAppDB::BookAuthor;
574
575 use base qw/DBIx::Class/;
576
577 # Load required DBIC stuff
578 __PACKAGE__->load_components(qw/PK::Auto Core/);
579 # Set the table name
580 __PACKAGE__->table('book_authors');
581 # Set columns in table
582 __PACKAGE__->add_columns(qw/book_id author_id/);
583 # Set the primary key for the table
584 __PACKAGE__->set_primary_key(qw/book_id author_id/);
585
586 #
587 # Set relationships:
588 #
589
590 # belongs_to():
591 # args:
592 # 1) Name of relationship, DBIC will create accessor with this name
593 # 2) Name of the model class referenced by this relationship
594 # 3) Column name in *this* table
595 __PACKAGE__->belongs_to(book => 'MyAppDB::Book', 'book_id');
208513f1 596
4d583dd8 597 # belongs_to():
598 # args:
599 # 1) Name of relationship, DBIC will create accessor with this name
600 # 2) Name of the model class referenced by this relationship
601 # 3) Column name in *this* table
602 __PACKAGE__->belongs_to(author => 'MyAppDB::Author', 'author_id');
603
604
605 =head1 NAME
606
607 MyAppDB::BookAuthor - A model object representing the JOIN between an author and
608 a book.
609
610 =head1 DESCRIPTION
611
612 This is an object that represents a row in the 'book_authors' table of your
613 application database. It uses DBIx::Class (aka, DBIC) to do ORM.
208513f1 614
4d583dd8 615 You probably won't need to use this class directly -- it will be automatically
616 used by DBIC where joins are needed.
617
618 For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
619 Offline utilities may wish to use this class directly.
620
621 =cut
622
623 1;
624
64ccd8a8 625B<Note:> This sample application uses a plural form for the database
626tables (e.g., C<books> and C<authors>) and a singular form for the model
627objects (e.g., C<Book> and C<Author>); however, Catalyst places no
628restrictions on the naming conventions you wish to use.
4d583dd8 629
4d583dd8 630=head2 Use C<Catalyst::Model::DBIC::Schema> To Load The Model Class
631
14e6feb0 632When L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> is
64ccd8a8 633in use, Catalyst essentially reads an existing copy of your database
634model and creates a new set of objects under C<MyApp::Model> for use
635inside of Catalyst.
4d583dd8 636
14e6feb0 637B<Note:> With
638L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> you
639essentially end up with two sets of model classes (only one of which
640you write... the other set is created automatically in memory when
641your Catalyst application initializes). For this tutorial application,
642the important points to remember are: you write the I<result source>
643files in C<MyAppDB>, but I<within Catalyst> you use the I<automatically
644created model classes> in C<MyApp::Model>.
4d583dd8 645
14e6feb0 646Use the
647L<Catalyst::Helper::Model::DBIC::Schema|Catalyst::Helper::Model::DBIC::Schema>
648helper script to create the model class that loads up the model we
649created in the previous step:
4d583dd8 650
651 $ script/myapp_create.pl model MyAppDB DBIC::Schema MyAppDB dbi:SQLite:myapp.db '' '' '{ AutoCommit => 1 }'
208513f1 652 exists "/root/dev/MyApp/script/../lib/MyApp/Model"
653 exists "/root/dev/MyApp/script/../t"
654 created "/root/dev/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
655 created "/root/dev/MyApp/script/../t/model_MyAppDB.t"
656
4d583dd8 657
64ccd8a8 658Where the first C<MyAppDB> is the name of the class to be created by the
659helper in C<lib/MyApp/Model> and the second C<MyAppDB> is the name of
660existing schema file we created (in C<lib/MyAppDB.pm>). You can see
661that the helper creates a model file under C<lib/MyApp/Model> (Catalyst
662has a separate directory under C<lib/MyApp> for each of the three parts
663of MVC: C<Model>, C<View>, and C<Controller> [although older Catalyst
664applications often use the directories C<M>, C<V>, and C<C>]).
4d583dd8 665
666
4d583dd8 667=head1 CREATE A CATALYST CONTROLLER
668
71dedf57 669Controllers are where you write methods that interact with user
670input--typically, controller methods respond to C<GET> and C<POST>
671messages from the user's web browser.
4d583dd8 672
71dedf57 673Use the Catalyst C<create> script to add a controller for book-related
674actions:
4d583dd8 675
676 $ script/myapp_create.pl controller Books
208513f1 677 exists "/root/dev/MyApp/script/../lib/MyApp/Controller"
678 exists "/root/dev/MyApp/script/../t"
679 created "/root/dev/MyApp/script/../lib/MyApp/Controller/Books.pm"
680 created "/root/dev/MyApp/script/../t/controller_Books.t"
4d583dd8 681
64ccd8a8 682Then edit C<lib/MyApp/Controller/Books.pm> and add the following method
683to the controller:
4d583dd8 684
685 =head2 list
686
687 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
688
689 =cut
690
691 sub list : Local {
692 # Retrieve the usual perl OO '$self' for this object. $c is the Catalyst
693 # 'Context' that's used to 'glue together' the various components
694 # that make up the application
695 my ($self, $c) = @_;
696
697 # Retrieve all of the book records as book model objects and store in the
698 # stash where they can be accessed by the TT template
699 $c->stash->{books} = [$c->model('MyAppDB::Book')->all];
700
701 # Set the TT template to use. You will almost always want to do this
8112f931 702 # in your action methods (actions methods respond to user input in
703 # your controllers).
4d583dd8 704 $c->stash->{template} = 'books/list.tt2';
705 }
706
64ccd8a8 707B<Note:> Programmers experienced with object-oriented Perl should
708recognize C<$self> as a reference to the object where this method was
709called. On the other hand, C<$c> will be new to many Perl programmers
710who have not used Catalyst before (it's sometimes written as
711C<$context>). The Context object is automatically passed to all
712Catalyst components. It is used to pass information between components
713and provide access to Catalyst and plugin functionality.
4d583dd8 714
64ccd8a8 715B<TIP>: You may see the C<$c-E<gt>model('MyAppDB::Book')> used above
716written as C<$c-E<gt>model('MyAppDB')-E<gt>resultset('Book)>. The two
717are equivalent.
4d583dd8 718
64ccd8a8 719B<Note:> Catalyst actions are regular Perl methods, but they make use of
14e6feb0 720Nicholas Clark's C<attributes> module (that's the C<: Local> next to the
721C<sub list> in the code above) to provide additional information to the
722Catalyst dispatcher logic.
4d583dd8 723
208513f1 724
4d583dd8 725=head1 CATALYST VIEWS
726
71dedf57 727Views are where you render output, typically for display in the user's
14e6feb0 728web browser, but also possibly using other display output-generation
71dedf57 729systems. As with virtually every aspect of Catalyst, options abound
730when it comes to the specific view technology you adopt inside your
731application. However, most Catalyst applications use the Template
732Toolkit, known as TT (for more information on TT, see
208513f1 733L<http://www.template-toolkit.org>). Other popular view technologies
71dedf57 734include Mason (L<http://www.masonhq.com> and
14e6feb0 735L<http://www.masonbook.com>) and L<HTML::Template|HTML::Template>
64ccd8a8 736(L<http://html-template.sourceforge.net>).
4d583dd8 737
70493af7 738=head2 Create a Catalyst View Using C<TTSite>
4d583dd8 739
740When using TT for the Catalyst view, there are two main helper scripts:
741
742=over 4
743
744=item *
745
14e6feb0 746L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
4d583dd8 747
748=item *
749
14e6feb0 750L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
4d583dd8 751
752=back
753
64ccd8a8 754Both are similar, but C<TT> merely creates the C<lib/MyApp/View/TT.pm>
755file and leaves the creation of any hierarchical template organization
71dedf57 756entirely up to you. (It also creates a C<t/view_TT.t> file for testing;
757test cases will be discussed in Part 7). The C<TTSite> helper creates a
758modular and hierarchical view layout with separate Template Toolkit (TT)
759files for common header and footer information, configuration values, a
760CSS stylesheet, and more.
4d583dd8 761
64ccd8a8 762Enter the following command to enable the C<TTSite> style of view
71dedf57 763rendering for this tutorial:
4d583dd8 764
765 $ script/myapp_create.pl view TT TTSite
208513f1 766 exists "/root/dev/MyApp/script/../lib/MyApp/View"
767 exists "/root/dev/MyApp/script/../t"
768 created "/root/dev/MyApp/script/../lib/MyApp/View/TT.pm"
769 created "/root/dev/MyApp/script/../root/lib"
770 ...
771 created "/root/dev/MyApp/script/../root/src/ttsite.css"
4d583dd8 772
64ccd8a8 773This puts a number of files in the C<root/lib> and C<root/src>
774directories that can be used to customize the look and feel of your
775application. Also take a look at C<lib/MyApp/View/TT.pm> for config
776values set by the C<TTSite> helper.
777
778B<TIP>: Note that TTSite does one thing that could confuse people who
208513f1 779are used to the normal C<TT> Catalyst view: it redefines the Catalyst
71dedf57 780context object in templates from its usual C<c> to C<Catalyst>. When
781looking at other Catalyst examples, remember that they almost always use
782C<c>. Note that Catalyst and TT I<do not complain> when you use the
783wrong name to access the context object...TT simply outputs blanks for
5c1f2a06 784that bogus logic (see next tip to change this behavior with TT C<DEBUG>
785options). Finally, be aware that this change in name I<only>
71dedf57 786applies to how the context object is accessed inside your TT templates;
64ccd8a8 787your controllers will continue to use C<$c> (or whatever name you use
71dedf57 788when fetching the reference from C<@_> inside your methods). (You can
64ccd8a8 789change back to the "default" behavior be removing the C<CATALYST_VAR>
790line from C<lib/MyApp/View/TT.pm>, but you will also have to edit
791C<root/lib/config/main> and C<root/lib/config/url>. If you do this, be
792careful not to have a collision between your own C<c> variable and the
793Catalyst C<c> variable.)
4d583dd8 794
5c1f2a06 795B<TIP>: When troubleshooting TT it can be helpful to enable variable
796C<DEBUG> options. You can do this in a Catalyst environment by adding
797a C<DEBUG> line to the C<__PACKAGE__->config> declaration in
8112f931 798C<lib/MyApp/View/TT.pm>:
5c1f2a06 799
800 __PACKAGE__->config({
801 CATALYST_VAR => 'Catalyst',
802 ...
803 DEBUG => 'undef',
804 ...
805 });
208513f1 806
5c1f2a06 807There are a variety of options you can use, such as 'undef', 'all',
808'service', 'context', 'parser', 'provider', and 'service'. See
809L<Template::Constants> for more information (remove the C<DEBUG_>
810portion of the name shown in the TT docs and convert to lower case
811for use inside Catalyst).
812
70493af7 813B<NOTE:> Please be sure to disable TT debug options before
814continuing the tutorial (especially the 'undef' option -- leaving
815this enabled will conflict with several of the conventions used
816by this tutorial and TTSite to leave some variables undefined
817on purpose).
818
5c1f2a06 819
208513f1 820=head2 Using C<RenderView> for the Default View
821
822Once your controller logic has processed the request from a user, it
823forwards processing to your view in order to generate the appropriate
8e956464 824response output. Catalyst v5.7000 ships with a new mechanism,
208513f1 825L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>, that
826automatically performs this operation. If you look in
827C<lib/MyApp/Controller/Root.pm>, you should see the this empty
828definition for the C<sub end> method:
829
830 sub end : ActionClass('RenderView') {}
831
832The following bullet points provide a quick overview of the
833C<RenderView> process:
834
835=over 4
836
837=item *
838
839C<Root.pm> is designed to hold application-wide logic.
840
841=item *
842
843At the end of a given user request, Catalyst will call the most specific
844C<end> method that's appropriate. For example, if the controller for a
845request has an C<end> method defined, it will be called. However, if
846the controller does not define a controller-specific C<end> method, the
847"global" C<end> method in C<Root.pm> will be called.
c608fae5 848
208513f1 849=item *
850
851Because the definition includes an C<ActionClass> attribute, the
852L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
565d379b 853will be executed B<after> any code inside the definition of C<sub end>
208513f1 854is run. See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
855for more information on C<ActionClass>.
856
857=item *
858
859Because C<sub end> is empty, this effectively just runs the default
860logic in C<RenderView>. However, you can easily extend the
861C<RenderView> logic by adding your own code inside the empty method body
862(C<{}>) created by the Catalyst Helpers when we first ran the
863C<catalyst.pl> to initialize our application. See
864L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more
865detailed information on how to extended C<RenderView> in C<sub end>.
866
867=back
868
869
870=head3 The History Leading Up To C<RenderView>
871
872Although C<RenderView> strikes a nice balance between default
873behavior and easy extensibility, it is a new feature that won't
874appear in most existing Catalyst examples. This section provides
875some brief background on the evolution of default view rendering
876logic with an eye to how they can be migrated to C<RenderView>:
c608fae5 877
878=over 4
879
880=item *
881
882Private C<end> Action in Application Class
883
884Older Catalyst-related documents often suggest that you add a "private
885end action" to your application class (C<MyApp.pm>) or Root.pm
886(C<MyApp/Controller/Root.pm>). These examples should be easily
208513f1 887converted to L<RenderView|Catalyst::Action::RenderView> by simply adding
8112f931 888the attribute C<:ActionClass('RenderView')> to the C<sub end>
889definition. If end sub is defined in your application class
890(C<MyApp.pm>), you should also migrate it to
891C<MyApp/Controller/Root.pm>.
c608fae5 892
893=item *
894
895L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
896
208513f1 897C<DefaultEnd> represented the "next step" in passing processing from
898your controller to your view. It has the advantage of only requiring
899that C<DefaultEnd> be added to the list of plugins in C<lib/MyApp.pm>.
900It also allowed you to add "dump_info=1" (precede with "?" or "&"
901depending on where it is in the URL) to I<force> the debug screen at the
902end of the Catalyst request processing cycle. However, it was more
c9b77c06 903difficult to extend than the C<RenderView> mechanism, and is now
904deprecated.
c608fae5 905
906=item *
907
908L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
909
208513f1 910As discussed above, the current recommended approach to handling your
911view logic relies on
c608fae5 912L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>. Although
208513f1 913similar in first appearance to the "private end action" approach, it
914utilizes Catalyst's "ActionClass" mechanism to provide both automatic
915default behavior (you don't have to include a plugin as with
916C<DefaultEnd>) and easy extensibility. As with C<DefaultEnd>, it allows
917you to add "dump_info=1" (precede with "?" or "&" depending on where it
918is in the URL) to I<force> the debug screen at the end of the Catalyst
919request processing cycle.
c608fae5 920
921=back
922
208513f1 923It is recommended that all Catalyst applications use or migrate to
924the C<RenderView> approach.
c608fae5 925
926
4d583dd8 927=head2 Globally Customize Every View
928
64ccd8a8 929When using TTSite, files in the subdirectories of C<root/lib> can be
930used to make changes that will appear in every view. For example, to
931display optional status and error messages in every view, edit
71dedf57 932C<root/lib/site/layout>, updating it to match the following (the two HTML
64ccd8a8 933C<span> elements are new):
4d583dd8 934
935 <div id="header">[% PROCESS site/header %]</div>
936
937 <div id="content">
938 <span class="message">[% status_msg %]</span>
939 <span class="error">[% error_msg %]</span>
940 [% content %]
941 </div>
942
943 <div id="footer">[% PROCESS site/footer %]</div>
944
64ccd8a8 945If we set either message in the Catalyst stash (e.g.,
71dedf57 946C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it will
947be displayed whenever any view used by that request is rendered. The
948C<message> and C<error> CSS styles are automatically defined in
949C<root/src/ttsite.css> and can be customized to suit your needs.
4d583dd8 950
64ccd8a8 951B<Note:> The Catalyst stash only lasts for a single HTTP request. If
952you need to retain information across requests you can use
14e6feb0 953L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
954Catalyst sessions in the Authentication part of the tutorial).
4d583dd8 955
956
957=head2 Create a TT Template Page
958
64ccd8a8 959To add a new page of content to the TTSite view hierarchy, just create a
960new C<.tt2> file in C<root/src>. Only include HTML markup that goes
961inside the HTML <body> and </body> tags, TTSite will use the contents of
962C<root/lib/site> to add the top and bottom.
4d583dd8 963
964First create a directory for book-related TT templates:
965
966 $ mkdir root/src/books
967
968Then open C<root/src/books/list.tt2> in your editor and enter:
969
970 [% # This is a TT comment. The '-' at the end "chomps" the newline. You won't -%]
971 [% # see this "chomping" in your browser because HTML ignores blank lines, but -%]
972 [% # it WILL eliminate a blank line if you view the HTML source. It's purely -%]
973 [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
974
975 [% # Provide a title to root/lib/site/header -%]
976 [% META title = 'Book List' -%]
977
978 <table>
979 <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
980 [% # Display each book in a table row %]
981 [% FOREACH book IN books -%]
982 <tr>
983 <td>[% book.title %]</td>
984 <td>[% book.rating %]</td>
985 <td>
14e6feb0 986 [% # First initialize a TT variable to hold a list. Then use a TT FOREACH -%]
987 [% # loop in 'side effect notation' to load just the last names of the -%]
c9b77c06 988 [% # authors into the list. Note that the 'push' TT vmethod does not -%]
989 [% # a value, so nothing will be printed here. But, if you have something -%]
990 [% # in TT that does return a method and you don't want it printed, you -%]
991 [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to -%]
992 [% # call it and discard the return value. -%]
14e6feb0 993 [% tt_authors = [ ];
c9b77c06 994 tt_authors.push(author.last_name) FOREACH author = book.authors %]
14e6feb0 995 [% # Now use a TT 'virtual method' to display the author count in parens -%]
996 ([% tt_authors.size %])
c9b77c06 997 [% # Use another TT vmethod to join & print the names & comma separators -%]
14e6feb0 998 [% tt_authors.join(', ') %]
4d583dd8 999 </td>
1000 </tr>
1001 [% END -%]
1002 </table>
1003
64ccd8a8 1004As indicated by the inline comments above, the C<META title> line uses
1005TT's META feature to provide a title to C<root/lib/site/header>.
1006Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
1007object and prints the C<title> and C<rating> fields. An inner
14e6feb0 1008C<FOREACH> loop prints the last name of each author in a comma-separated
1009list within a single table cell.
64ccd8a8 1010
71dedf57 1011If you are new to TT, the C<[%> and C<%]> tags are used to delimit TT
1012code. TT supports a wide variety of directives for "calling" other
64ccd8a8 1013files, looping, conditional logic, etc. In general, TT simplifies the
1014usual range of Perl operators down to the single dot (C<.>) operator.
1015This applies to operations as diverse as method calls, hash lookups, and
1016list index values (see
1017L<http://www.template-toolkit.org/docs/default/Manual/Variables.html>
1018for details and examples). In addition to the usual C<Template> module
1019Pod documentation, you can access the TT manual at
1020L<http://www.template-toolkit.org/docs/default/>.
1021
1022B<NOTE>: The C<TTSite> helper creates several TT files using an
1023extension of C<.tt2>. Most other Catalyst and TT examples use an
1024extension of C<.tt>. You can use either extension (or no extension at
1025all) with TTSite and TT, just be sure to use the appropriate extension
1026for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} =
1027...> line in your controller. This document will use C<.tt2> for
1028consistency with the files already created by the C<TTSite> helper.
4d583dd8 1029
1030
4d583dd8 1031=head1 RUN THE APPLICATION
1032
64ccd8a8 1033First, let's enable an environment variable option that causes
1034DBIx::Class to dump the SQL statements it's using to access the database
1035(this option can provide extremely helpful troubleshooting information):
4d583dd8 1036
bc384c9d 1037 $ export DBIC_TRACE=1
1038
1039B<NOTE>: You can also use the older
1040C<export DBIX_CLASS_STORAGE_DBI_DEBUG=1>, that that's a lot more to
1041type.
4d583dd8 1042
cc548726 1043This assumes you are using BASH as your shell -- adjust accordingly if
1044you are using a different shell (for example, under tcsh, use
1045C<setenv DBIX_CLASS_STORAGE_DBI_DEBUG 1>).
1046
64ccd8a8 1047B<NOTE>: You can also set this in your code using
1048C<$class-E<gt>storage-E<gt>debug(1);>. See
71dedf57 1049L<DBIx::Class::Manual::Troubleshooting> for details (including options
1050to log to file instead of displaying to the Catalyst development server
1051log).
4d583dd8 1052
1053Then run the Catalyst "demo server" script:
1054
1055 $ script/myapp_server.pl
1056
208513f1 1057Your development server log output should display something like:
4d583dd8 1058
1059 $ script/myapp_server.pl
208513f1 1060 [debug] Debug messages enabled
1061 [debug] Loaded plugins:
1062 .----------------------------------------------------------------------------.
b2dd9167 1063 | Catalyst::Plugin::ConfigLoader 0.13 |
1064 | Catalyst::Plugin::StackTrace 0.06 |
208513f1 1065 | Catalyst::Plugin::Static::Simple 0.14 |
1066 '----------------------------------------------------------------------------'
4d583dd8 1067
208513f1 1068 [debug] Loaded dispatcher "Catalyst::Dispatcher"
1069 [debug] Loaded engine "Catalyst::Engine::HTTP"
1070 [debug] Found home "/home/me/MyApp"
b2dd9167 1071 [debug] Loaded Config "/home/me/myapp.yml"
208513f1 1072 [debug] Loaded components:
1073 .-----------------------------------------------------------------+----------.
1074 | Class | Type |
1075 +-----------------------------------------------------------------+----------+
1076 | MyApp::Controller::Books | instance |
1077 | MyApp::Controller::Root | instance |
1078 | MyApp::Model::MyAppDB | instance |
1079 | MyApp::Model::MyAppDB::Author | class |
1080 | MyApp::Model::MyAppDB::Book | class |
1081 | MyApp::Model::MyAppDB::BookAuthor | class |
1082 | MyApp::View::TT | instance |
1083 '-----------------------------------------------------------------+----------'
4d583dd8 1084
208513f1 1085 [debug] Loaded Private actions:
1086 .----------------------+--------------------------------------+--------------.
1087 | Private | Class | Method |
1088 +----------------------+--------------------------------------+--------------+
1089 | /default | MyApp::Controller::Root | default |
1090 | /end | MyApp::Controller::Root | end |
1091 | /books/index | MyApp::Controller::Books | index |
1092 | /books/list | MyApp::Controller::Books | list |
1093 '----------------------+--------------------------------------+--------------'
4d583dd8 1094
208513f1 1095 [debug] Loaded Path actions:
1096 .-------------------------------------+--------------------------------------.
1097 | Path | Private |
1098 +-------------------------------------+--------------------------------------+
1099 | /books/list | /books/list |
1100 '-------------------------------------+--------------------------------------'
4d583dd8 1101
b2dd9167 1102 [info] MyApp powered by Catalyst 5.7002
208513f1 1103 You can connect to your server at http://localhost.localdomain:3000
4d583dd8 1104
1105Some things you should note in the output above:
1106
1107=over 4
1108
1109=item *
1110
64ccd8a8 1111Catalyst::Model::DBIC::Schema took our C<MyAppDB::Book> and made it
1112C<MyApp::Model::MyAppDB::Book> (and similar actions were performed on
1113C<MyAppDB::Author> and C<MyAppDB::BookAuthor>).
4d583dd8 1114
1115=item *
1116
64ccd8a8 1117The "list" action in our Books controller showed up with a path of
1118C</books/list>.
4d583dd8 1119
1120=back
1121
64ccd8a8 1122Point your browser to L<http://localhost:3000> and you should still get
1123the Catalyst welcome page.
4d583dd8 1124
64ccd8a8 1125Next, to view the book list, change the URL in your browser to
1126L<http://localhost:3000/books/list>. You should get a list of the five
1127books loaded by the C<myapp01.sql> script above, with TTSite providing
1128the formatting for the very simple output we generated in our template.
1129The count and space-separated list of author last names appear on the
1130end of each row.
4d583dd8 1131
64ccd8a8 1132Also notice in the output of the C<script/myapp_server.pl> that DBIC
1133used the following SQL to retrieve the data:
4d583dd8 1134
1135 SELECT me.id, me.title, me.rating FROM books me
1136
64ccd8a8 1137Along with a list of the following commands to retrieve the authors for
1138each book (the lines have been "word wrapped" here to improve
1139legibility):
4d583dd8 1140
1141 SELECT author.id, author.first_name, author.last_name
1142 FROM book_authors me
1143 JOIN authors author ON ( author.id = me.author_id )
1144 WHERE ( me.book_id = ? ): `1'
1145
208513f1 1146You should see 5 such lines of debug output as DBIC fetches the author
1147information for each book.
4d583dd8 1148
1149
770fdaa9 1150=head1 USING THE DEFAULT TEMPLATE NAME
1151
1152By default, C<Catalyst::View::TT> will look for a template that uses the
1153same name as your controller action, allowing you to save the step of
1154manually specifying the template name in each action. For example, this
1155would allow us to remove (or comment out) the
1156C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our
1157C<list> action in the Books controller. Open
1158C<lib/MyApp/Controller/Books.pm> in your editor and update it to
1159match the following:
1160
1161 =head2 list
1162
1163 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
1164
1165 =cut
1166
1167 sub list : Local {
1168 # Retrieve the usual perl OO '$self' for this object. $c is the Catalyst
1169 # 'Context' that's used to 'glue together' the various components
1170 # that make up the application
1171 my ($self, $c) = @_;
1172
1173 # Retrieve all of the book records as book model objects and store in the
1174 # stash where they can be accessed by the TT template
1175 $c->stash->{books} = [$c->model('MyAppDB::Book')->all];
1176
1177 # Automatically look for a template of 'books/list.tt2' template
1178 # (if TEMPLATE_EXTENSION is set to '.tt2')
1179 }
1180
1181C<Catalyst::View::TT> defaults to looking for a template with no
1182extension. In our case, we need to override this to look for an
1183extension of C<.tt2>. Open C<lib/MyApp/View/TT.pm> and add the
1184C<TEMPLATE_EXTENSION> definition as follows:
1185
1186 __PACKAGE__->config({
1187 CATALYST_VAR => 'Catalyst',
1188 INCLUDE_PATH => [
1189 MyApp->path_to( 'root', 'src' ),
1190 MyApp->path_to( 'root', 'lib' )
1191 ],
1192 PRE_PROCESS => 'config/main',
1193 WRAPPER => 'site/wrapper',
1194 ERROR => 'error.tt2',
1195 TIMER => 0,
1196 TEMPLATE_EXTENSION => '.tt2',
1197 });
1198
1199You should now be able to restart the development server as per the
1200previous section and access the L<http://localhost:3000/books/list>
1201as before.
1202
1203Although this can be a valuable technique to establish a default
1204template for each of your actions, the remainder of the tutorial
1205will manually assign the template name to
1206C<$c-E<gt>stash-E<gt>{template}> in each action in order to make
1207the logic as conspicuous as possible.
1208
1209
4d583dd8 1210=head1 AUTHOR
1211
1212Kennedy Clark, C<hkclark@gmail.com>
1213
c608fae5 1214Please report any errors, issues or suggestions to the author. The
7d310f12 1215most recent version of the Catalyst Tutorial can be found at
c608fae5 1216L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Runtime/lib/Catalyst/Manual/Tutorial/>.
4d583dd8 1217
71dedf57 1218Copyright 2006, Kennedy Clark, under Creative Commons License
1219(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
4d583dd8 1220