yaml expurgation and placeholders for a couple of upcoming tutorial articles
[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
c010ae0d 136parameters for your application from a central
137L<Config::General|Config::General> file (versus having the values
138hard-coded inside your Perl modules). Config::General uses syntax
139very similar to Apache configuration files. We will see how to use
140this feature of Catalyst during the authentication and authorization
141sections (Part 5 and Part 6).
3533daff 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
c010ae0d 573=head2 Create a DBIC Model
3533daff 574
c010ae0d 575Use the C<create=static> model helper option to build a model that
3533daff 576dynamically reads your database structure every time the application
577starts:
578
c010ae0d 579 $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=static dbi:SQLite:myapp.db
3533daff 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
3533daff 600=head1 RUN THE APPLICATION
601
602First, let's enable an environment variable option that causes
603DBIx::Class to dump the SQL statements it's using to access the database
604(this option can provide extremely helpful troubleshooting information):
605
606 $ export DBIC_TRACE=1
607
608This assumes you are using BASH as your shell -- adjust accordingly if
609you are using a different shell (for example, under tcsh, use
610C<setenv DBIC_TRACE 1>).
611
612B<NOTE>: You can also set this in your code using
613C<$class-E<gt>storage-E<gt>debug(1);>. See
614L<DBIx::Class::Manual::Troubleshooting> for details (including options
615to log to file instead of displaying to the Catalyst development server
616log).
617
618Then run the Catalyst "demo server" script:
619
620 $ script/myapp_server.pl
621
622Your development server log output should display something like:
623
624 $script/myapp_server.pl
625 [debug] Debug messages enabled
626 [debug] Loaded plugins:
627 .----------------------------------------------------------------------------.
628 | Catalyst::Plugin::ConfigLoader 0.17 |
629 | Catalyst::Plugin::StackTrace 0.06 |
630 | Catalyst::Plugin::Static::Simple 0.20 |
631 '----------------------------------------------------------------------------'
632
633 [debug] Loaded dispatcher "Catalyst::Dispatcher"
634 [debug] Loaded engine "Catalyst::Engine::HTTP"
635 [debug] Found home "/home/me/MyApp"
636 [debug] Loaded Config "/home/me/MyApp/myapp.yml"
637 [debug] Loaded components:
638 .-----------------------------------------------------------------+----------.
639 | Class | Type |
640 +-----------------------------------------------------------------+----------+
641 | MyApp::Controller::Books | instance |
642 | MyApp::Controller::Root | instance |
643 | MyApp::Model::MyAppDB | instance |
644 | MyApp::Model::MyAppDB::Authors | class |
645 | MyApp::Model::MyAppDB::BookAuthors | class |
646 | MyApp::Model::MyAppDB::Books | class |
647 | MyApp::View::TT | instance |
648 '-----------------------------------------------------------------+----------'
649
650 [debug] Loaded Private actions:
651 .----------------------+--------------------------------------+--------------.
652 | Private | Class | Method |
653 +----------------------+--------------------------------------+--------------+
654 | /default | MyApp::Controller::Root | default |
655 | /end | MyApp::Controller::Root | end |
656 | /books/index | MyApp::Controller::Books | index |
657 | /books/list | MyApp::Controller::Books | list |
658 '----------------------+--------------------------------------+--------------'
659
660 [debug] Loaded Path actions:
661 .-------------------------------------+--------------------------------------.
662 | Path | Private |
663 +-------------------------------------+--------------------------------------+
664 | /books/list | /books/list |
665 '-------------------------------------+--------------------------------------'
666
667 [info] MyApp powered by Catalyst 5.7011
668 You can connect to your server at http://localhost:3000
669
670B<NOTE>: Be sure you run the C<script/myapp_server.pl> command from
671the 'base' directory of your application, not inside the C<script>
672directory itself or it will not be able to locate the C<myapp.db>
673database file. You can use a fully qualified or a relative path to
674locate the database file, but we did not specify that when we ran the
675model helper earlier.
676
677Some things you should note in the output above:
678
679=over 4
680
681=item *
682
683Catalyst::Model::DBIC::Schema dynamically created three model classes,
684one to represent each of the three tables in our database
685(C<MyApp::Model::MyAppDB::Authors>, C<MyApp::Model::MyAppDB::BookAuthors>,
686and C<MyApp::Model::MyAppDB::Books>).
687
688=item *
689
690The "list" action in our Books controller showed up with a path of
691C</books/list>.
692
693=back
694
695Point your browser to L<http://localhost:3000> and you should still get
696the Catalyst welcome page.
697
698Next, to view the book list, change the URL in your browser to
699L<http://localhost:3000/books/list>. You should get a list of the five
700books loaded by the C<myapp01.sql> script above, with TTSite providing
701the formatting for the very simple output we generated in our template.
702The rating for each book should appear on each row.
703
704Also notice in the output of the C<script/myapp_server.pl> that DBIC
705used the following SQL to retrieve the data:
706
707 SELECT me.id, me.title, me.rating FROM books me
708
709because we enabled DBIC_TRACE.
710
711You now the beginnings of a simple but workable web application.
712Continue on to future sections and we will develop the application
713more fully.
714
715
716=head1 A STATIC DATABASE MODEL WITH C<DBIx::Class>
717
718=head2 Create Static DBIC Schema Files
719
720Unlike the previous section where we had DBIC automatically discover the
721structure of the database every time the application started, here we
722will use static schema files for more control. This is typical of most
723"real world" applications.
724
725One option would be to create a separate schema file for each table in
726the database, however, lets use the same L<DBIx::Class::Schema::Loader>
727used earlier with C<create=dynamic> to build the static files for us.
728First, lets remove the schema file created in Part 2:
729
730 $ rm lib/MyApp/Schema/MyAppDB.pm
731
732Now regenerate the schema using the C<create=static> option:
733
734 $ script/myapp_create.pl model MyAppDB DBIC::Schema MyApp::Schema::MyAppDB create=static dbi:SQLite:myapp.db
735 exists "/home/me/MyApp/script/../lib/MyApp/Model"
736 exists "/home/me/MyApp/script/../t"
737 Dumping manual schema for MyApp::Schema::MyAppDB to directory /home/me/MyApp/script/../lib ...
738 Schema dump completed.
739 exists "/home/me/MyApp/script/../lib/MyApp/Model/MyAppDB.pm"
740
741We could have also deleted C<lib/MyApp/Model/MyAppDB.pm>, but it would
742have regenerated the same file (note the C<exists> in the output above).
743If you take a look at C<lib/MyApp/Model/MyAppDB.pm>, it simply contains
744a reference to the actual schema file in C<lib/MyApp/Schema/MyAppDB.pm>
745along with the database connect string.
746
747If you look in the C<lib/MyApp/Schema> directory, you will find that
748C<MyAppDB.pm> is no longer using L<DBIx::Class::Schema::Loader> as its
749base class (L<DBIx::Class::Schema::Loader> is only being used by the
750helper to load the schema once and then create the static files for us)
751and that it only contains a call to the C<load_classes> method. You
752will also find that C<lib/MyApp/Schema> contains a C<MyAppDB>
753subdirectory, with one file inside this directory for each of the tables
754in our simple database (C<Authors.pm>, C<BookAuthors.pm>, and
755C<Books.pm>). These three files were created based on the information
756found by L<DBIx::Class::Schema::Loader> as the helper ran.
757
758The idea with all of the files created under C<lib/MyApp/Schema> by the
759C<create=static> option is to only edit the files below the C<# DO NOT
760MODIFY THIS OR ANYTHING ABOVE!> warning. If you place all of your
761changes below that point in the file, you can regenerate the
762auto-generated information at the top of each file should your database
763structure get updated.
764
765Also note the "flow" of the model information across the various files
766and directories. Catalyst will initially load the model from
767C<lib/MyApp/Model/MyAppDB.pm>. This file contains a reference to
768C<lib/MyApp/Schema/MyAppDB.pm>, so that file is loaded next. Finally,
769the call to C<load_classes> in that file will load each of the
770table-specific "results source" files from the C<lib/MyApp/Schema/MyAppDB>
771subdirectory. These three table-specific DBIC schema files will then be
772used to create three table-specific Catalyst models every time the
773application starts (you can see these three model files listed in
774the debug output generated when you launch the application).
775
776
777=head2 Updating the Generated DBIC Schema Files
778
779
780Let's manually add some relationship information to the auto-generated
781schema files. First edit C<lib/MyApp/Schema/MyAppDB/Books.pm> and
782add the following text below the C<# You can replace this text...>
783comment:
784
785 #
786 # Set relationships:
787 #
788
789 # has_many():
790 # args:
791 # 1) Name of relationship, DBIC will create accessor with this name
792 # 2) Name of the model class referenced by this relationship
793 # 3) Column name in *foreign* table
794 __PACKAGE__->has_many(book_authors => 'MyApp::Schema::MyAppDB::BookAuthors', 'book_id');
795
796 # many_to_many():
797 # args:
798 # 1) Name of relationship, DBIC will create accessor with this name
799 # 2) Name of has_many() relationship this many_to_many() is shortcut for
800 # 3) Name of belongs_to() relationship in model class of has_many() above
801 # You must already have the has_many() defined to use a many_to_many().
802 __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
803
804
805B<Note:> Be careful to put this code I<above> the C<1;> at the end of the
806file. As with any Perl package, we need to end the last line with
807a statement that evaluates to C<true>. This is customarily done with
808C<1;> on a line by itself.
809
810This code defines both a C<has_many> and a C<many_to_many> relationship.
811The C<many_to_many> relationship is optional, but it makes it easier to
812map a book to its collection of authors. Without it, we would have to
813"walk" though the C<book_authors> table as in C<$book-E<gt>book_authors-
814E<gt>first-E<gt>author-E<gt>last_name> (we will see examples on how to
815use DBIC objects in your code soon, but note that because C<$book-
816E<gt>book_authors> can return multiple authors, we have to use C<first>
817to display a single author). C<many_to_many> allows us to use the
818shorter C<$book-E<gt>authors-E<gt>first-E<gt>last_name>. Note that you
819cannot define a C<many_to_many> relationship without also having the
820C<has_many> relationship in place.
821
822Then edit C<lib/MyApp/Schema/MyAppDB/Authors.pm> and add relationship
823information as follows (again, be careful to put in above the C<1;> but
824below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!> comment):
825
826 #
827 # Set relationships:
828 #
829
830 # has_many():
831 # args:
832 # 1) Name of relationship, DBIC will create accessor with this name
833 # 2) Name of the model class referenced by this relationship
834 # 3) Column name in *foreign* table
835 __PACKAGE__->has_many(book_author => 'MyApp::Schema::MyAppDB::BookAuthors', 'author_id');
836
837 # many_to_many():
838 # args:
839 # 1) Name of relationship, DBIC will create accessor with this name
840 # 2) Name of has_many() relationship this many_to_many() is shortcut for
841 # 3) Name of belongs_to() relationship in model class of has_many() above
842 # You must already have the has_many() defined to use a many_to_many().
843 __PACKAGE__->many_to_many(books => 'book_author', 'book');
844
845Finally, do the same for the "join table,"
846C<lib/MyApp/Schema/MyAppDB/BookAuthors.pm>:
847
848 #
849 # Set relationships:
850 #
851
852 # belongs_to():
853 # args:
854 # 1) Name of relationship, DBIC will create accessor with this name
855 # 2) Name of the model class referenced by this relationship
856 # 3) Column name in *this* table
857 __PACKAGE__->belongs_to(book => 'MyApp::Schema::MyAppDB::Books', 'book_id');
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(author => 'MyApp::Schema::MyAppDB::Authors', 'author_id');
865
866
867=head1 RUN THE APPLICATION
868
869Run the Catalyst "demo server" script with the C<DBIC_TRACE> option
870(it might still be enabled from earlier in the tutorial, but here
871is an alternate way to specify the option just in case):
872
873 $ DBIC_TRACE=1 script/myapp_server.pl
874
875Make sure that the application loads correctly and that you see the
876three dynamically created model class (one for each of the
877table-specific schema classes we created).
878
879Then hit the URL L<http://localhost:3000/books/list> and be sure that
880the book list is displayed.
881
882
883=head1 RUNNING THE APPLICATION FROM THE COMMAND LINE
884
885In some situations, it can be useful to run your application and
886display a page without using a browser. Catalyst lets you do this
887using the C<scripts/myapp_test.pl> script. Just supply the URL you
888wish to display and it will run that request through the normal
889controller dispatch logic and use the appropriate view to render the
890output (obviously, complex pages may dump a lot of text to your
891terminal window). For example, if you type:
892
893 $ script/myapp_test.pl "/books/list"
894
895You should get the same text as if you visited
896L<http://localhost:3000/books/list> with the normal development server
897and asked your browser to view the page source.
898
899
900=head1 UPDATING THE VIEW
901
902Let's add a new column to our book list page that takes advantage of
903the relationship information we manually added to our schema files
904in the previous section. Edit C<root/src/books/list.tt2> add add the
905following code below the existing table cell that contains
906C<book.rating> (IOW, add a new table cell below the existing two
907C<td> cells):
908
909 <td>
910 [% # First initialize a TT variable to hold a list. Then use a TT FOREACH -%]
911 [% # loop in 'side effect notation' to load just the last names of the -%]
912 [% # authors into the list. Note that the 'push' TT vmethod does not -%]
913 [% # a value, so nothing will be printed here. But, if you have something -%]
914 [% # in TT that does return a method and you don't want it printed, you -%]
915 [% # can: 1) assign it to a bogus value, or 2) use the CALL keyword to -%]
916 [% # call it and discard the return value. -%]
917 [% tt_authors = [ ];
918 tt_authors.push(author.last_name) FOREACH author = book.authors %]
919 [% # Now use a TT 'virtual method' to display the author count in parens -%]
920 [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
921 ([% tt_authors.size | html %])
922 [% # Use another TT vmethod to join & print the names & comma separators -%]
923 [% tt_authors.join(', ') | html %]
924 </td>
925
926Then hit C<Ctrl+R> in your browser (not that you don't need to reload
927the development server or use the C<-r> option when updating TT
928templates) and you should now the the number of authors each book and
929a comma-separated list of the author's last names.
930
931If you are still running the development server with C<DBIC_TRACE>
932enabled, you should also now see five more C<SELECT> statements in the
933debug output (one for each book as the authors are being retrieved by
934DBIC).
935
936Also note that we are using "| html", a type of TT filter, to escape
937characters such as E<lt> and E<gt> to &lt; and &gt; and avoid various
938types of dangerous hacks against your application. In a real
939application, you would probably want to put "| html" at the end of
940every field where a user has control over the information that can
941appear in that field (and can therefore inject markup or code if you
942don't "neutralize" those fields). In addition to "| html", Template
943Toolkit has a variety of other useful filters that can found in the
944documentation for L<Template::Filters|Template::Filters>.
945
946
947=head2 Using C<RenderView> for the Default View
948
949B<NOTE: The rest of this part of the tutorial is optional. You can
950skip to Part 4, L<Basic CRUD|Catalyst::Manual::Tutorial::BasicCRUD>,
951if you wish.>
952
953Once your controller logic has processed the request from a user, it
954forwards processing to your view in order to generate the appropriate
955response output. Catalyst uses
956L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> by
957default to automatically performs this operation. If you look in
958C<lib/MyApp/Controller/Root.pm>, you should see the empty
959definition for the C<sub end> method:
960
961 sub end : ActionClass('RenderView') {}
962
963The following bullet points provide a quick overview of the
964C<RenderView> process:
965
966=over 4
967
968=item *
969
970C<Root.pm> is designed to hold application-wide logic.
971
972=item *
973
974At the end of a given user request, Catalyst will call the most specific
975C<end> method that's appropriate. For example, if the controller for a
976request has an C<end> method defined, it will be called. However, if
977the controller does not define a controller-specific C<end> method, the
978"global" C<end> method in C<Root.pm> will be called.
979
980=item *
981
982Because the definition includes an C<ActionClass> attribute, the
983L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> logic
984will be executed B<after> any code inside the definition of C<sub end>
985is run. See L<Catalyst::Manual::Actions|Catalyst::Manual::Actions>
986for more information on C<ActionClass>.
987
988=item *
989
990Because C<sub end> is empty, this effectively just runs the default
991logic in C<RenderView>. However, you can easily extend the
992C<RenderView> logic by adding your own code inside the empty method body
993(C<{}>) created by the Catalyst Helpers when we first ran the
994C<catalyst.pl> to initialize our application. See
995L<Catalyst::Action::RenderView|Catalyst::Action::RenderView> for more
996detailed information on how to extended C<RenderView> in C<sub end>.
997
998=back
999
1000
1001=head2 Using The Default Template Name
1002
1003By default, C<Catalyst::View::TT> will look for a template that uses the
1004same name as your controller action, allowing you to save the step of
1005manually specifying the template name in each action. For example, this
1006would allow us to remove the
1007C<$c-E<gt>stash-E<gt>{template} = 'books/list.tt2';> line of our
1008C<list> action in the Books controller. Open
1009C<lib/MyApp/Controller/Books.pm> in your editor and comment out this line
1010to match the following (only the C<$c-E<gt>stash-E<gt>{template}> line
1011has changed):
1012
1013 =head2 list
1014
1015 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
1016
1017 =cut
1018
1019 sub list : Local {
1020 # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
1021 # 'Context' that's used to 'glue together' the various components
1022 # that make up the application
1023 my ($self, $c) = @_;
1024
1025 # Retrieve all of the book records as book model objects and store in the
1026 # stash where they can be accessed by the TT template
1027 $c->stash->{books} = [$c->model('MyAppDB::Books')->all];
1028
1029 # Set the TT template to use. You will almost always want to do this
1030 # in your action methods (actions methods respond to user input in
1031 # your controllers).
1032 #$c->stash->{template} = 'books/list.tt2';
1033 }
1034
1035C<Catalyst::View::TT> defaults to looking for a template with no
1036extension. In our case, we need to override this to look for an
1037extension of C<.tt2>. Open C<lib/MyApp/View/TT.pm> and add the
1038C<TEMPLATE_EXTENSION> definition as follows:
1039
1040 __PACKAGE__->config({
1041 CATALYST_VAR => 'Catalyst',
1042 INCLUDE_PATH => [
1043 MyApp->path_to( 'root', 'src' ),
1044 MyApp->path_to( 'root', 'lib' )
1045 ],
1046 PRE_PROCESS => 'config/main',
1047 WRAPPER => 'site/wrapper',
1048 ERROR => 'error.tt2',
1049 TIMER => 0,
1050 TEMPLATE_EXTENSION => '.tt2',
1051 });
1052
1053You should now be able to restart the development server as per the
1054previous section and access the L<http://localhost:3000/books/list>
1055as before.
1056
1057B<NOTE:> Please note that if you use the default template technique,
1058you will B<not> be able to use either the C<$c-E<gt>forward> or
1059the C<$c-E<gt>detach> mechanisms (these are discussed in Part 2 and
1060Part 9 of the Tutorial).
1061
1062
1063=head2 Return To A Manually-Specified Template
1064
1065In order to be able to use C<$c-E<gt>forward> and C<$c-E<gt>detach>
1066later in the tutorial, you should remove the comment from the
1067statement in C<sub list> in C<lib/MyApp/Controller/Books.pm>:
1068
1069 $c->stash->{template} = 'books/list.tt2';
1070
1071Then delete the C<TEMPLATE_EXTENSION> line in
1072C<lib/MyApp/View/TT.pm>.
1073
1074You should then be able to restart the development server and
1075access L<http://localhost:3000/books/list> in the same manner as
1076with earlier sections.
1077
1078
1079=head1 AUTHOR
1080
1081Kennedy Clark, C<hkclark@gmail.com>
1082
1083Please report any errors, issues or suggestions to the author. The
1084most recent version of the Catalyst Tutorial can be found at
1085L<http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Manual/lib/Catalyst/Manual/Tutorial/>.
1086
1087Copyright 2006, Kennedy Clark, under Creative Commons License
1088(L<http://creativecommons.org/licenses/by-nc-sa/2.5/>).
1089