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