lib/Catalyst/Log.pm
[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
6
7=head1 OVERVIEW
8
9This is B<Part 2 of 9> for the Catalyst tutorial.
10
64ccd8a8 11L<Tutorial Overview|Catalyst::Manual::Tutorial>
4d583dd8 12
13=over 4
14
15=item 1
16
17L<Introduction|Catalyst::Manual::Tutorial::Intro>
18
19=item 2
20
21B<Catalyst Basics>
22
23=item 3
24
64ccd8a8 25L<Basic CRUD|Catalyst::Manual::Tutorial_BasicCRUD>
4d583dd8 26
27=item 4
28
29L<Authentication|Catalyst::Manual::Tutorial::Authentication>
30
31=item 5
32
33L<Authorization|Catalyst::Manual::Tutorial::Authorization>
34
35=item 6
36
37L<Debugging|Catalyst::Manual::Tutorial::Debugging>
38
39=item 7
40
41L<Testing|Catalyst::Manual::Tutorial::Testing>
42
43=item 8
44
45L<AdvancedCRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
46
47=item 9
48
49L<Appendicies|Catalyst::Manual::Tutorial::Appendicies>
50
51=back
52
53
54
55=head1 DESCRIPTION
56
64ccd8a8 57In this part of the tutorial, we will create a very basic Catalyst web
58application. Though simple in many respects, this section will already
59demonstrate a number of powerful capabilities such as:
4d583dd8 60
61=over 4
62
63=item * Helper Scripts
64
64ccd8a8 65Catalyst helper scripts that can be used to rapidly bootstrap the
66skeletal structure of an application.
4d583dd8 67
68=item * MVC
69
64ccd8a8 70Model/View/Controller (MVC) provides an architecture that facilitates a
71clean "separation of control" between the different portions of your
72application. Given that many other documents cover this subject in
73detail, MVC will not be discussed in depth here (for an excellent
74introduction to MVC and general Catalyst concepts, please see
75L<Catalyst::Manual::About|Catalyst::Manual::About>. In short:
4d583dd8 76
77=over 4
78
79=item * Model
80
64ccd8a8 81In most applications, the model equates to the objects that are created
82from and saved to your SQL database.
4d583dd8 83
84=item * View
85
64ccd8a8 86The view takes model objects and renders them into something for the end
87user to look at. Normally this involves a template-generation tool that
88creates HTML for the user's web browser, but it could easily be code
89that generates other forms such as PDF documents or Excel spreadsheets.
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
64ccd8a8 100The use Object-Relational Mapping (ORM) technology for database access
101(specifically, ORM provides an automated means to persist and restore
102objects to/from a relational database).
4d583dd8 103
104=back
105
64ccd8a8 106B<TIP>: Note that all of the code for this part of the tutorial can be
107pulled from the Catalyst Subversion repository in one step with the
108following command:
4d583dd8 109
110 svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial@###
111 IMPORTANT: Does not work yet. Will be completed for final version.
112
113
114
115=head1 CREATE A CATALYST PROJECT
116
64ccd8a8 117Catalyst provides a number of helper scripts that can be used to quickly
118flesh out the basic structure of your application. All Catalyst
119projects begin with the C<catalyst.pl> helper.
4d583dd8 120
64ccd8a8 121In the case of this tutorial, use the Catalyst C<catalyst.pl> script to
122initialize the framework for an application called C<MyApp>:
4d583dd8 123
124 $ catalyst.pl MyApp
125 $ cd MyApp
126
64ccd8a8 127The C<catalyst.pl> helper script will display the names of the
128directories and files it creates.
4d583dd8 129
64ccd8a8 130Though it's obviously too early for any significant celebration, we
131already have a functioning application. Run the following command to
132run this application with the built-in development web server:
4d583dd8 133
134 $ script/myapp_server.pl
135
64ccd8a8 136Point your web browser to L<http://localhost:3000> (substituting a
137different hostname or IP address as appropriate) and you should be
138greeted by the Catalyst welcome screen. Press Ctrl-C to break out of
139the development server.
4d583dd8 140
141
142
143=head1 CREATE A SQLITE DATABASE
144
64ccd8a8 145In this step, we make a text file with the required SQL commands to
146create a database table and load some sample data. Open C<myapp01.sql>
147in your editor and enter:
4d583dd8 148
149 --
150 -- Create a very simple database to hold book and author information
151 --
152 CREATE TABLE books (
153 id INTEGER PRIMARY KEY,
154 title TEXT ,
155 rating INTEGER
156 );
157 -- 'book_authors' is a many-to-many join table between books & authors
158 CREATE TABLE book_authors (
159 book_id INTEGER,
160 author_id INTEGER,
161 PRIMARY KEY (book_id, author_id)
162 );
163 CREATE TABLE authors (
164 id INTEGER PRIMARY KEY,
165 first_name TEXT,
166 last_name TEXT
167 );
168 ---
169 --- Load some sample data
170 ---
171 INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
172 INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
173 INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
174 INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
175 INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
176 INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
177 INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
178 INSERT INTO authors VALUES (3, 'Christian', 'Degu');
179 INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
180 INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
181 INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
182 INSERT INTO authors VALUES (7, ' Nathan', 'Torkington');
183 INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
184 INSERT INTO book_authors VALUES (1, 1);
185 INSERT INTO book_authors VALUES (1, 2);
186 INSERT INTO book_authors VALUES (1, 3);
187 INSERT INTO book_authors VALUES (2, 4);
188 INSERT INTO book_authors VALUES (3, 5);
189 INSERT INTO book_authors VALUES (4, 6);
190 INSERT INTO book_authors VALUES (4, 7);
191 INSERT INTO book_authors VALUES (5, 8);
192
64ccd8a8 193B<TIP>: See Appendix 1 for tips on removing the leading spaces when
194cutting and pasting example code from Pod documents.
4d583dd8 195
196Then use the following command to build a C<myapp.db> SQLite database:
197
198 $ sqlite3 myapp.db < myapp01.sql
199
64ccd8a8 200If you need to create the database more than once, you probably want to
201issue the C<rm myapp.db> command to delete the database before you use
202the C<sqlite3 myapp.db < myapp01.sql> command.
4d583dd8 203
64ccd8a8 204Once the C<myapp.db> database file has been created and initialized, you
205can use the SQLite command line environment to do a quick dump of the
206database contents:
4d583dd8 207
208 $ sqlite3 myapp.db
209 SQLite version 3.2.2
210 Enter ".help" for instructions
211 sqlite> select * from books;
212 1|CCSP SNRS Exam Certification Guide|5
213 2|TCP/IP Illustrated, Volume 1|5
214 3|Internetworking with TCP/IP Vol.1|4
215 4|Perl Cookbook|5
216 5|Designing with Web Standards|5
217 sqlite> .q
218 $
219
220Or:
221
222 $ sqlite3 myapp.db "select * from books"
223 1|CCSP SNRS Exam Certification Guide|5
224 2|TCP/IP Illustrated, Volume 1|5
225 3|Internetworking with TCP/IP Vol.1|4
226 4|Perl Cookbook|5
227 5|Designing with Web Standards|5
228
64ccd8a8 229As with most other SQL tools, if you are using the full "interactive"
230environment you need to terminate your SQL commands with a ";" (it's not
231required if you do a single SQL statement on the command line). Use
232".q" to exit from SQLite from the SQLite interactive mode and return to
233your OS command prompt.
4d583dd8 234
235
236
237=head1 EDIT THE LIST OF CATALYST PLUGINS
238
64ccd8a8 239One of the greatest benefits of Catalyst is that it has such a large
240library of plugins available. Plugins are used to seamlessly integrate
241existing Perl modules into the overall Catalyst framework. In general,
242they do this by adding additional methods to the C<context> object
243(generally written as C<$c>) that Catalyst passes to every component
244throughout the framework.
4d583dd8 245
246By default, Catalyst enables three plugins/flags:
247
248=over 4
249
250=item *
251
252C<-Debug> Flag
253
64ccd8a8 254Enables the Catalyst debug output you saw when we started the
255C<script/myapp_server.pl> development server earlier. You can remove
256this plugin when you place your application into production.
4d583dd8 257
64ccd8a8 258As you may have noticed, C<-Debug> is not a plugin, but a I<flag>.
259Although most of the items specified on the C<use Catalyst> line of your
260application class will be plugins, Catalyst supports a limited number of
261flag options (of these, C<-Debug> is the most common).
4d583dd8 262
64ccd8a8 263If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
264messages.
4d583dd8 265
266=item *
267
268L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
269
64ccd8a8 270C<ConfigLoader> provides an automatic way to load your configurable
271parameters for your application from a central YAML file (versus having
272the values hard-coded inside your Perl modules). If you have not been
273exposed to YAML before, it is a human-readable data serialization format
274that can be used to read (and write) values to/from text files. We will
275see how to use this feature of Catalyst during the authentication and
276authorization sections (Part 4 and Part 5).
4d583dd8 277
278
279=item *
280
281L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
282
64ccd8a8 283C<Static::Simple> provides an easy method of serving static content such
284as images and CSS files under the development server.
4d583dd8 285
286=back
287
64ccd8a8 288To modify the list of plugins, edit C<lib/MyApp.pm> (this file is
289generally referred to as your I<application class>) and delete the line
290with:
4d583dd8 291
292 use Catalyst qw/-Debug ConfigLoader Static::Simple/;
293
294Replace it with:
295
296 use Catalyst qw/
297 -Debug
298 ConfigLoader
299 Static::Simple
300
301 Dumper
302 StackTrace
303 DefaultEnd
304 /;
305
306This tells Catalyst to start using three new plugins:
307
308=over 4
309
310=item *
311
312L<Catalyst::Plugin::Dumper|Catalyst::Plugin::Dumper>
313
64ccd8a8 314Allows you to easily use L<Data::Dumper|Data::Dumper> to dump variables
315to the logs, for example:
4d583dd8 316
317 $c->log->dumper($myvar);
318
64ccd8a8 319When running your application under the development server, the logs
320will be printed to your screen along with the other debug information
321generated by the C<-Debug> flag.
4d583dd8 322
323=item *
324
325L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>
326
64ccd8a8 327Adds a stack trace to the standard Catalyst "debug screen" (this is the
328screen Catalyst sends to your browser when an error occurs).
4d583dd8 329
64ccd8a8 330Note: L<Dumper|Catalyst::Plugin::Dumper> output appears on the
331console/telnet/SSH window where you issue the C<script/myapp_server.pl>
332command. L<StackTrace|Catalyst::Plugin::StackTrace> output appears in
333your browser.
4d583dd8 334
335=item *
336
337L<Catalyst::Plugin::DefaultEnd|Catalyst::Plugin::DefaultEnd>
338
64ccd8a8 339Automatically provides a Catalyst "end action" that invokes your view at
340the end of each request. Also allows you to add "dump_info=1" (precede
341with "?" or "&" depending on where it is in the URL) to I<force> the
342debug screen at the end of the Catalyst request processing cycle.
4d583dd8 343
64ccd8a8 344TIP: Many Catalyst-related documents predate
345L<DefaultEnd|Catalyst::Plugin::DefaultEnd> and suggest that you add an
346C<end> action to your application class (C<MyApp.pm>) or Root.pm
347(C<MyApp/Controller/Root.pm>). In most of these cases, you can convert
348to L<DefaultEnd|Catalyst::Plugin::DefaultEnd> by deleting the C<end>
349action and using the plugin instead.
4d583dd8 350
351=back
352
64ccd8a8 353Note that when specifying plugins on the C<use Catalyst> line, you can
354omit C<Catalyst::Plugin> from the name. Additionally, you can spread
355the plugin names across multiple lines as shown here, or place them all
356on one (or more) lines as with the default configuration.
4d583dd8 357
358
359
360=head1 DATABASE ACCESS WITH C<DBIx::Class>
361
64ccd8a8 362Catalyst can be used with virtually any form of persistent datastore
363available via Perl. For example,
364L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to easily
365access databases through the traditional Perl DBI interface. However,
366most Catalyst applications use some form of ORM technology to
367automatically create and save model objects as they are used. Although
368Tony Bowden's L<Class::DBI|Class::DBI> has been the traditional Perl ORM
369engine, Matt Trout's L<DBIx::Class|DBIx::Class> (abbreviated as "DBIC")
370has rapidly emerged as the Perl-based ORM technology of choice. Most
371new Catalyst applications rely on DBIC, as will this tutorial.
4d583dd8 372
64ccd8a8 373Note: See L<Catalyst::Model::CDBI| Catalyst:: Model::CDBI > for more
374information on using Catalyst with L<Class::DBI|Class::DBI>. Catalyst
375can also be used with "plain old DBI"; see L<Catalyst::Model::DBI|
376Catalyst::Model::DBI>.
4d583dd8 377
378
379=head2 Create a DBIC Schema File
380
64ccd8a8 381DBIx::Class uses a schema file to load other classes that represent the
382tables in your database (DBIC refers to these "table objects" as "result
383sources," see L<DBIx::Class::ResultSource|DBIx::Class::ResultSource>).
384In this case, we want to load the model object for the C<books>,
385C<book_authors>, and C<authors> tables created in the previous step.
4d583dd8 386
387Open C<lib/MyAppDB.pm> in your editor and insert:
388
389 package MyAppDB;
390
391 =head1 NAME
392
393 MyAppDB -- DBIC Schema Class
394
395 =cut
396
397 # Our schema needs to inherit from 'DBIx::Class::Schema'
398 use base qw/DBIx::Class::Schema/;
399
400 # Need to load the DB Model classes here.
401 # You can use this syntax if you want:
402 # __PACKAGE__->load_classes(qw/Book BookAuthor Author/);
403 # Also, if you simply want to load all of the classes in a directory
404 # of the same name as your schema class (as we do here) you can use:
405 # __PACKAGE__->load_classes(qw//);
406 # But the variation below is more flexible in that it can be used to
407 # load from multiple namespaces.
408 __PACKAGE__->load_classes({
409 MyAppDB => [qw/Book BookAuthor Author/]
410 });
411
412 1;
413
64ccd8a8 414B<Note:> C<__PACKAGE__> is just a shorthand way of referencing the name
415of the package where it is used. Therefore, in C<MyAppDB.pm>,
416C<__PACKAGE> is equivalent to C<MyAppDB>
4d583dd8 417
418
419=head2 Create the DBIC "Result Source" Files
420
64ccd8a8 421In this step, we create "table classes" (again, these are called a
422"result source" classes in DBIC) that acts as model objects for the
423C<books>, C<book_authors>, and C<authors> tables in our database.
4d583dd8 424
425First, create a directory to hold the class:
426
427 $ mkdir lib/MyAppDB
428
429Then open C<lib/MyAppDB/Book.pm> in your editor and enter:
430
431 package MyAppDB::Book;
432
433 use base qw/DBIx::Class/;
434
435 # Load required DBIC stuff
436 __PACKAGE__->load_components(qw/PK::Auto Core/);
437 # Set the table name
438 __PACKAGE__->table('books');
439 # Set columns in table
440 __PACKAGE__->add_columns(qw/id title rating/);
441 # Set the primary key for the table
442 __PACKAGE__->set_primary_key(qw/id/);
443
444 #
445 # Set relationships:
446 #
447
448 # has_many():
449 # args:
450 # 1) Name of relationship, DBIC will create accessor with this name
451 # 2) Name of the model class referenced by this relationship
452 # 3) Column name in *foreign* table
453 __PACKAGE__->has_many(book_authors => 'MyAppDB::BookAuthor', 'book_id');
454
455 # many_to_many():
456 # args:
457 # 1) Name of relationship, DBIC will create accessor with this name
458 # 2) Name of has_many() relationship this many_to_many() is shortcut for
459 # 3) Name of belongs_to() relationship in model class of has_many() above
460 # You must already have the has_many() defined to use a many_to_many().
461 __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
462
463
464 =head1 NAME
465
466 MyAppDB::Book - A model object representing a book.
467
468 =head1 DESCRIPTION
469
470 This is an object that represents a row in the 'books' table of your application
471 database. It uses DBIx::Class (aka, DBIC) to do ORM.
472
473 For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
474 Offline utilities may wish to use this class directly.
475
476 =cut
477
478 1;
479
64ccd8a8 480This defines both a C<has_many> and a C<many_to_many> relationship. The
481C<many_to_many> relationship is optional, but it makes it easier to map
482a book to its collection of authors. Without it, we would have to
483"walk" though the C<book_authors> table as in
484C<$book-E<gt>book_authors-E<gt>first-E<gt>author-E<gt>last_name> (we
485will see examples on how to use DBIC objects in your code soon, but note
486that because C<$book-E<gt>book_authors> can return multiple authors, we
487have to use C<first> to display a single author). C<many_to_many>
488allows us to use the shorter
489C<$book-E<gt>authors-E<gt>first-E<gt>last_name>. Note that you cannot
490define a C<many_to_many> relationship without also having the
491C<has_many> relationship in place.
4d583dd8 492
493Next, open C<lib/MyAppDB/Author.pm> in your editor and enter:
494
495 package MyAppDB::Author;
496
497 use base qw/DBIx::Class/;
498
499 # Load required DBIC stuff
500 __PACKAGE__->load_components(qw/PK::Auto Core/);
501 # Set the table name
502 __PACKAGE__->table('authors');
503 # Set columns in table
504 __PACKAGE__->add_columns(qw/id first_name last_name/);
505 # Set the primary key for the table
506 __PACKAGE__->set_primary_key(qw/id/);
507
508 #
509 # Set relationships:
510 #
511
512 # has_many():
513 # args:
514 # 1) Name of relationship, DBIC will create accessor with this name
515 # 2) Name of the model class referenced by this relationship
516 # 3) Column name in *foreign* table
517 __PACKAGE__->has_many(book_author => 'MyAppDB::BookAuthor', 'author_id');
518
519 # many_to_many():
520 # args:
521 # 1) Name of relationship, DBIC will create accessor with this name
522 # 2) Name of has_many() relationship this many_to_many() is shortcut for
523 # 3) Name of belongs_to() relationship in model class of has_many() above
524 # You must already have the has_many() defined to use a many_to_many().
525 __PACKAGE__->many_to_many(books => 'book_author', 'book');
526
527
528 =head1 NAME
529
530 MyAppDB::Author - A model object representing an author of a book (if a book has
531 multiple authors, each will be represented be separate Author object).
532
533 =head1 DESCRIPTION
534
535 This is an object that represents a row in the 'authors' table of your application
536 database. It uses DBIx::Class (aka, DBIC) to do ORM.
537
538 For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
539 Offline utilities may wish to use this class directly.
540
541 =cut
542
543 1;
544
545Finally, open C<lib/MyAppDB/BookAuthor.pm> in your editor and enter:
546
547 package MyAppDB::BookAuthor;
548
549 use base qw/DBIx::Class/;
550
551 # Load required DBIC stuff
552 __PACKAGE__->load_components(qw/PK::Auto Core/);
553 # Set the table name
554 __PACKAGE__->table('book_authors');
555 # Set columns in table
556 __PACKAGE__->add_columns(qw/book_id author_id/);
557 # Set the primary key for the table
558 __PACKAGE__->set_primary_key(qw/book_id author_id/);
559
560 #
561 # Set relationships:
562 #
563
564 # belongs_to():
565 # args:
566 # 1) Name of relationship, DBIC will create accessor with this name
567 # 2) Name of the model class referenced by this relationship
568 # 3) Column name in *this* table
569 __PACKAGE__->belongs_to(book => 'MyAppDB::Book', 'book_id');
570
571 # belongs_to():
572 # args:
573 # 1) Name of relationship, DBIC will create accessor with this name
574 # 2) Name of the model class referenced by this relationship
575 # 3) Column name in *this* table
576 __PACKAGE__->belongs_to(author => 'MyAppDB::Author', 'author_id');
577
578
579 =head1 NAME
580
581 MyAppDB::BookAuthor - A model object representing the JOIN between an author and
582 a book.
583
584 =head1 DESCRIPTION
585
586 This is an object that represents a row in the 'book_authors' table of your
587 application database. It uses DBIx::Class (aka, DBIC) to do ORM.
588
589 You probably won't need to use this class directly -- it will be automatically
590 used by DBIC where joins are needed.
591
592 For Catalyst, this is designed to be used through MyApp::Model::MyAppDB.
593 Offline utilities may wish to use this class directly.
594
595 =cut
596
597 1;
598
64ccd8a8 599B<Note:> This sample application uses a plural form for the database
600tables (e.g., C<books> and C<authors>) and a singular form for the model
601objects (e.g., C<Book> and C<Author>); however, Catalyst places no
602restrictions on the naming conventions you wish to use.
4d583dd8 603
604
605=head2 Use C<Catalyst::Model::DBIC::Schema> To Load The Model Class
606
64ccd8a8 607When L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> is
608in use, Catalyst essentially reads an existing copy of your database
609model and creates a new set of objects under C<MyApp::Model> for use
610inside of Catalyst.
4d583dd8 611
64ccd8a8 612B<Note:> With
613L<Catalyst::Model::DBIC::Schema|Catalyst::Model::DBIC::Schema> you
614essentially end up with two sets of model classes (only one of which you
615write... the other set is created automatically in memory when your
616Catalyst application initializes). For this tutorial application, the
617important points to remember are: you write the I<result source> files
618in C<MyAppDB>, but I<within Catalyst> you use the I<automatically
619created model classes> in C<MyApp::Model>.
4d583dd8 620
64ccd8a8 621Use the L<Catalyst::Helper::Model::DBIC::Schema|
622Catalyst::Helper::Model::DBIC::Schema > helper script to create the
623model class that loads up the model we created in the previous step:
4d583dd8 624
625 $ script/myapp_create.pl model MyAppDB DBIC::Schema MyAppDB dbi:SQLite:myapp.db '' '' '{ AutoCommit => 1 }'
626
64ccd8a8 627Where the first C<MyAppDB> is the name of the class to be created by the
628helper in C<lib/MyApp/Model> and the second C<MyAppDB> is the name of
629existing schema file we created (in C<lib/MyAppDB.pm>). You can see
630that the helper creates a model file under C<lib/MyApp/Model> (Catalyst
631has a separate directory under C<lib/MyApp> for each of the three parts
632of MVC: C<Model>, C<View>, and C<Controller> [although older Catalyst
633applications often use the directories C<M>, C<V>, and C<C>]).
4d583dd8 634
635
636
637=head1 CREATE A CATALYST CONTROLLER
638
639Controllers are where you write methods that respond to C<GET> and C<POST> messages from the user's web browser.
640
641Use the Catalyst C<create> script to add a controller for book-related actions:
642
643 $ script/myapp_create.pl controller Books
644
64ccd8a8 645Then edit C<lib/MyApp/Controller/Books.pm> and add the following method
646to the controller:
4d583dd8 647
648 =head2 list
649
650 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
651
652 =cut
653
654 sub list : Local {
655 # Retrieve the usual perl OO '$self' for this object. $c is the Catalyst
656 # 'Context' that's used to 'glue together' the various components
657 # that make up the application
658 my ($self, $c) = @_;
659
660 # Retrieve all of the book records as book model objects and store in the
661 # stash where they can be accessed by the TT template
662 $c->stash->{books} = [$c->model('MyAppDB::Book')->all];
663
664 # Set the TT template to use. You will almost always want to do this
665 # in your action methods.
666 $c->stash->{template} = 'books/list.tt2';
667 }
668
64ccd8a8 669B<Note:> Programmers experienced with object-oriented Perl should
670recognize C<$self> as a reference to the object where this method was
671called. On the other hand, C<$c> will be new to many Perl programmers
672who have not used Catalyst before (it's sometimes written as
673C<$context>). The Context object is automatically passed to all
674Catalyst components. It is used to pass information between components
675and provide access to Catalyst and plugin functionality.
4d583dd8 676
64ccd8a8 677B<TIP>: You may see the C<$c-E<gt>model('MyAppDB::Book')> used above
678written as C<$c-E<gt>model('MyAppDB')-E<gt>resultset('Book)>. The two
679are equivalent.
4d583dd8 680
64ccd8a8 681B<Note:> Catalyst actions are regular Perl methods, but they make use of
682Nicholas Clark's C<attributes> module to provide additional information
683to the Catalyst dispatcher logic.
4d583dd8 684
685
686=head1 CATALYST VIEWS
687
64ccd8a8 688Views are where you render output for display in the user's web browser
689(or possibly using other display technology). As with virtually every
690aspect of Catalyst, options abound when it comes to the specific view
691technology you adopt inside your application. However, most Catalyst
692applications use the Template Toolkit, known as TT (for more information
693on TT, see L<http://www.template-toolkit.org>). Other popular View
694technologies include Mason (L<http://www.masonhq.com> and
695L<http://www.masonbook.com>) and L<HTML::Template|HTML::Template>
696(L<http://html-template.sourceforge.net>).
4d583dd8 697
698
699=head2 Create a Catalyst View Using C<TTSITE>
700
701When using TT for the Catalyst view, there are two main helper scripts:
702
703=over 4
704
705=item *
706
707L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
708
709=item *
710
711L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
712
713=back
714
64ccd8a8 715Both are similar, but C<TT> merely creates the C<lib/MyApp/View/TT.pm>
716file and leaves the creation of any hierarchical template organization
717entirely up to you (it also creates a C<t/view_TT.t> file for testing;
718test cases will be discussed in Part 7). Conversely, the C<TTSite>
719helper creates a modular and hierarchical view layout with separate
720Template Toolkit (TT) files for common header and footer information,
721configuration values, a CSS stylesheet, etc.
4d583dd8 722
64ccd8a8 723Enter the following command to enable the C<TTSite> style of view
724rendering for the tutorial:
4d583dd8 725
726 $ script/myapp_create.pl view TT TTSite
727
64ccd8a8 728This puts a number of files in the C<root/lib> and C<root/src>
729directories that can be used to customize the look and feel of your
730application. Also take a look at C<lib/MyApp/View/TT.pm> for config
731values set by the C<TTSite> helper.
732
733B<TIP>: Note that TTSite does one thing that could confuse people who
734are used to the normal C<TT> Catalyst View: it redefines the Catalyst
735context object in templates from its usual C<c> to C<Catalyst>. Also
736keep this in mind when looking at other Catalyst examples (they almost
737always use C<c>). Note that Catalyst and TT I<do not complain> when you
738use the wrong name to access the context... it simply outputs blanks for
739that bogus logic. Finally, be aware that this change in name I<only>
740applies to how the context object is accessed inside your TT templates,
741your controllers will continue to use C<$c> (or whatever name you use
742when fetching the reference from C<@_> inside your methods). (You can
743change back to the "default" behavior be removing the C<CATALYST_VAR>
744line from C<lib/MyApp/View/TT.pm>, but you will also have to edit
745C<root/lib/config/main> and C<root/lib/config/url>. If you do this, be
746careful not to have a collision between your own C<c> variable and the
747Catalyst C<c> variable.)
4d583dd8 748
749
750
751=head2 Globally Customize Every View
752
64ccd8a8 753When using TTSite, files in the subdirectories of C<root/lib> can be
754used to make changes that will appear in every view. For example, to
755display optional status and error messages in every view, edit
756C<root/lib/site/layout> update it to match the following (the two HTML
757C<span> elements are new):
4d583dd8 758
759 <div id="header">[% PROCESS site/header %]</div>
760
761 <div id="content">
762 <span class="message">[% status_msg %]</span>
763 <span class="error">[% error_msg %]</span>
764 [% content %]
765 </div>
766
767 <div id="footer">[% PROCESS site/footer %]</div>
768
64ccd8a8 769If we set either message in the Catalyst stash (e.g.,
770C<$c-E<gt>stash-E<gt>{status_msg} = 'Hello world'>) it will be displayed
771whenever any view used by that request is rendered. The C<message> and
772C<error> CSS styles are automatically defined in C<root/src/ttsite.css>
773and can be customized to suit your needs.
4d583dd8 774
64ccd8a8 775B<Note:> The Catalyst stash only lasts for a single HTTP request. If
776you need to retain information across requests you can use
777L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
778Catalyst sessions in the Authentication part).
4d583dd8 779
780
781=head2 Create a TT Template Page
782
64ccd8a8 783To add a new page of content to the TTSite view hierarchy, just create a
784new C<.tt2> file in C<root/src>. Only include HTML markup that goes
785inside the HTML <body> and </body> tags, TTSite will use the contents of
786C<root/lib/site> to add the top and bottom.
4d583dd8 787
788First create a directory for book-related TT templates:
789
790 $ mkdir root/src/books
791
792Then open C<root/src/books/list.tt2> in your editor and enter:
793
794 [% # This is a TT comment. The '-' at the end "chomps" the newline. You won't -%]
795 [% # see this "chomping" in your browser because HTML ignores blank lines, but -%]
796 [% # it WILL eliminate a blank line if you view the HTML source. It's purely -%]
797 [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
798
799 [% # Provide a title to root/lib/site/header -%]
800 [% META title = 'Book List' -%]
801
802 <table>
803 <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
804 [% # Display each book in a table row %]
805 [% FOREACH book IN books -%]
806 <tr>
807 <td>[% book.title %]</td>
808 <td>[% book.rating %]</td>
809 <td>
810 [% # Print author count in parens. 'book.authors' uses the 'many_to_many' -%]
811 [% # relationship to retrieve all of the authors of a book. 'size' is a -%]
812 [% # TT VMethod to get the number of elements in a list. -%]
813 ([% book.authors.size %])
814 [% # Use an alternate form of a FOREACH loop to display authors. -%]
815 [% # _ below is the TT string concatenation operator. -%]
816 [% author.last_name _' ' FOREACH author = book.authors %]
817 [% # Note: if many_to_many relationship not used in Authors.pm, you could -%]
818 [% # have used the following to 'walk' through the 'join table objects' -%]
819 [% # bk_author.author.last_name _' ' FOREACH bk_author = book.book_authors %]
820 </td>
821 </tr>
822 [% END -%]
823 </table>
824
64ccd8a8 825As indicated by the inline comments above, the C<META title> line uses
826TT's META feature to provide a title to C<root/lib/site/header>.
827Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
828object and prints the C<title> and C<rating> fields. An inner
829C<FOREACH> loop prints the last name of each author in a single table
830cell (a simple space is used between the names; in reality you would
831probably want to modify the code to use a comma as a separator).
832
833If you are new to TT, the [% and %] tags are used to delimit "variable
834text". TT supports a wide variety of directives for "calling" other
835files, looping, conditional logic, etc. In general, TT simplifies the
836usual range of Perl operators down to the single dot (C<.>) operator.
837This applies to operations as diverse as method calls, hash lookups, and
838list index values (see
839L<http://www.template-toolkit.org/docs/default/Manual/Variables.html>
840for details and examples). In addition to the usual C<Template> module
841Pod documentation, you can access the TT manual at
842L<http://www.template-toolkit.org/docs/default/>.
843
844B<NOTE>: The C<TTSite> helper creates several TT files using an
845extension of C<.tt2>. Most other Catalyst and TT examples use an
846extension of C<.tt>. You can use either extension (or no extension at
847all) with TTSite and TT, just be sure to use the appropriate extension
848for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} =
849...> line in your controller. This document will use C<.tt2> for
850consistency with the files already created by the C<TTSite> helper.
4d583dd8 851
852
853
854=head1 RUN THE APPLICATION
855
64ccd8a8 856First, let's enable an environment variable option that causes
857DBIx::Class to dump the SQL statements it's using to access the database
858(this option can provide extremely helpful troubleshooting information):
4d583dd8 859
860 $ export DBIX_CLASS_STORAGE_DBI_DEBUG=1
861
64ccd8a8 862B<NOTE>: You can also set this in your code using
863C<$class-E<gt>storage-E<gt>debug(1);>. See
864L<DBIx::Class::Manual::Troubleshooting|DBIx::Class::Manual::Troubleshooting>
865for details (including options to log to file vs. the Catalyst
866development server log.
4d583dd8 867
868Then run the Catalyst "demo server" script:
869
870 $ script/myapp_server.pl
871
872You should get something like this:
873
874 $ script/myapp_server.pl
875 [Tue May 16 12:51:33 2006] [catalyst] [debug] Debug messages enabled
876 [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded plugins:
877 .------------------------------------------------------------------------------.
878 | Catalyst::Plugin::ConfigLoader 0.07 |
879 | Catalyst::Plugin::Static::Simple 0.14 |
880 | Catalyst::Plugin::Dumper 0.000002 |
881 | Catalyst::Plugin::StackTrace 0.04 |
882 | Catalyst::Plugin::DefaultEnd 0.06 |
883 '------------------------------------------------------------------------------'
884
885 [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
886 [Tue May 16 12:51:33 2006] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
887 [Tue May 16 12:51:33 2006] [catalyst] [debug] Found home "/home/me/MyApp"
888 [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded components:
889 .-------------------------------------------------------------------+----------.
890 | Class | Type |
891 +-------------------------------------------------------------------+----------+
892 | MyApp::Controller::Books | instance |
893 | MyApp::Controller::Root | instance |
894 | MyApp::Model::MyAppDB | instance |
895 | MyApp::Model::MyAppDB::Author | class |
896 | MyApp::Model::MyAppDB::Book | class |
897 | MyApp::Model::MyAppDB::BookAuthor | class |
898 | MyApp::View::TT | instance |
899 '-------------------------------------------------------------------+----------'
900
901 [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded Private actions:
902 .----------------------+----------------------------------------+--------------.
903 | Private | Class | Method |
904 +----------------------+----------------------------------------+--------------+
905 | /default | MyApp::Controller::Root | default |
906 | /end | MyApp | end |
907 | /books/list | MyApp::Controller::Books | list |
908 '----------------------+----------------------------------------+--------------'
909
910 [Tue May 16 12:51:37 2006] [catalyst] [debug] Loaded Path actions:
911 .--------------------------------------+---------------------------------------.
912 | Path | Private |
913 +--------------------------------------+---------------------------------------+
914 | /books/list | /books/list |
915 '--------------------------------------+---------------------------------------'
916
917 [Tue May 16 12:51:37 2006] [catalyst] [info] MyApp powered by Catalyst 5.6902
918 You can connect to your server at http://localhost:3000
919
920Some things you should note in the output above:
921
922=over 4
923
924=item *
925
64ccd8a8 926Catalyst::Model::DBIC::Schema took our C<MyAppDB::Book> and made it
927C<MyApp::Model::MyAppDB::Book> (and similar actions were performed on
928C<MyAppDB::Author> and C<MyAppDB::BookAuthor>).
4d583dd8 929
930=item *
931
64ccd8a8 932The "list" action in our Books controller showed up with a path of
933C</books/list>.
4d583dd8 934
935=back
936
937
64ccd8a8 938Point your browser to L<http://localhost:3000> and you should still get
939the Catalyst welcome page.
4d583dd8 940
64ccd8a8 941Next, to view the book list, change the URL in your browser to
942L<http://localhost:3000/books/list>. You should get a list of the five
943books loaded by the C<myapp01.sql> script above, with TTSite providing
944the formatting for the very simple output we generated in our template.
945The count and space-separated list of author last names appear on the
946end of each row.
4d583dd8 947
64ccd8a8 948Also notice in the output of the C<script/myapp_server.pl> that DBIC
949used the following SQL to retrieve the data:
4d583dd8 950
951 SELECT me.id, me.title, me.rating FROM books me
952
64ccd8a8 953Along with a list of the following commands to retrieve the authors for
954each book (the lines have been "word wrapped" here to improve
955legibility):
4d583dd8 956
957 SELECT author.id, author.first_name, author.last_name
958 FROM book_authors me
959 JOIN authors author ON ( author.id = me.author_id )
960 WHERE ( me.book_id = ? ): `1'
961
64ccd8a8 962You should see 10 such lines of debug output, two for each of the five
963author_id values (it pulls the data once for the count logic and another
964time to actually display the list).
4d583dd8 965
966
967=head1 AUTHOR
968
969Kennedy Clark, C<hkclark@gmail.com>
970
971Please report any errors, issues or suggestions to the author.
972
973Copyright 2006, Kennedy Clark, under Creative Commons License (L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
974
975Version: .94
976