Fix test skipping of http tests
[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
292eba91 110 svn checkout http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/Tutorial -r 4609 .
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
173 [info] *** Request 1 (0.008/s) [2822] [Mon Jul 3 12:42:43 2006] ***
174 [debug] "GET" request for "/" from "127.0.0.1"
175 [info] Request took 0.154781s (6.461/s)
176 .----------------------------------------------------------------+-----------.
177 | Action | Time |
178 +----------------------------------------------------------------+-----------+
586b6141 179 | /default | 0.069475s |
180 | /end | 0.085305s |
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
889difficult to extend the C<RenderView> mechanism, and is now deprecated.
c608fae5 890
891=item *
892
893L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>
894
208513f1 895As discussed above, the current recommended approach to handling your
896view logic relies on
c608fae5 897L<Catalyst::Action::RenderView|Catalyst::Action::RenderView>. Although
208513f1 898similar in first appearance to the "private end action" approach, it
899utilizes Catalyst's "ActionClass" mechanism to provide both automatic
900default behavior (you don't have to include a plugin as with
901C<DefaultEnd>) and easy extensibility. As with C<DefaultEnd>, it allows
902you to add "dump_info=1" (precede with "?" or "&" depending on where it
903is in the URL) to I<force> the debug screen at the end of the Catalyst
904request processing cycle.
c608fae5 905
906=back
907
208513f1 908It is recommended that all Catalyst applications use or migrate to
909the C<RenderView> approach.
c608fae5 910
911
4d583dd8 912=head2 Globally Customize Every View
913
64ccd8a8 914When using TTSite, files in the subdirectories of C<root/lib> can be
915used to make changes that will appear in every view. For example, to
916display optional status and error messages in every view, edit
71dedf57 917C<root/lib/site/layout>, updating it to match the following (the two HTML
64ccd8a8 918C<span> elements are new):
4d583dd8 919
920 <div id="header">[% PROCESS site/header %]</div>
921
922 <div id="content">
923 <span class="message">[% status_msg %]</span>
924 <span class="error">[% error_msg %]</span>
925 [% content %]
926 </div>
927
928 <div id="footer">[% PROCESS site/footer %]</div>
929
64ccd8a8 930If we set either message in the Catalyst stash (e.g.,
71dedf57 931C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it will
932be displayed whenever any view used by that request is rendered. The
933C<message> and C<error> CSS styles are automatically defined in
934C<root/src/ttsite.css> and can be customized to suit your needs.
4d583dd8 935
64ccd8a8 936B<Note:> The Catalyst stash only lasts for a single HTTP request. If
937you need to retain information across requests you can use
14e6feb0 938L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
939Catalyst sessions in the Authentication part of the tutorial).
4d583dd8 940
941
942=head2 Create a TT Template Page
943
64ccd8a8 944To add a new page of content to the TTSite view hierarchy, just create a
945new C<.tt2> file in C<root/src>. Only include HTML markup that goes
946inside the HTML <body> and </body> tags, TTSite will use the contents of
947C<root/lib/site> to add the top and bottom.
4d583dd8 948
949First create a directory for book-related TT templates:
950
951 $ mkdir root/src/books
952
953Then open C<root/src/books/list.tt2> in your editor and enter:
954
955 [% # This is a TT comment. The '-' at the end "chomps" the newline. You won't -%]
956 [% # see this "chomping" in your browser because HTML ignores blank lines, but -%]
957 [% # it WILL eliminate a blank line if you view the HTML source. It's purely -%]
958 [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
959
960 [% # Provide a title to root/lib/site/header -%]
961 [% META title = 'Book List' -%]
962
963 <table>
964 <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
965 [% # Display each book in a table row %]
966 [% FOREACH book IN books -%]
967 <tr>
968 <td>[% book.title %]</td>
969 <td>[% book.rating %]</td>
970 <td>
14e6feb0 971 [% # First initialize a TT variable to hold a list. Then use a TT FOREACH -%]
972 [% # loop in 'side effect notation' to load just the last names of the -%]
7e5eb02c 973 [% # authors into the list. Note that we make a bogus assignment to the -%]
974 [% # 'unused' vbl to avoid printing the size of the list after each push. -%]
14e6feb0 975 [% tt_authors = [ ];
7e5eb02c 976 unused = tt_authors.push(author.last_name) FOREACH author = book.authors %]
14e6feb0 977 [% # Now use a TT 'virtual method' to display the author count in parens -%]
978 ([% tt_authors.size %])
979 [% # Use another vmethod to join & print the names with comma separators -%]
980 [% tt_authors.join(', ') %]
4d583dd8 981 </td>
982 </tr>
983 [% END -%]
984 </table>
985
64ccd8a8 986As indicated by the inline comments above, the C<META title> line uses
987TT's META feature to provide a title to C<root/lib/site/header>.
988Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
989object and prints the C<title> and C<rating> fields. An inner
14e6feb0 990C<FOREACH> loop prints the last name of each author in a comma-separated
991list within a single table cell.
64ccd8a8 992
71dedf57 993If you are new to TT, the C<[%> and C<%]> tags are used to delimit TT
994code. TT supports a wide variety of directives for "calling" other
64ccd8a8 995files, looping, conditional logic, etc. In general, TT simplifies the
996usual range of Perl operators down to the single dot (C<.>) operator.
997This applies to operations as diverse as method calls, hash lookups, and
998list index values (see
999L<http://www.template-toolkit.org/docs/default/Manual/Variables.html>
1000for details and examples). In addition to the usual C<Template> module
1001Pod documentation, you can access the TT manual at
1002L<http://www.template-toolkit.org/docs/default/>.
1003
1004B<NOTE>: The C<TTSite> helper creates several TT files using an
1005extension of C<.tt2>. Most other Catalyst and TT examples use an
1006extension of C<.tt>. You can use either extension (or no extension at
1007all) with TTSite and TT, just be sure to use the appropriate extension
1008for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} =
1009...> line in your controller. This document will use C<.tt2> for
1010consistency with the files already created by the C<TTSite> helper.
4d583dd8 1011
1012
4d583dd8 1013=head1 RUN THE APPLICATION
1014
64ccd8a8 1015First, let's enable an environment variable option that causes
1016DBIx::Class to dump the SQL statements it's using to access the database
1017(this option can provide extremely helpful troubleshooting information):
4d583dd8 1018
1019 $ export DBIX_CLASS_STORAGE_DBI_DEBUG=1
1020
cc548726 1021This assumes you are using BASH as your shell -- adjust accordingly if
1022you are using a different shell (for example, under tcsh, use
1023C<setenv DBIX_CLASS_STORAGE_DBI_DEBUG 1>).
1024
64ccd8a8 1025B<NOTE>: You can also set this in your code using
1026C<$class-E<gt>storage-E<gt>debug(1);>. See
71dedf57 1027L<DBIx::Class::Manual::Troubleshooting> for details (including options
1028to log to file instead of displaying to the Catalyst development server
1029log).
4d583dd8 1030
1031Then run the Catalyst "demo server" script:
1032
1033 $ script/myapp_server.pl
1034
208513f1 1035Your development server log output should display something like:
4d583dd8 1036
1037 $ script/myapp_server.pl
208513f1 1038 [debug] Debug messages enabled
1039 [debug] Loaded plugins:
1040 .----------------------------------------------------------------------------.
1041 | Catalyst::Plugin::ConfigLoader 0.06 |
1042 | Catalyst::Plugin::StackTrace 0.04 |
1043 | Catalyst::Plugin::Static::Simple 0.14 |
1044 '----------------------------------------------------------------------------'
4d583dd8 1045
208513f1 1046 [debug] Loaded dispatcher "Catalyst::Dispatcher"
1047 [debug] Loaded engine "Catalyst::Engine::HTTP"
1048 [debug] Found home "/home/me/MyApp"
1049 [debug] Loaded components:
1050 .-----------------------------------------------------------------+----------.
1051 | Class | Type |
1052 +-----------------------------------------------------------------+----------+
1053 | MyApp::Controller::Books | instance |
1054 | MyApp::Controller::Root | instance |
1055 | MyApp::Model::MyAppDB | instance |
1056 | MyApp::Model::MyAppDB::Author | class |
1057 | MyApp::Model::MyAppDB::Book | class |
1058 | MyApp::Model::MyAppDB::BookAuthor | class |
1059 | MyApp::View::TT | instance |
1060 '-----------------------------------------------------------------+----------'
4d583dd8 1061
208513f1 1062 [debug] Loaded Private actions:
1063 .----------------------+--------------------------------------+--------------.
1064 | Private | Class | Method |
1065 +----------------------+--------------------------------------+--------------+
1066 | /default | MyApp::Controller::Root | default |
1067 | /end | MyApp::Controller::Root | end |
1068 | /books/index | MyApp::Controller::Books | index |
1069 | /books/list | MyApp::Controller::Books | list |
1070 '----------------------+--------------------------------------+--------------'
4d583dd8 1071
208513f1 1072 [debug] Loaded Path actions:
1073 .-------------------------------------+--------------------------------------.
1074 | Path | Private |
1075 +-------------------------------------+--------------------------------------+
1076 | /books/list | /books/list |
1077 '-------------------------------------+--------------------------------------'
4d583dd8 1078
8e956464 1079 [info] MyApp powered by Catalyst 5.7000
208513f1 1080 You can connect to your server at http://localhost.localdomain:3000
4d583dd8 1081
1082Some things you should note in the output above:
1083
1084=over 4
1085
1086=item *
1087
64ccd8a8 1088Catalyst::Model::DBIC::Schema took our C<MyAppDB::Book> and made it
1089C<MyApp::Model::MyAppDB::Book> (and similar actions were performed on
1090C<MyAppDB::Author> and C<MyAppDB::BookAuthor>).
4d583dd8 1091
1092=item *
1093
64ccd8a8 1094The "list" action in our Books controller showed up with a path of
1095C</books/list>.
4d583dd8 1096
1097=back
1098
64ccd8a8 1099Point your browser to L<http://localhost:3000> and you should still get
1100the Catalyst welcome page.
4d583dd8 1101
64ccd8a8 1102Next, to view the book list, change the URL in your browser to
1103L<http://localhost:3000/books/list>. You should get a list of the five
1104books loaded by the C<myapp01.sql> script above, with TTSite providing
1105the formatting for the very simple output we generated in our template.
1106The count and space-separated list of author last names appear on the
1107end of each row.
4d583dd8 1108
64ccd8a8 1109Also notice in the output of the C<script/myapp_server.pl> that DBIC
1110used the following SQL to retrieve the data:
4d583dd8 1111
1112 SELECT me.id, me.title, me.rating FROM books me
1113
64ccd8a8 1114Along with a list of the following commands to retrieve the authors for
1115each book (the lines have been "word wrapped" here to improve
1116legibility):
4d583dd8 1117
1118 SELECT author.id, author.first_name, author.last_name
1119 FROM book_authors me
1120 JOIN authors author ON ( author.id = me.author_id )
1121 WHERE ( me.book_id = ? ): `1'
1122
208513f1 1123You should see 5 such lines of debug output as DBIC fetches the author
1124information for each book.
4d583dd8 1125
1126
1127=head1 AUTHOR
1128
1129Kennedy Clark, C<hkclark@gmail.com>
1130
c608fae5 1131Please report any errors, issues or suggestions to the author. The
1132most recent version of the Catlayst Tutorial can be found at
1133L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Runtime/lib/Catalyst/Manual/Tutorial/>.
4d583dd8 1134
71dedf57 1135Copyright 2006, Kennedy Clark, under Creative Commons License
1136(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
4d583dd8 1137