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