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