Rework tutorial. Lots of things changed, but key items include: new content in Catal...
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / MoreCatalystBasics.pod
CommitLineData
3533daff 1=head1 NAME
2
3Catalyst::Manual::Tutorial::MoreCatalystBasics - Catalyst Tutorial - Part 3: More Catalyst Application Development Basics
4
5
6=head1 OVERVIEW
7
8This is B<Part 3 of 10> for the Catalyst tutorial.
9
10L<Tutorial Overview|Catalyst::Manual::Tutorial>
11
12=over 4
13
14=item 1
15
16L<Introduction|Catalyst::Manual::Tutorial::Intro>
17
18=item 2
19
20L<Catalyst Basics|Catalyst::Manual::Tutorial::CatalystBasics>
21
22=item 3
23
24B<More Catalyst Basics>
25
26=item 4
27
28L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>
29
30=item 5
31
32L<Authentication|Catalyst::Manual::Tutorial::Authentication>
33
34=item 6
35
36L<Authorization|Catalyst::Manual::Tutorial::Authorization>
37
38=item 7
39
40L<Debugging|Catalyst::Manual::Tutorial::Debugging>
41
42=item 8
43
44L<Testing|Catalyst::Manual::Tutorial::Testing>
45
46=item 9
47
48L<Advanced CRUD|Catalyst::Manual::Tutorial::AdvancedCRUD>
49
50=item 10
51
52L<Appendices|Catalyst::Manual::Tutorial::Appendices>
53
54=back
55
56
57=head1 DESCRIPTION
58
59This part of the tutorial builds on the work done in Part 2 to explore
60some features that are more typical of "real world" web applications.
61From this part of the tutorial onward, we will be building a simple
62book database application. Although the application will be too
63limited to be of use to anyone, it should provide a basic environment
64where we can explore a variety of features used in virtually all web
65applications.
66
67You can checkout the source code for this example from the catalyst
68subversion repository as per the instructions in
69L<Catalyst::Manual::Tutorial::Intro>
70
71
72=head1 CREATE A NEW APPLICATION
73
74The remainder of the tutorial will build an application call C<MyApp>.
75Use the Catalyst C<catalyst.pl> script to initialize the framework for
76an application called C<MyApp> (make sure you aren't still inside the
77directory of the C<Hello> application from the previous part of the
78tutorial):
79
80 $ catalyst.pl MyApp
81 created "MyApp"
82 created "MyApp/script"
83 created "MyApp/lib"
84 created "MyApp/root"
85 ...
86 created "MyApp/script/myapp_create.pl"
87 $ cd MyApp
88
89This creates a similar skeletal structure to what we saw in Part 2 of
90the tutorial, except with C<MyApp> or C<myapp> substituted for
91C<Hello> and C<hello>.
92
93
94=head1 EDIT THE LIST OF CATALYST PLUGINS
95
96One of the greatest benefits of Catalyst is that it has such a large
97library of plugins available. Plugins are used to seamlessly integrate
98existing Perl modules into the overall Catalyst framework. In general,
99they do this by adding additional methods to the C<context> object
100(generally written as C<$c>) that Catalyst passes to every component
101throughout the framework.
102
103By default, Catalyst enables three plugins/flags:
104
105=over 4
106
107=item *
108
109C<-Debug> Flag
110
111Enables the Catalyst debug output you saw when we started the
112C<script/myapp_server.pl> development server earlier. You can remove
113this plugin when you place your application into production.
114
115As you may have noticed, C<-Debug> is not a plugin, but a I<flag>.
116Although most of the items specified on the C<use Catalyst> line of your
117application class will be plugins, Catalyst supports a limited number of
118flag options (of these, C<-Debug> is the most common). See the
119documentation for C<Catalyst.pm> to get details on other flags
120(currently C<-Engine>, C<-Home>, and C<-Log>).
121
122If you prefer, you can use the C<$c-E<gt>debug> method to enable debug
123messages.
124
125B<TIP>: Depending on your needs, it can be helpful to permanently
126remove C<-Debug> from C<lib/MyApp.pm> and then use the C<-d> option
127to C<script/myapp_server.pl> to re-enable it just for the development
128server. We will not be using that approach in the tutorial, but feel
129free to make use of it in your own projects.
130
131=item *
132
133L<Catalyst::Plugin::ConfigLoader|Catalyst::Plugin::ConfigLoader>
134
135C<ConfigLoader> provides an automatic way to load configurable
136parameters for your application from a central YAML file (versus having
137the values hard-coded inside your Perl modules). If you have not been
138exposed to YAML before, it is a human-readable data serialization format
139that can be used to read (and write) values to/from text files. We will
140see how to use this feature of Catalyst during the authentication and
141authorization sections (Part 5 and Part 6).
142
143=item *
144
145L<Catalyst::Plugin::Static::Simple|Catalyst::Plugin::Static::Simple>
146
147C<Static::Simple> provides an easy method of serving static content such
148as images and CSS files under the development server.
149
150=back
151
152To modify the list of plugins, edit C<lib/MyApp.pm> (this file is
153generally referred to as your I<application class>) and delete the line
154with:
155
156 use Catalyst qw/-Debug ConfigLoader Static::Simple/;
157
158Replace it with:
159
160 use Catalyst qw/
161 -Debug
162 ConfigLoader
163 Static::Simple
164
165 StackTrace
166 /;
167
168This tells Catalyst to start using one new plugin:
169
170=over 4
171
172=item *
173
174L<Catalyst::Plugin::StackTrace|Catalyst::Plugin::StackTrace>
175
176Adds a stack trace to the standard Catalyst "debug screen" (this is the
177screen Catalyst sends to your browser when an error occurs).
178
179Note: L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your
180browser, not in the console window from which you're running your
181application, which is where logging output usually goes.
182
183=back
184
185Note that when specifying plugins on the C<use Catalyst> line, you can
186omit C<Catalyst::Plugin::> from the name. Additionally, you can spread
187the plugin names across multiple lines as shown here, or place them all
188on one (or more) lines as with the default configuration.
189
190
191=head1 CREATE A CATALYST CONTROLLER
192
193As discussed earlier, controllers are where you write methods that
194interact with user input. Typically, controller methods respond to
195C<GET> and C<POST> messages from the user's web browser.
196
197Use the Catalyst C<create> script to add a controller for book-related
198actions:
199
200 $ script/myapp_create.pl controller Books
201 exists "/home/me/MyApp/script/../lib/MyApp/Controller"
202 exists "/home/me/MyApp/script/../t"
203 created "/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm"
204 created "/home/me/MyApp/script/../t/controller_Books.t"
205
206Then edit C<lib/MyApp/Controller/Books.pm> and add the following method
207to the controller:
208
209 =head2 list
210
211 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
212
213 =cut
214
215 sub list : Local {
216 # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
217 # 'Context' that's used to 'glue together' the various components
218 # that make up the application
219 my ($self, $c) = @_;
220
221 # Retrieve all of the book records as book model objects and store in the
222 # stash where they can be accessed by the TT template
223 $c->stash->{books} = [$c->model('MyAppDB::Books')->all];
224
225 # Set the TT template to use. You will almost always want to do this
226 # in your action methods (action methods respond to user input in
227 # your controllers).
228 $c->stash->{template} = 'books/list.tt2';
229 }
230
231B<Note:> This won't actually work yet since you haven't set up your
232model yet.
233
234B<Note:> Programmers experienced with object-oriented Perl should
235recognize C<$self> as a reference to the object where this method was
236called. On the other hand, C<$c> will be new to many Perl programmers
237who have not used Catalyst before (it's sometimes written as
238C<$context>). The Context object is automatically passed to all
239Catalyst components. It is used to pass information between
240components and provide access to Catalyst and plugin functionality.
241
242B<TIP>: You may see the C<$c-E<gt>model('MyAppDB::Book')> used above
243written as C<$c-E<gt>model('MyAppDB')-E<gt>resultset('Book)>. The two
244are equivalent.
245
246B<Note:> Catalyst actions are regular Perl methods, but they make use
247of Nicholas Clark's C<attributes> module (that's the C<: Local> next
248to the C<sub list> in the code above) to provide additional
249information to the Catalyst dispatcher logic. Many newer Catalyst
250applications are switching to the use of "Literal" C<: Path> actions
251and C<Args> attribute in lieu of C<: Local> and C<: Private>. For
252example, C<sub any_method : Path Args(0)> can be used instead of
253C<sub index :Private> (because no path was supplied to C<Path> it
254matches the "empty" URL in the namespace of that module... the same
255thing C<sub index> would do) or C<sub list : Path('list') Args(0)>
256could be used instead of the C<sub list : Local> above (the C<list>
257argument to C<Path> would make it match on the URL C<list> under
258C<books>, the namespace of the current module). See "Action Types" in
259L<Catalyst::Manual::Intro|Catalyst::Manual::Intro> as well as Part 5
260of this tutorial (Authentication) for additional information. Another
261popular but more advanced feature is C<Chained> actions that allow a
262single URL to "chain together" multiple action method calls, each with
263an appropriate number of arguments (see
264L<Catalyst::DispatchType::Chained|Catalyst::DispatchType::Chained>
265for details).
266
267
268=head1 CATALYST VIEWS
269
270As mentioned in Part 2 of the tutorial, views are where you render
271output, typically for display in the user's web browser, but also
272possibly using other display output- generation systems. As with
273virtually every aspect of Catalyst, options abound when it comes to
274the specific view technology you adopt inside your application.
275However, most Catalyst applications use the Template Toolkit, known as
276TT (for more information on TT, see L<http://www.template-
277toolkit.org>). Other popular view technologies include Mason
278(L<http://www.masonhq.com> and L<http://www.masonbook.com>) and
279L<HTML::Template|HTML::Template> (L<http://html-
280template.sourceforge.net>).
281
282=head2 Create a Catalyst View Using C<TTSite>
283
284When using TT for the Catalyst view, there are two main helper scripts:
285
286=over 4
287
288=item *
289
290L<Catalyst::Helper::View::TT|Catalyst::Helper::View::TT>
291
292=item *
293
294L<Catalyst::Helper::View::TTSite|Catalyst::Helper::View::TTSite>
295
296=back
297
298Both are similar, but C<TT> merely creates the C<lib/MyApp/View/TT.pm>
299file and leaves the creation of any hierarchical template organization
300entirely up to you. (It also creates a C<t/view_TT.t> file for testing;
301test cases will be discussed in Part 8). The C<TTSite> helper creates a
302modular and hierarchical view layout with separate Template Toolkit (TT)
303files for common header and footer information, configuration values, a
304CSS stylesheet, and more.
305
306While TTSite is useful to bootstrap a project, we recommend that
307unless you know what you're doing or want to pretty much use the
308supplied templates as is, that you use the plain Template Toolkit view
309when starting a project from scratch. This is because TTSite can be
310tricky to customize. Additionally TT contains constructs that you
311need to learn yourself if you're going to be a serious user of TT.
312Our experience suggests that you're better off learning these from
313scratch. We use TTSite here precisely because it is useful for
314bootstrap/prototype purposes.
315
316Enter the following command to enable the C<TTSite> style of view
317rendering for this tutorial:
318
319 $ script/myapp_create.pl view TT TTSite
320 exists "/home/me/MyApp/script/../lib/MyApp/View"
321 exists "/home/me/MyApp/script/../t"
322 created "/home/me/MyApp/script/../lib/MyApp/View/TT.pm"
323 created "/home/me/MyApp/script/../root/lib"
324 ...
325 created "/home/me/MyApp/script/../root/src/ttsite.css"
326
327This puts a number of files in the C<root/lib> and C<root/src>
328directories that can be used to customize the look and feel of your
329application. Also take a look at C<lib/MyApp/View/TT.pm> for config
330values set by the C<TTSite> helper.
331
332B<TIP>: Note that TTSite does one thing that could confuse people who
333are used to the normal C<TT> Catalyst view: it redefines the Catalyst
334context object in templates from its usual C<c> to C<Catalyst>. When
335looking at other Catalyst examples, remember that they almost always use
336C<c>. Note that Catalyst and TT I<do not complain> when you use the
337wrong name to access the context object...TT simply outputs blanks for
338that bogus logic (see next tip to change this behavior with TT C<DEBUG>
339options). Finally, be aware that this change in name I<only>
340applies to how the context object is accessed inside your TT templates;
341your controllers will continue to use C<$c> (or whatever name you use
342when fetching the reference from C<@_> inside your methods). (You can
343change back to the "default" behavior be removing the C<CATALYST_VAR>
344line from C<lib/MyApp/View/TT.pm>, but you will also have to edit
345C<root/lib/config/main> and C<root/lib/config/url>. If you do this, be
346careful not to have a collision between your own C<c> variable and the
347Catalyst C<c> variable.)
348
349B<TIP>: When troubleshooting TT it can be helpful to enable variable
350C<DEBUG> options. You can do this in a Catalyst environment by adding
351a C<DEBUG> line to the C<__PACKAGE__->config> declaration in
352C<lib/MyApp/View/TT.pm>:
353
354 __PACKAGE__->config({
355 CATALYST_VAR => 'Catalyst',
356 ...
357 DEBUG => 'undef',
358 ...
359 });
360
361B<Note:> C<__PACKAGE__> is just a shorthand way of referencing the name
362of the package where it is used. Therefore, in C<TT.pm>,
363C<__PACKAGE__> is equivalent to C<TT>.
364
365There are a variety of options you can use, such as 'undef', 'all',
366'service', 'context', 'parser', 'provider', and 'service'. See
367L<Template::Constants> for more information (remove the C<DEBUG_>
368portion of the name shown in the TT docs and convert to lower case
369for use inside Catalyst).
370
371B<NOTE:> B<Please be sure to disable TT debug options before
372continuing the tutorial> (especially the 'undef' option -- leaving
373this enabled will conflict with several of the conventions used
374by this tutorial and TTSite to leave some variables undefined
375on purpose).
376
377
378=head2 Globally Customize Every View
379
380When using TTSite, files in the subdirectories of C<root/lib> can be
381used to make changes that will appear in every view. For example, to
382display optional status and error messages in every view, edit
383C<root/lib/site/layout>, updating it to match the following (the two HTML
384C<span> elements are new):
385
386 <div id="header">[% PROCESS site/header %]</div>
387
388 <div id="content">
389 <span class="message">[% status_msg %]</span>
390 <span class="error">[% error_msg %]</span>
391 [% content %]
392 </div>
393
394 <div id="footer">[% PROCESS site/footer %]</div>
395
396If we set either message in the Catalyst stash (e.g.,
397C<$c-E<gt>stash-E<gt>{status_msg} = 'Request was successful!'>) it will
398be displayed whenever any view used by that request is rendered. The
399C<message> and C<error> CSS styles are automatically defined in
400C<root/src/ttsite.css> and can be customized to suit your needs.
401
402B<Note:> The Catalyst stash only lasts for a single HTTP request. If
403you need to retain information across requests you can use
404L<Catalyst::Plugin::Session|Catalyst::Plugin::Session> (we will use
405Catalyst sessions in the Authentication part of the tutorial).
406
407
408=head2 Create a TT Template Page
409
410To add a new page of content to the TTSite view hierarchy, just create a
411new C<.tt2> file in C<root/src>. Only include HTML markup that goes
412inside the HTML <body> and </body> tags, TTSite will use the contents of
413C<root/lib/site> to add the top and bottom.
414
415First create a directory for book-related TT templates:
416
417 $ mkdir root/src/books
418
419Then create C<root/src/books/list.tt2> in your editor and enter:
420
421 [% # This is a TT comment. The '-' at the end "chomps" the newline. You won't -%]
422 [% # see this "chomping" in your browser because HTML ignores blank lines, but -%]
423 [% # it WILL eliminate a blank line if you view the HTML source. It's purely -%]
424 [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
425
426 [% # Provide a title to root/lib/site/header -%]
427 [% META title = 'Book List' -%]
428
429 <table>
430 <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
431 [% # Display each book in a table row %]
432 [% FOREACH book IN books -%]
433 <tr>
434 <td>[% book.title %]</td>
435 <td>[% book.rating %]</td>
436 </tr>
437 [% END -%]
438 </table>
439
440As indicated by the inline comments above, the C<META title> line uses
441TT's META feature to provide a title to C<root/lib/site/header>.
442Meanwhile, the outer C<FOREACH> loop iterates through each C<book> model
443object and prints the C<title> and C<rating> fields. An inner
444C<FOREACH> loop prints the last name of each author in a comma-separated
445list within a single table cell.
446
447If you are new to TT, the C<[%> and C<%]> tags are used to delimit TT
448code. TT supports a wide variety of directives for "calling" other
449files, looping, conditional logic, etc. In general, TT simplifies the
450usual range of Perl operators down to the single dot (C<.>) operator.
451This applies to operations as diverse as method calls, hash lookups, and
452list index values (see
453L<http://www.template-toolkit.org/docs/default/Manual/Variables.html>
454for details and examples). In addition to the usual C<Template> module
455Pod documentation, you can access the TT manual at
456L<http://www.template-toolkit.org/docs/default/>.
457
458B<NOTE>: The C<TTSite> helper creates several TT files using an
459extension of C<.tt2>. Most other Catalyst and TT examples use an
460extension of C<.tt>. You can use either extension (or no extension at
461all) with TTSite and TT, just be sure to use the appropriate extension
462for both the file itself I<and> the C<$c-E<gt>stash-E<gt>{template} =
463...> line in your controller. This document will use C<.tt2> for
464consistency with the files already created by the C<TTSite> helper.
465
466
467=head1 CREATE A SQLITE DATABASE
468
469In this step, we make a text file with the required SQL commands to
470create a database table and load some sample data. Open C<myapp01.sql>
471in your editor and enter:
472
473 --
474 -- Create a very simple database to hold book and author information
475 --
476 CREATE TABLE books (
477 id INTEGER PRIMARY KEY,
478 title TEXT ,
479 rating INTEGER
480 );
481 -- 'book_authors' is a many-to-many join table between books & authors
482 CREATE TABLE book_authors (
483 book_id INTEGER,
484 author_id INTEGER,
485 PRIMARY KEY (book_id, author_id)
486 );
487 CREATE TABLE authors (
488 id INTEGER PRIMARY KEY,
489 first_name TEXT,
490 last_name TEXT
491 );
492 ---
493 --- Load some sample data
494 ---
495 INSERT INTO books VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
496 INSERT INTO books VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
497 INSERT INTO books VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
498 INSERT INTO books VALUES (4, 'Perl Cookbook', 5);
499 INSERT INTO books VALUES (5, 'Designing with Web Standards', 5);
500 INSERT INTO authors VALUES (1, 'Greg', 'Bastien');
501 INSERT INTO authors VALUES (2, 'Sara', 'Nasseh');
502 INSERT INTO authors VALUES (3, 'Christian', 'Degu');
503 INSERT INTO authors VALUES (4, 'Richard', 'Stevens');
504 INSERT INTO authors VALUES (5, 'Douglas', 'Comer');
505 INSERT INTO authors VALUES (6, 'Tom', 'Christiansen');
506 INSERT INTO authors VALUES (7, 'Nathan', 'Torkington');
507 INSERT INTO authors VALUES (8, 'Jeffrey', 'Zeldman');
508 INSERT INTO book_authors VALUES (1, 1);
509 INSERT INTO book_authors VALUES (1, 2);
510 INSERT INTO book_authors VALUES (1, 3);
511 INSERT INTO book_authors VALUES (2, 4);
512 INSERT INTO book_authors VALUES (3, 5);
513 INSERT INTO book_authors VALUES (4, 6);
514 INSERT INTO book_authors VALUES (4, 7);
515 INSERT INTO book_authors VALUES (5, 8);
516
517B<TIP>: See Appendix 1 for tips on removing the leading spaces when
518cutting and pasting example code from POD-based documents.
519
520Then use the following command to build a C<myapp.db> SQLite database:
521
522 $ sqlite3 myapp.db < myapp01.sql
523
524If you need to create the database more than once, you probably want to
525issue the C<rm myapp.db> command to delete the database before you use
526the C<sqlite3 myapp.db < myapp01.sql> command.
527
528Once the C<myapp.db> database file has been created and initialized, you
529can use the SQLite command line environment to do a quick dump of the
530database contents:
531
532 $ sqlite3 myapp.db
533 SQLite version 3.4.2
534 Enter ".help" for instructions
535 sqlite> select * from books;
536 1|CCSP SNRS Exam Certification Guide|5
537 2|TCP/IP Illustrated, Volume 1|5
538 3|Internetworking with TCP/IP Vol.1|4
539 4|Perl Cookbook|5
540 5|Designing with Web Standards|5
541 sqlite> .q
542 $
543
544Or:
545
546 $ sqlite3 myapp.db "select * from books"
547 1|CCSP SNRS Exam Certification Guide|5
548 2|TCP/IP Illustrated, Volume 1|5
549 3|Internetworking with TCP/IP Vol.1|4
550 4|Perl Cookbook|5
551 5|Designing with Web Standards|5
552
553As with most other SQL tools, if you are using the full "interactive"
554environment you need to terminate your SQL commands with a ";" (it's not
555required if you do a single SQL statement on the command line). Use
556".q" to exit from SQLite from the SQLite interactive mode and return to
557your OS command prompt.
558
559
560=head1 DATABASE ACCESS WITH C<DBIx::Class>
561
562Catalyst can be used with virtually any form of persistent datastore
563available via Perl. For example,
564L<Catalyst::Model::DBI|Catalyst::Model::DBI> can be used to
565easily access databases through the traditional Perl C<DBI> interface.
566However, most Catalyst applications use some form of ORM technology to
567automatically create and save model objects as they are used. Although
568Tony Bowden's L<Class::DBI|Class::DBI> has been a popular choice
569in the past, Matt Trout's L<DBIx::Class|DBIx::Class> (abbreviated
570as "DBIC") has rapidly emerged as the Perl-based ORM technology of choice.
571Most new Catalyst applications rely on DBIC, as will this tutorial.
572
573=head2 Create a Dynamic DBIC Model
574
575Use the C<create=dynamic> model helper option to build a model that
576dynamically reads your database structure every time the application
577starts:
578
579 $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=dynamic dbi:SQLite:myapp.db
580 exists "/home/me/MyApp/script/../lib/MyApp/Model"
581 exists "/home/me/MyApp/script/../t"
582 created "/home/me/MyApp/script/../lib/MyApp/Schema"
583 created "/home/me/MyApp/script/../lib/MyApp/Schema/MyAppDB.pm"
584 created "/home/me/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
585 created "/home/me/MyApp/script/../t/model_MyAppDB.t"
586
587
588C<MyAppDB> is the name of the model class to be created by the helper in
589C<lib/MyApp/Model> (Catalyst has a separate directory under C<lib/MyApp>
590for each of the three parts of MVC: C<Model>, C<View>, and C<Controller>
591[although older Catalyst applications often use the directories C<M>,
592C<V>, and C<C>]). C<DBIC::Schema> is the type of the model to create.
593C<MyApp::Schema::MyAppDB> is the name of the DBIC schema file written to
594C<lib/MyApp/Schema/MyAppDB.pm>. Because we specified C<create=dynamic>
595to the helper, it use L<DBIx::Class::Schema::Loader> to dynamically load
596the schema information from the database every time the application
597starts. And finally, C<dbi:SQLite:myapp.db> is the standard DBI connect
598string for use with SQLite.
599
600B<NOTE>: Although the C<create=dynamic> option to the DBIC helper
601makes for a nifty demonstration, is not suitable for real world
602applications. Moreover, it may not be supported in future versions of
603DBIC. After this demonstration, please use the C<create=static>
604option that we switch to below.
605
606
607=head1 RUN THE APPLICATION
608
609First, let's enable an environment variable option that causes
610DBIx::Class to dump the SQL statements it's using to access the database
611(this option can provide extremely helpful troubleshooting information):
612
613 $ export DBIC_TRACE=1
614
615This assumes you are using BASH as your shell -- adjust accordingly if
616you are using a different shell (for example, under tcsh, use
617C<setenv DBIC_TRACE 1>).
618
619B<NOTE>: You can also set this in your code using
620C<$class-E<gt>storage-E<gt>debug(1);>. See
621L<DBIx::Class::Manual::Troubleshooting> for details (including options
622to log to file instead of displaying to the Catalyst development server
623log).
624
625Then run the Catalyst "demo server" script:
626
627 $ script/myapp_server.pl
628
629Your development server log output should display something like:
630
631 $script/myapp_server.pl
632 [debug] Debug messages enabled
633 [debug] Loaded plugins:
634 .----------------------------------------------------------------------------.
635 | Catalyst::Plugin::ConfigLoader 0.17 |
636 | Catalyst::Plugin::StackTrace 0.06 |
637 | Catalyst::Plugin::Static::Simple 0.20 |
638 '----------------------------------------------------------------------------'
639
640 [debug] Loaded dispatcher "Catalyst::Dispatcher"
641 [debug] Loaded engine "Catalyst::Engine::HTTP"
642 [debug] Found home "/home/me/MyApp"
643 [debug] Loaded Config "/home/me/MyApp/myapp.yml"
644 [debug] Loaded components:
645 .-----------------------------------------------------------------+----------.
646 | Class | Type |
647 +-----------------------------------------------------------------+----------+
648 | MyApp::Controller::Books | instance |
649 | MyApp::Controller::Root | instance |
650 | MyApp::Model::MyAppDB | instance |
651 | MyApp::Model::MyAppDB::Authors | class |
652 | MyApp::Model::MyAppDB::BookAuthors | class |
653 | MyApp::Model::MyAppDB::Books | class |
654 | MyApp::View::TT | instance |
655 '-----------------------------------------------------------------+----------'
656
657 [debug] Loaded Private actions:
658 .----------------------+--------------------------------------+--------------.
659 | Private | Class | Method |
660 +----------------------+--------------------------------------+--------------+
661 | /default | MyApp::Controller::Root | default |
662 | /end | MyApp::Controller::Root | end |
663 | /books/index | MyApp::Controller::Books | index |
664 | /books/list | MyApp::Controller::Books | list |
665 '----------------------+--------------------------------------+--------------'
666
667 [debug] Loaded Path actions:
668 .-------------------------------------+--------------------------------------.
669 | Path | Private |
670 +-------------------------------------+--------------------------------------+
671 | /books/list | /books/list |
672 '-------------------------------------+--------------------------------------'
673
674 [info] MyApp powered by Catalyst 5.7011
675 You can connect to your server at http://localhost:3000
676
677B<NOTE>: Be sure you run the C<script/myapp_server.pl> command from
678the 'base' directory of your application, not inside the C<script>
679directory itself or it will not be able to locate the C<myapp.db>
680database file. You can use a fully qualified or a relative path to
681locate the database file, but we did not specify that when we ran the
682model helper earlier.
683
684Some things you should note in the output above:
685
686=over 4
687
688=item *
689
690Catalyst::Model::DBIC::Schema dynamically created three model classes,
691one to represent each of the three tables in our database
692(C<MyApp::Model::MyAppDB::Authors>, C<MyApp::Model::MyAppDB::BookAuthors>,
693and C<MyApp::Model::MyAppDB::Books>).
694
695=item *
696
697The "list" action in our Books controller showed up with a path of
698C</books/list>.
699
700=back
701
702Point your browser to L<http://localhost:3000> and you should still get
703the Catalyst welcome page.
704
705Next, to view the book list, change the URL in your browser to
706L<http://localhost:3000/books/list>. You should get a list of the five
707books loaded by the C<myapp01.sql> script above, with TTSite providing
708the formatting for the very simple output we generated in our template.
709The rating for each book should appear on each row.
710
711Also notice in the output of the C<script/myapp_server.pl> that DBIC
712used the following SQL to retrieve the data:
713
714 SELECT me.id, me.title, me.rating FROM books me
715
716because we enabled DBIC_TRACE.
717
718You now the beginnings of a simple but workable web application.
719Continue on to future sections and we will develop the application
720more fully.
721
722
723=head1 A STATIC DATABASE MODEL WITH C<DBIx::Class>
724
725=head2 Create Static DBIC Schema Files
726
727Unlike the previous section where we had DBIC automatically discover the
728structure of the database every time the application started, here we
729will use static schema files for more control. This is typical of most
730"real world" applications.
731
732One option would be to create a separate schema file for each table in
733the database, however, lets use the same L<DBIx::Class::Schema::Loader>
734used earlier with C<create=dynamic> to build the static files for us.
735First, lets remove the schema file created in Part 2:
736
737 $ rm lib/MyApp/Schema/MyAppDB.pm
738
739Now regenerate the schema using the C<create=static> option:
740
741 $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=static dbi:SQLite:myapp.db
742 exists "/home/me/MyApp/script/../lib/MyApp/Model"
743 exists "/home/me/MyApp/script/../t"
744 Dumping manual schema for MyApp::Schema::MyAppDB to directory /home/me/MyApp/script/../lib ...
745 Schema dump completed.
746 exists "/home/me/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
747
748We could have also deleted C<lib/MyApp/Model/MyAppDB.pm>, but it would
749have regenerated the same file (note the C<exists> in the output above).
750If you take a look at C<lib/MyApp/Model/MyAppDB.pm>, it simply contains
751a reference to the actual schema file in C<lib/MyApp/Schema/MyAppDB.pm>
752along with the database connect string.
753
754If you look in the C<lib/MyApp/Schema> directory, you will find that
755C<MyAppDB.pm> is no longer using L<DBIx::Class::Schema::Loader> as its
756base class (L<DBIx::Class::Schema::Loader> is only being used by the
757helper to load the schema once and then create the static files for us)
758and that it only contains a call to the C<load_classes> method. You
759will also find that C<lib/MyApp/Schema> contains a C<MyAppDB>
760subdirectory, with one file inside this directory for each of the tables
761in our simple database (C<Authors.pm>, C<BookAuthors.pm>, and
762C<Books.pm>). These three files were created based on the information
763found by L<DBIx::Class::Schema::Loader> as the helper ran.
764
765The idea with all of the files created under C<lib/MyApp/Schema> by the
766C<create=static> option is to only edit the files below the C<# DO NOT
767MODIFY THIS OR ANYTHING ABOVE!> warning. If you place all of your
768changes below that point in the file, you can regenerate the
769auto-generated information at the top of each file should your database
770structure get updated.
771
772Also note the "flow" of the model information across the various files
773and directories. Catalyst will initially load the model from
774C<lib/MyApp/Model/MyAppDB.pm>. This file contains a reference to
775C<lib/MyApp/Schema/MyAppDB.pm>, so that file is loaded next. Finally,
776the call to C<load_classes> in that file will load each of the
777table-specific "results source" files from the C<lib/MyApp/Schema/MyAppDB>
778subdirectory. These three table-specific DBIC schema files will then be
779used to create three table-specific Catalyst models every time the
780application starts (you can see these three model files listed in
781the debug output generated when you launch the application).
782
783
784=head2 Updating the Generated DBIC Schema Files
785
786
787Let's manually add some relationship information to the auto-generated
788schema files. First edit C<lib/MyApp/Schema/MyAppDB/Books.pm> and
789add the following text below the C<# You can replace this text...>
790comment:
791
792 #
793 # Set relationships:
794 #
795
796 # has_many():
797 # args:
798 # 1) Name of relationship, DBIC will create accessor with this name
799 # 2) Name of the model class referenced by this relationship
800 # 3) Column name in *foreign* table
801 __PACKAGE__->has_many(book_authors => 'MyApp::Schema::MyAppDB::BookAuthors', 'book_id');
802
803 # many_to_many():
804 # args:
805 # 1) Name of relationship, DBIC will create accessor with this name
806 # 2) Name of has_many() relationship this many_to_many() is shortcut for
807 # 3) Name of belongs_to() relationship in model class of has_many() above
808 # You must already have the has_many() defined to use a many_to_many().
809 __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
810
811
812B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
813file. As with any Perl package, we need to end the last line with
814a statement that evaluates to C<true>. This is customarily done with
815C<1;> on a line by itself.
816
817This code defines both a C<has_many> and a C<many_to_many> relationship.
818The C<many_to_many> relationship is optional, but it makes it easier to
819map a book to its collection of authors. Without it, we would have to
820"walk" though the C<book_authors> table as in C<$book-E<gt>book_authors-
821E<gt>first-E<gt>author-E<gt>last_name> (we will see examples on how to
822use DBIC objects in your code soon, but note that because C<$book-
823E<gt>book_authors> can return multiple authors, we have to use C<first>
824to display a single author). C<many_to_many> allows us to use the
825shorter C<$book-E<gt>authors-E<gt>first-E<gt>last_name>. Note that you
826cannot define a C<many_to_many> relationship without also having the
827C<has_many> relationship in place.
828
829Then edit C<lib/MyApp/Schema/MyAppDB/Authors.pm> and add relationship
830information as follows (again, be careful to put in above the C<1;> but
831below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
832
833 #
834 # Set relationships:
835 #
836
837 # has_many():
838 # args:
839 # 1) Name of relationship, DBIC will create accessor with this name
840 # 2) Name of the model class referenced by this relationship
841 # 3) Column name in *foreign* table
842 __PACKAGE__->has_many(book_author => 'MyApp::Schema::MyAppDB::BookAuthors', 'author_id');
843
844 # many_to_many():
845 # args:
846 # 1) Name of relationship, DBIC will create accessor with this name
847 # 2) Name of has_many() relationship this many_to_many() is shortcut for
848 # 3) Name of belongs_to() relationship in model class of has_many() above
849 # You must already have the has_many() defined to use a many_to_many().
850 __PACKAGE__->many_to_many(books => 'book_author', 'book');
851
852Finally, do the same for the "join table,"
853C<lib/MyApp/Schema/MyAppDB/BookAuthors.pm>:
854
855 #
856 # Set relationships:
857 #
858
859 # belongs_to():
860 # args:
861 # 1) Name of relationship, DBIC will create accessor with this name
862 # 2) Name of the model class referenced by this relationship
863 # 3) Column name in *this* table
864 __PACKAGE__->belongs_to(book => 'MyApp::Schema::MyAppDB::Books', 'book_id');
865
866 # belongs_to():
867 # args:
868 # 1) Name of relationship, DBIC will create accessor with this name
869 # 2) Name of the model class referenced by this relationship
870 # 3) Column name in *this* table
871 __PACKAGE__->belongs_to(author => 'MyApp::Schema::MyAppDB::Authors', 'author_id');
872
873
874=head1 RUN THE APPLICATION
875
876Run the Catalyst "demo server" script with the C<DBIC_TRACE> option
877(it might still be enabled from earlier in the tutorial, but here
878is an alternate way to specify the option just in case):
879
880 $ DBIC_TRACE=1 script/myapp_server.pl
881
882Make sure that the application loads correctly and that you see the
883three dynamically created model class (one for each of the
884table-specific schema classes we created).
885
886Then hit the URL L<http://localhost:3000/books/list> and be sure that
887the book list is displayed.
888
889
890=head1 RUNNING THE APPLICATION FROM THE COMMAND LINE
891
892In some situations, it can be useful to run your application and
893display a page without using a browser. Catalyst lets you do this
894using the C<scripts/myapp_test.pl> script. Just supply the URL you
895wish to display and it will run that request through the normal
896controller dispatch logic and use the appropriate view to render the
897output (obviously, complex pages may dump a lot of text to your
898terminal window). For example, if you type:
899
900 $ script/myapp_test.pl "/books/list"
901
902You should get the same text as if you visited
903L<http://localhost:3000/books/list> with the normal development server
904and asked your browser to view the page source.
905
906
907=head1 UPDATING THE VIEW
908
909Let's add a new column to our book list page that takes advantage of
910the relationship information we manually added to our schema files
911in the previous section. Edit C<root/src/books/list.tt2> add add the
912following code below the existing table cell that contains
913C<book.rating> (IOW, add a new table cell below the existing two
914C<td> cells):
915
916 <td>
917 [% # First initialize a TT variable to hold a list. Then use a TT FOREACH -%]
918 [% # loop in 'side effect notation' to load just the last names of the -%]
919 [% # authors into the list. Note that the 'push' TT vmethod does not -%]
920 [% # a value, so nothing will be printed here. But, if you have something -%]
921 [% # in TT that does return a method and you don't want it printed, you -%]
922 [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to -%]
923 [% # call it and discard the return value. -%]
924 [% tt_authors = [ ];
925 tt_authors.push(author.last_name) FOREACH author = book.authors %]
926 [% # Now use a TT 'virtual method' to display the author count in parens -%]
927 [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
928 ([% tt_authors.size | html %])
929 [% # Use another TT vmethod to join & print the names & comma separators -%]
930 [% tt_authors.join(', ') | html %]
931 </td>
932
933Then hit C<Ctrl+R> in your browser (not that you don't need to reload
934the development server or use the C<-r> option when updating TT
935templates) and you should now the the number of authors each book and
936a comma-separated list of the author's last names.
937
938If you are still running the development server with C<DBIC_TRACE>
939enabled, you should also now see five more C<SELECT> statements in the
940debug output (one for each book as the authors are being retrieved by
941DBIC).
942
943Also note that we are using "| html", a type of TT filter, to escape
944characters such as E<lt> and E<gt> to &lt; and &gt; and avoid various
945types of dangerous hacks against your application. In a real
946application, you would probably want to put "| html" at the end of
947every field where a user has control over the information that can
948appear in that field (and can therefore inject markup or code if you
949don't "neutralize" those fields). In addition to "| html", Template
950Toolkit has a variety of other useful filters that can found in the
951documentation for L<Template::Filters|Template::Filters>.
952
953
954=head2 Using C<RenderView> for the Default View
955
956B<NOTE: The rest of this part of the tutorial is optional. You can
957skip to Part 4, L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>,
958if you wish.>
959
960Once your controller logic has processed the request from a user, it
961forwards processing to your view in order to generate the appropriate
962response output. Catalyst uses
963L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> by
964default to automatically performs this operation. If you look in
965C<lib/MyApp/Controller/Root.pm>, you should see the empty
966definition for the C<sub end> method:
967
968 sub end : ActionClass('RenderView') {}
969
970The following bullet points provide a quick overview of the
971C<RenderView> process:
972
973=over 4
974
975=item *
976
977C<Root.pm> is designed to hold application-wide logic.
978
979=item *
980
981At the end of a given user request, Catalyst will call the most specific
982C<end> method that's appropriate. For example, if the controller for a
983request has an C<end> method defined, it will be called. However, if
984the controller does not define a controller-specific C<end> method, the
985"global" C<end> method in C<Root.pm> will be called.
986
987=item *
988
989Because the definition includes an C<ActionClass> attribute, the
990L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
991will be executed B<after> any code inside the definition of C<sub end>
992is run. See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
993for more information on C<ActionClass>.
994
995=item *
996
997Because C<sub end> is empty, this effectively just runs the default
998logic in C<RenderView>. However, you can easily extend the
999C<RenderView> logic by adding your own code inside the empty method body
1000(C<{}>) created by the Catalyst Helpers when we first ran the
1001C<catalyst.pl> to initialize our application. See
1002L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more
1003detailed information on how to extended C<RenderView> in C<sub end>.
1004
1005=back
1006
1007
1008=head2 Using The Default Template Name
1009
1010By default, C<Catalyst::View::TT> will look for a template that uses the
1011same name as your controller action, allowing you to save the step of
1012manually specifying the template name in each action. For example, this
1013would allow us to remove the
1014C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our
1015C<list> action in the Books controller. Open
1016C<lib/MyApp/Controller/Books.pm> in your editor and comment out this line
1017to match the following (only the C<$c-E<gt>stash-E<gt>{template}> line
1018has changed):
1019
1020 =head2 list
1021
1022 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
1023
1024 =cut
1025
1026 sub list : Local {
1027 # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
1028 # 'Context' that's used to 'glue together' the various components
1029 # that make up the application
1030 my ($self, $c) = @_;
1031
1032 # Retrieve all of the book records as book model objects and store in the
1033 # stash where they can be accessed by the TT template
1034 $c->stash->{books} = [$c->model('MyAppDB::Books')->all];
1035
1036 # Set the TT template to use. You will almost always want to do this
1037 # in your action methods (actions methods respond to user input in
1038 # your controllers).
1039 #$c->stash->{template} = 'books/list.tt2';
1040 }
1041
1042C<Catalyst::View::TT> defaults to looking for a template with no
1043extension. In our case, we need to override this to look for an
1044extension of C<.tt2>. Open C<lib/MyApp/View/TT.pm> and add the
1045C<TEMPLATE_EXTENSION> definition as follows:
1046
1047 __PACKAGE__->config({
1048 CATALYST_VAR => 'Catalyst',
1049 INCLUDE_PATH => [
1050 MyApp->path_to( 'root', 'src' ),
1051 MyApp->path_to( 'root', 'lib' )
1052 ],
1053 PRE_PROCESS => 'config/main',
1054 WRAPPER => 'site/wrapper',
1055 ERROR => 'error.tt2',
1056 TIMER => 0,
1057 TEMPLATE_EXTENSION => '.tt2',
1058 });
1059
1060You should now be able to restart the development server as per the
1061previous section and access the L<http://localhost:3000/books/list>
1062as before.
1063
1064B<NOTE:> Please note that if you use the default template technique,
1065you will B<not> be able to use either the C<$c-E<gt>forward> or
1066the C<$c-E<gt>detach> mechanisms (these are discussed in Part 2 and
1067Part 9 of the Tutorial).
1068
1069
1070=head2 Return To A Manually-Specified Template
1071
1072In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
1073later in the tutorial, you should remove the comment from the
1074statement in C<sub list> in C<lib/MyApp/Controller/Books.pm>:
1075
1076 $c->stash->{template} = 'books/list.tt2';
1077
1078Then delete the C<TEMPLATE_EXTENSION> line in
1079C<lib/MyApp/View/TT.pm>.
1080
1081You should then be able to restart the development server and
1082access L<http://localhost:3000/books/list> in the same manner as
1083with earlier sections.
1084
1085
1086=head1 AUTHOR
1087
1088Kennedy Clark, C<hkclark@gmail.com>
1089
1090Please report any errors, issues or suggestions to the author. The
1091most recent version of the Catalyst Tutorial can be found at
1092L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/>.
1093
1094Copyright 2006, Kennedy Clark, under Creative Commons License
1095(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
1096