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