1Catalyst::Manual::TutorUisaelr:C:Ca0ot3na_tlMryoisrbteu:Ct:aeMtdaanlPuyeasrltl:B:aDTsouictcuosmr(ei3na)tla:t:i0o3n_MoreCatalystBasics(3)
2
3
4

NAME

6       Catalyst::Manual::Tutorial::03_MoreCatalystBasics - Catalyst Tutorial -
7       Chapter 3: More Catalyst Application Development Basics
8

OVERVIEW

10       This is Chapter 3 of 10 for the Catalyst tutorial.
11
12       Tutorial Overview
13
14       1.  Introduction
15
16       2.  Catalyst Basics
17
18       3.  03_More Catalyst Basics
19
20       4.  Basic CRUD
21
22       5.  Authentication
23
24       6.  Authorization
25
26       7.  Debugging
27
28       8.  Testing
29
30       9.  Advanced CRUD
31
32       10. Appendices
33

DESCRIPTION

35       This chapter of the tutorial builds on the work done in Chapter 2 to
36       explore some features that are more typical of "real world" web
37       applications. From this chapter of the tutorial onward, we will be
38       building a simple book database application.  Although the application
39       will be too limited to be of use to anyone, it should provide a basic
40       environment where we can explore a variety of features used in
41       virtually all web applications.
42
43       You can check out the source code for this example from the Catalyst
44       Subversion repository as per the instructions in
45       Catalyst::Manual::Tutorial::01_Intro.
46
47       Please take a look at "CATALYST INSTALLATION" in
48       Catalyst::Manual::Tutorial::01_Intro before doing the rest of this
49       tutorial.  Although the tutorial should work correctly under most any
50       recent version of Perl running on any operating system, the tutorial
51       has been written using Debian 5 and tested to be sure it runs correctly
52       in this environment.
53

CREATE A NEW APPLICATION

55       The remainder of the tutorial will build an application called "MyApp".
56       First use the Catalyst "catalyst.pl" script to initialize the framework
57       for the "MyApp" application (make sure you aren't still inside the
58       directory of the "Hello" application from the previous chapter of the
59       tutorial or in a directory that already has a "MyApp" subdirectory):
60
61           $ catalyst.pl MyApp
62           created "MyApp"
63           created "MyApp/script"
64           created "MyApp/lib"
65           created "MyApp/root"
66           ...
67           created "MyApp/script/myapp_create.pl"
68           Change to application directory and Run "perl Makefile.PL" to make sure your install is complete
69           $ cd MyApp
70
71       This creates a similar skeletal structure to what we saw in Chapter 2
72       of the tutorial, except with "MyApp" and "myapp" substituted for
73       "Hello" and "hello".  (As noted in Chapter 2, omit the ".pl" from the
74       command if you are using Strawberry Perl.)
75

EDIT THE LIST OF CATALYST PLUGINS

77       One of the greatest benefits of Catalyst is that it has such a large
78       library of bases classes and plugins available that you can use easily
79       add functionality to your application. Plugins are used to seamlessly
80       integrate existing Perl modules into the overall Catalyst framework. In
81       general, they do this by adding additional methods to the "context"
82       object (generally written as $c) that Catalyst passes to every
83       component throughout the framework.
84
85       By default, Catalyst enables three plugins/flags:
86
87       ·   "-Debug" Flag
88
89           Enables the Catalyst debug output you saw when we started the
90           "script/myapp_server.pl" development server earlier.  You can
91           remove this item when you place your application into production.
92
93           To be technically correct, it turns out that "-Debug" is not a
94           plugin, but a flag.  Although most of the items specified on the
95           "__PACKAGE__->setup" line of your application class will be
96           plugins, Catalyst supports a limited number of flag options (of
97           these, "-Debug" is the most common).  See the documentation for
98           "Catalyst.pm" to get details on other flags (currently "-Engine",
99           "-Home", and "-Log").
100
101           If you prefer, there are several other ways to enable debug output:
102
103           ·   Use the "$c->debug" method
104
105           ·   The "-d" option to "script/myapp_server.pl"
106
107           ·   The "CATALYST_DEBUG=1" environment variable (or set it to zero
108               to templorarily disable debug output).
109
110           TIP: Depending on your needs, it can be helpful to permanently
111           remove "-Debug" from "lib/MyApp.pm" and then use the "-d" option to
112           "script/myapp_server.pl" to re-enable it just for the development
113           server.  We will not be using that approach in the tutorial, but
114           feel free to make use of it in your own projects.
115
116       ·   Catalyst::Plugin::ConfigLoader
117
118           "ConfigLoader" provides an automatic way to load configurable
119           parameters for your application from a central Config::General file
120           (versus having the values hard-coded inside your Perl modules).
121           Config::General uses syntax very similar to Apache configuration
122           files.  We will see how to use this feature of Catalyst during the
123           authentication and authorization sections (Chapter 5 and Chapter
124           6).
125
126           IMPORTANT NOTE: If you are using a version of Catalyst::Devel prior
127           to version 1.06, be aware that Catalyst changed the default format
128           from YAML to the more straightforward "Config::General" style.
129           This tutorial uses the newer "myapp.conf" file for
130           "Config::General". However, Catalyst supports both formats and will
131           automatically use either "myapp.conf" or "myapp.yml" (or any other
132           format supported by Catalyst::Plugin::ConfigLoader and
133           Config::Any).  If you are using a version of Catalyst::Devel prior
134           to 1.06, you can convert to the newer format by simply creating the
135           "myapp.conf" file manually and deleting "myapp.yml".  The default
136           contents of the "myapp.conf" you create should only consist of one
137           line:
138
139               name MyApp
140
141           TIP: This script can be useful for converting between configuration
142           formats:
143
144               perl -Ilib -e 'use MyApp; use Config::General;
145                   Config::General->new->save_file("myapp.conf", MyApp->config);'
146
147       ·   Catalyst::Plugin::Static::Simple
148
149           "Static::Simple" provides an easy way to serve static content, such
150           as images and CSS files, from the development server.
151
152       For our application, we want to add one new plugin into the mix.  To do
153       this, edit "lib/MyApp.pm" (this file is generally referred to as your
154       application class) and delete the lines with:
155
156           use Catalyst qw/
157               -Debug
158               ConfigLoader
159               Static::Simple
160           /;
161
162       Then replace it with:
163
164           # Load plugins
165           use Catalyst qw/
166               -Debug
167               ConfigLoader
168               Static::Simple
169
170               StackTrace
171           /;
172
173       Note: Recent versions of "Catalyst::Devel" have used a variety of
174       techniques to load these plugins/flags.  For example, you might see the
175       following:
176
177           __PACKAGE__->setup(qw/-Debug ConfigLoader Static::Simple/);
178
179       Don't let these variations confuse you -- they all accomplish the same
180       result.
181
182       This tells Catalyst to start using one additional plugin,
183       Catalyst::Plugin::StackTrace, to add a stack trace to the standard
184       Catalyst "debug screen" (the screen Catalyst sends to your browser when
185       an error occurs). Be aware that StackTrace output appears in your
186       browser, not in the console window from which you're running your
187       application, which is where logging output usually goes.
188
189       Make sure when adding new plugins you also include them as a new
190       dependency within the Makefile.PL file. For example, after adding the
191       StackTrace plugin the Makefile.PL should include the following line:
192
193           requires 'Catalyst::Plugin::StackTrace';
194
195       Notes:
196
197       ·   "__PACKAGE__" is just a shorthand way of referencing the name of
198           the package where it is used.  Therefore, in "MyApp.pm",
199           "__PACKAGE__" is equivalent to "MyApp".
200
201       ·   You will want to disable StackTrace before you put your application
202           into production, but it can be helpful during development.
203
204       ·   When specifying plugins, you can omit "Catalyst::Plugin::" from the
205           name.  Additionally, you can spread the plugin names across
206           multiple lines as shown here or place them all on one line.
207

CREATE A CATALYST CONTROLLER

209       As discussed earlier, controllers are where you write methods that
210       interact with user input.  Typically, controller methods respond to
211       "GET" and "POST" requests from the user's web browser.
212
213       Use the Catalyst "create" script to add a controller for book-related
214       actions:
215
216           $ script/myapp_create.pl controller Books
217            exists "/home/me/MyApp/script/../lib/MyApp/Controller"
218            exists "/home/me/MyApp/script/../t"
219           created "/home/me/MyApp/script/../lib/MyApp/Controller/Books.pm"
220           created "/home/me/MyApp/script/../t/controller_Books.t"
221
222       Then edit "lib/MyApp/Controller/Books.pm" (as discussed in Chapter 2 of
223       the Tutorial, Catalyst has a separate directory under "lib/MyApp" for
224       each of the three parts of MVC: "Model", "View", and "Controller") and
225       add the following method to the controller:
226
227           =head2 list
228
229           Fetch all book objects and pass to books/list.tt2 in stash to be displayed
230
231           =cut
232
233           sub list :Local {
234               # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
235               # 'Context' that's used to 'glue together' the various components
236               # that make up the application
237               my ($self, $c) = @_;
238
239               # Retrieve all of the book records as book model objects and store in the
240               # stash where they can be accessed by the TT template
241               # $c->stash(books => [$c->model('DB::Book')->all]);
242               # But, for now, use this code until we create the model later
243               $c->stash(books => '');
244
245               # Set the TT template to use.  You will almost always want to do this
246               # in your action methods (action methods respond to user input in
247               # your controllers).
248               $c->stash(template => 'books/list.tt2');
249           }
250
251       TIP: See Appendix 1 for tips on removing the leading spaces when
252       cutting and pasting example code from POD-based documents.
253
254       Programmers experienced with object-oriented Perl should recognize
255       $self as a reference to the object where this method was called.  On
256       the other hand, $c will be new to many Perl programmers who have not
257       used Catalyst before (it's sometimes written as $context).  The Context
258       object is automatically passed to all Catalyst components.  It is used
259       to pass information between components and provide access to Catalyst
260       and plugin functionality.
261
262       Catalyst actions are regular Perl methods, but they make use of
263       attributes (the "":Local"" next to the ""sub list"" in the code above)
264       to provide additional information to the Catalyst dispatcher logic
265       (note that the space between the colon and the attribute name is
266       optional; you will see attributes written both ways).  Most Catalyst
267       Controllers use one of five action types:
268
269       ·   :Private -- Use ":Private" for methods that you want to make into
270           an action, but you do not want Catalyst to directly expose  the
271           method to your users.  Catalyst will not map ":Private" methods to
272           a URI.  Use them for various sorts of "special" methods (the
273           "begin", "auto", etc. discussed below) or for methods you want to
274           be able to "forward" or "detach" to.  (If the method is a plain old
275           "helper method" that you don't want to be an action at all, then
276           just define the method without any attribute -- you can call it in
277           your code, but the Catalyst dispatcher will ignore it.)
278
279           There are five types of "special" build-in ":Private" actions:
280           "begin", "end", "default", "index", and "auto".
281
282           ·   With "begin", "end", "default", "index" private actions, only
283               the most specific action of each type will be called.  For
284               example, if you define a "begin" action in your controller it
285               will override a "begin" action in your application/root
286               controller -- only the action in your controller will be
287               called.
288
289           ·   Unlike the other actions where only a single method is called
290               for each request, every auto action along the chain of
291               namespaces will be called.  Each "auto" action will be called
292               from the application/root controller down through the most
293               specific class.
294
295       ·   :Path -- ":Path" actions let you map a method to an explicit URI
296           path.  For example, "":Path('list')"" in
297           "lib/MyApp/Controller/Books.pm" would match on the URL
298           "http://localhost:3000/books/list", but "":Path('/list')"" would
299           match on "http://localhost:3000/list" (because of the leading
300           slash).  You can use ":Args()" to specify how many arguments an
301           action should accept.  See "Action_types" in
302           Catalyst::Manual::Intro for more information and examples.
303
304       ·   :Local -- ":Local" is merely a shorthand for
305           "":Path('_name_of_method_')"".  For example, these are equivalent:
306           ""sub create_book :Local {...}"" and ""sub create_book
307           :Path('create_book') {...}"".
308
309       ·   :Global -- ":Global" is merely a shorthand for
310           "":Path('/_name_of_method_')"".  For example, these are equivalent:
311           ""sub create_book :Global {...}"" and ""sub create_book
312           :Path('/create_book') {...}"".
313
314       ·   :Chained -- Newer Catalyst applications tend to use the Chained
315           dispatch form of action types because of its power and flexibility.
316           It allows a series of controller methods to be automatically
317           dispatched to service a single user request.  See
318           Catalyst::Manual::Tutorial::04_BasicCRUD and
319           Catalyst::DispatchType::Chained for more information on chained
320           actions.
321
322       You should refer to "Action_types" in Catalyst::Manual::Intro for
323       additional information and for coverage of some lesser-used action
324       types not discussed here ("Regex" and "LocalRegex").
325

CATALYST VIEWS

327       As mentioned in Chapter 2 of the tutorial, views are where you render
328       output, typically for display in the user's web browser (but also
329       possibly using into output-generation systems, such as PDF or JSON).
330       The code in "lib/MyApp/View" selects the type of view to use, with the
331       actual rendering template found in the "root" directory.  As with
332       virtually every aspect of Catalyst, options abound when it comes to the
333       specific view technology you adopt inside your application. However,
334       most Catalyst applications use the Template Toolkit, known as TT (for
335       more information on TT, see http://www.template-toolkit.org
336       <http://www.template-toolkit.org>). Other somewhat popular view
337       technologies include Mason (<http://www.masonhq.com> and
338       <http://www.masonbook.com>) and HTML::Template
339       (http://html-template.sourceforge.net <http://html-
340       template.sourceforge.net>).
341
342   Create a Catalyst View
343       When using TT for the Catalyst view, the main helper script is
344       Catalyst::Helper::View::TT.  You may also come across references to
345       Catalyst::Helper::View::TTSite, but its use is now deprecated.
346
347       Enter the following command to enable the "TT" style of view rendering
348       for this tutorial:
349
350           $ script/myapp_create.pl view TT TT
351            exists "/home/me/MyApp/script/../lib/MyApp/View"
352            exists "/home/me/MyApp/script/../t"
353            created "/home/me/MyApp/script/../lib/MyApp/View/TT.pm"
354            created "/home/me/MyApp/script/../t/view_TT.t"
355
356       This simply creates a view called "TT" (the second 'TT' argument) in a
357       file called "TT.pm" (the first 'TT' argument). It is now up to you to
358       decide how you want to structure your view layout.  For the tutorial,
359       we will start with a very simple TT template to initially demonstrate
360       the concepts, but quickly migrate to a more typical "wrapper page" type
361       of configuration (where the "wrapper" controls the overall "look and
362       feel" of your site from a single file or set of files).
363
364       Edit "lib/MyApp/View/TT.pm" and you should see that the default
365       contents contains something similar to the following:
366
367           __PACKAGE__->config(TEMPLATE_EXTENSION => '.tt');
368
369       And update it to match:
370
371           __PACKAGE__->config(
372               # Change default TT extension
373               TEMPLATE_EXTENSION => '.tt2',
374               # Set the location for TT files
375               INCLUDE_PATH => [
376                       MyApp->path_to( 'root', 'src' ),
377                   ],
378           );
379
380       NOTE: Make sure to add a comma after '.tt2' outside the single quote.
381
382       This changes the default extension for Template Toolkit from '.tt' to
383       '.tt2' and changes the base directory for your template files from
384       "root" to "root/src".  Stick with these conventions for the tutorial,
385       but feel free to use whatever options you desire in your applications
386       (as with most things Perl, there's more than one way to do it...).
387
388       Note: We will use "root/src" as the base directory for our template
389       files, with a full naming convention of
390       "root/src/_controller_name_/_action_name_.tt2".  Another popular option
391       is to use "root/" as the base (with a full filename pattern of
392       "root/_controller_name_/_action_name_.tt2").
393
394   Create a TT Template Page
395       First create a directory for book-related TT templates:
396
397           $ mkdir -p root/src/books
398
399       Then create "root/src/books/list.tt2" in your editor and enter:
400
401           [% # This is a TT comment.  The '-' at the end "chomps" the newline.  You won't -%]
402           [% # see this "chomping" in your browser because HTML ignores blank lines, but  -%]
403           [% # it WILL eliminate a blank line if you view the HTML source.  It's purely   -%]
404           [%- # optional, but both the beginning and the ending TT tags support chomping. -%]
405
406           [% # Provide a title -%]
407           [% META title = 'Book List' -%]
408
409           <table>
410           <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
411           [% # Display each book in a table row %]
412           [% FOREACH book IN books -%]
413             <tr>
414               <td>[% book.title %]</td>
415               <td>[% book.rating %]</td>
416               <td></td>
417             </tr>
418           [% END -%]
419           </table>
420
421       As indicated by the inline comments above, the "META title" line uses
422       TT's META feature to provide a title to the "wrapper" that we will
423       create later. Meanwhile, the "FOREACH" loop iterates through each
424       "book" model object and prints the "title" and "rating" fields.
425
426       The "[%" and "%]" tags are used to delimit Template Toolkit code.  TT
427       supports a wide variety of directives for "calling" other files,
428       looping, conditional logic, etc.  In general, TT simplifies the usual
429       range of Perl operators down to the single dot (".") operator.  This
430       applies to operations as diverse as method calls, hash lookups, and
431       list index values (see
432       <http://search.cpan.org/perldoc?Template::Manual::Variables> for
433       details and examples).  In addition to the usual Template module Pod
434       documentation, you can access the TT manual at
435       <http://search.cpan.org/perldoc?Template::Manual>.
436
437       TIP: While you can build all sorts of complex logic into your TT
438       templates, you should in general keep the "code" part of your templates
439       as simple as possible.  If you need more complex logic, create helper
440       methods in your model that abstract out a set of code into a single
441       call from your TT template.  (Note that the same is true of your
442       controller logic as well -- complex sections of code in your
443       controllers should often be pulled out and placed into your model
444       objects.)  In Chapter 4 of the tutorial we will explore some extremely
445       helpful and powerful features of DBIx::Class that allow you to pull
446       code out of your views and controllers and place it where it rightfully
447       belongs in a model class.
448
449   Test Run The Application
450       To test your work so far, first start the development server:
451
452           $ script/myapp_server.pl -r
453
454       Then point your browser to <http://localhost:3000> and you should still
455       get the Catalyst welcome page.  Next, change the URL in your browser to
456       <http://localhost:3000/books/list>.  If you have everything working so
457       far, you should see a web page that displays nothing other than our
458       column headers for "Title", "Rating", and "Author(s)" -- we will not
459       see any books until we get the database and model working below.
460
461       If you run into problems getting your application to run correctly, it
462       might be helpful to refer to some of the debugging techniques covered
463       in the Debugging chapter of the tutorial.
464

CREATE A SQLITE DATABASE

466       In this step, we make a text file with the required SQL commands to
467       create a database table and load some sample data.  We will use SQLite
468       (<http://www.sqlite.org>), a popular database that is lightweight and
469       easy to use. Be sure to get at least version 3. Open "myapp01.sql" in
470       your editor and enter:
471
472           --
473           -- Create a very simple database to hold book and author information
474           --
475           PRAGMA foreign_keys = ON;
476           CREATE TABLE book (
477                   id          INTEGER PRIMARY KEY,
478                   title       TEXT ,
479                   rating      INTEGER
480           );
481           -- 'book_author' is a many-to-many join table between books & authors
482           CREATE TABLE book_author (
483                   book_id     INTEGER REFERENCES book(id) ON DELETE CASCADE ON UPDATE CASCADE,
484                   author_id   INTEGER REFERENCES author(id) ON DELETE CASCADE ON UPDATE CASCADE,
485                   PRIMARY KEY (book_id, author_id)
486           );
487           CREATE TABLE author (
488                   id          INTEGER PRIMARY KEY,
489                   first_name  TEXT,
490                   last_name   TEXT
491           );
492           ---
493           --- Load some sample data
494           ---
495           INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
496           INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
497           INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
498           INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
499           INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
500           INSERT INTO author VALUES (1, 'Greg', 'Bastien');
501           INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
502           INSERT INTO author VALUES (3, 'Christian', 'Degu');
503           INSERT INTO author VALUES (4, 'Richard', 'Stevens');
504           INSERT INTO author VALUES (5, 'Douglas', 'Comer');
505           INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
506           INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
507           INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
508           INSERT INTO book_author VALUES (1, 1);
509           INSERT INTO book_author VALUES (1, 2);
510           INSERT INTO book_author VALUES (1, 3);
511           INSERT INTO book_author VALUES (2, 4);
512           INSERT INTO book_author VALUES (3, 5);
513           INSERT INTO book_author VALUES (4, 6);
514           INSERT INTO book_author VALUES (4, 7);
515           INSERT INTO book_author VALUES (5, 8);
516
517       Then use the following command to build a "myapp.db" SQLite database:
518
519           $ sqlite3 myapp.db < myapp01.sql
520
521       If you need to create the database more than once, you probably want to
522       issue the "rm myapp.db" command to delete the database before you use
523       the "sqlite3 myapp.db < myapp01.sql" command.
524
525       Once the "myapp.db" database file has been created and initialized, you
526       can use the SQLite command line environment to do a quick dump of the
527       database contents:
528
529           $ sqlite3 myapp.db
530           SQLite version 3.6.22
531           Enter ".help" for instructions
532           Enter SQL statements terminated with a ";"
533           sqlite> select * from book;
534           1|CCSP SNRS Exam Certification Guide|5
535           2|TCP/IP Illustrated, Volume 1|5
536           3|Internetworking with TCP/IP Vol.1|4
537           4|Perl Cookbook|5
538           5|Designing with Web Standards|5
539           sqlite> .q
540           $
541
542       Or:
543
544           $ sqlite3 myapp.db "select * from book"
545           1|CCSP SNRS Exam Certification Guide|5
546           2|TCP/IP Illustrated, Volume 1|5
547           3|Internetworking with TCP/IP Vol.1|4
548           4|Perl Cookbook|5
549           5|Designing with Web Standards|5
550
551       As with most other SQL tools, if you are using the full "interactive"
552       environment you need to terminate your SQL commands with a ";" (it's
553       not required if you do a single SQL statement on the command line).
554       Use ".q" to exit from SQLite from the SQLite interactive mode and
555       return to your OS command prompt.
556
557       Please note that here we have chosen to use 'singular' table names.
558       This is because the default inflection code for older versions of
559       DBIx::Class::Schema::Loader does NOT handle plurals. There has been
560       much philosophical discussion on whether table names should be plural
561       or singular.  There is no one correct answer, as long as one makes a
562       choice and remains consistent with it. If you prefer plural table names
563       (e.g. you think that they are easier to read) then see the
564       documentation in "naming" in DBIx::Class::Schema::Loader::Base (version
565       0.05 or greater).
566
567       For using other databases, such as PostgreSQL or MySQL, see Appendix 2.
568

DATABASE ACCESS WITH DBIx::Class

570       Catalyst can be used with virtually any form of datastore available via
571       Perl.  For example, Catalyst::Model::DBI can be used to access
572       databases through the traditional Perl DBI interface or you can use a
573       model to access files of any type on the filesystem.  However, most
574       Catalyst applications use some form of object-relational mapping (ORM)
575       technology to create objects associated with tables in a relational
576       database.  Matt Trout's DBIx::Class (abbreviated as "DBIC") has rapidly
577       emerged as the Perl-based ORM technology of choice. Most new Catalyst
578       applications rely on DBIx::Class, as will this tutorial.
579
580       Although DBIx::Class has included support for a "create=dynamic" mode
581       to automatically read the database structure every time the application
582       starts, it's use is no longer recommended.  While it can make for
583       "flashy" demos, the use of the "create=static" mode we use below can be
584       implemented just as quickly and provides many advantages (such as the
585       ability to add your own methods to the overall DBIC framework, a
586       technique that we see in Chapter 4).
587
588   Make Sure You Have a Recent Version of the DBIx::Class Model
589       First, let's be sure we have a recent version of the DBIC helper,
590       Catalyst::Model::DBIC::Schema, so that we can take advantage of some
591       recent enhancements in how foreign keys are handled with SQLite.  To
592       check your version, run this command:
593
594           $ perl -MCatalyst::Model::DBIC::Schema -e \
595               'print "$Catalyst::Model::DBIC::Schema::VERSION\n"'
596           0.4
597
598       Please note the '\' above.  Depending on your environment, you might be
599       able to cut and paste the text as shown or need to remove the '\'
600       character to that the command is all on a single line.
601
602       If you are following along in Debian 5, you should have version 0.40 or
603       higher (shown above as "0.4" with the tailing zero removed). If you
604       have less than v0.39, you will need to run this command to install it
605       directly from CPAN:
606
607           $ sudo cpan Catalyst::Model::DBIC::Schema
608
609       And re-run the version print command to verify that you are now at 0.39
610       or higher.
611
612       In addition, since we are using SQLite's foreign key support here,
613       please be sure that you use version 1.27 of DBD::SQLite or later:
614
615           $ perl -MDBD::SQLite -e 'print "$DBD::SQLite::VERSION\n"'
616           1.29
617
618       Upgrade if you are not at version 1.27 or higher.
619
620   Create Static DBIx::Class Schema Files
621       Before you continue, make sure your "myapp.db" database file is in the
622       application's topmost directory. Now use the model helper with the
623       "create=static" option to read the database with
624       DBIx::Class::Schema::Loader and automatically build the required files
625       for us:
626
627           $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
628               create=static dbi:SQLite:myapp.db \
629               on_connect_do="PRAGMA foreign_keys = ON"
630            exists "/home/me/MyApp/script/../lib/MyApp/Model"
631            exists "/home/me/MyApp/script/../t"
632           Dumping manual schema for MyApp::Schema to directory /home/me/MyApp/script/../lib ...
633           Schema dump completed.
634           created "/home/me/MyApp/script/../lib/MyApp/Model/DB.pm"
635           created "/home/me/MyApp/script/../t/model_DB.t"
636
637       Please note the '\' above.  Depending on your environment, you might be
638       able to cut and paste the text as shown or need to remove the '\'
639       character to that the command is all on a single line.
640
641       The "script/myapp_create.pl" command breaks down like this:
642
643       ·   "DB" is the name of the model class to be created by the helper in
644           "lib/MyApp/Model".
645
646       ·   "DBIC::Schema" is the type of the model to create.
647
648       ·   "MyApp::Schema" is the name of the DBIC schema file written to
649           "lib/MyApp/Schema.pm".
650
651       ·   "create=static" causes DBIx::Class::Schema::Loader to load the
652           schema as it runs and then write that information out into files.
653
654       ·   "dbi:SQLite:myapp.db" is the standard DBI connect string for use
655           with SQLite.
656
657       ·   And finally, the "on_connect_do" string requests that
658           DBIx::Class::Schema::Loader create foreign key relationships for us
659           (this is not needed for databases such as PostgreSQL and MySQL, but
660           is required for SQLite). If you take a look at
661           "lib/MyApp/Model/DB.pm", you will see that the SQLite pragma is
662           propogated to the Model, so that SQLite's recent (and optional)
663           foreign key enforcement is enabled at the start of every database
664           connection.
665
666       If you look in the "lib/MyApp/Schema.pm" file, you will find that it
667       only contains a call to the "load_namespaces" method.  You will also
668       find that "lib/MyApp" contains a "Schema" subdirectory, which then has
669       a subdirectory called "Result".  This "Result" subdirectory then has
670       files named according to each of the tables in our simple database
671       ("Author.pm", "BookAuthor.pm", and "Book.pm").  These three files are
672       called "Result Classes" in DBIx::Class nomenclature. Although the
673       Result Class files are named after tables in our database, the classes
674       correspond to the row-level data that is returned by DBIC (more on this
675       later, especially in "EXPLORING THE POWER OF DBIC" in
676       Catalyst::Manual::Tutorial::04_BasicCRUD).
677
678       The idea with the Result Source files created under
679       "lib/MyApp/Schema/Result" by the "create=static" option is to only edit
680       the files below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!"  warning.
681       If you place all of your changes below that point in the file, you can
682       regenerate the automatically created information at the top of each
683       file should your database structure get updated.
684
685       Also note the "flow" of the model information across the various files
686       and directories.  Catalyst will initially load the model from
687       "lib/MyApp/Model/DB.pm".  This file contains a reference to
688       "lib/MyApp/Schema.pm", so that file is loaded next.  Finally, the call
689       to "load_namespaces" in "Schema.pm" will load each of the "Result
690       Class" files from the "lib/MyApp/Schema/Result" subdirectory.  The
691       final outcome is that Catalyst will dynamically create three table-
692       specific Catalyst models every time the application starts (you can see
693       these three model files listed in the debug output generated when you
694       launch the application).
695
696       NOTE: Older versions of Catalyst::Model::DBIC::Schema use the
697       deprecated DBIx::Class "load_classes" technique instead of the newer
698       "load_namspaces".  For new applications, please try to use
699       "load_namespaces" since it more easily supports a very useful DBIC
700       technique called "ResultSet Classes."  If you need to convert an
701       existing application from "load_classes" to "load_namespaces," you can
702       use this process to automate the migration, but first make sure you
703       have version 0.39 of Catalyst::Model::DBIC::Schema and
704       DBIx::Class::Schema::Loader version 0.05000 or later.
705
706           $ # Re-run the helper to upgrade for you
707           $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
708               create=static naming=current use_namespaces=1 \
709               dbi:SQLite:myapp.db \
710               on_connect_do="PRAGMA foreign_keys = ON"
711

ENABLE THE MODEL IN THE CONTROLLER

713       Open "lib/MyApp/Controller/Books.pm" and un-comment the model code we
714       left disabled earlier so that your version matches the following (un-
715       comment the line containing "[$c->model('DB::Book')->all]" and delete
716       the next 2 lines):
717
718           =head2 list
719
720           Fetch all book objects and pass to books/list.tt2 in stash to be displayed
721
722           =cut
723
724           sub list :Local {
725               # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
726               # 'Context' that's used to 'glue together' the various components
727               # that make up the application
728               my ($self, $c) = @_;
729
730               # Retrieve all of the book records as book model objects and store
731               # in the stash where they can be accessed by the TT template
732               $c->stash(books => [$c->model('DB::Book')->all]);
733
734               # Set the TT template to use.  You will almost always want to do this
735               # in your action methods (action methods respond to user input in
736               # your controllers).
737               $c->stash(template => 'books/list.tt2');
738           }
739
740       TIP: You may see the "$c->model('DB::Book')" un-commented above written
741       as "$c->model('DB')->resultset('Book')".  The two are equivalent.
742       Either way, "$c->model" returns a DBIx::Class::ResultSet which handles
743       queries against the database and iterating over the set of results that
744       is returned.
745
746       We are using the "->all" to fetch all of the books.  DBIC supports a
747       wide variety of more advanced operations to easily do things like
748       filtering and sorting the results.  For example, the following could be
749       used to sort the results by descending title:
750
751           $c->model('DB::Book')->search({}, {order_by => 'title DESC'});
752
753       Some other examples are provided in "Complex WHERE clauses" in
754       DBIx::Class::Manual::Cookbook, with additional information found at
755       "search" in DBIx::Class::ResultSet, "Searching" in
756       DBIx::Class::Manual::FAQ, DBIx::Class::Manual::Intro and
757       Catalyst::Model::DBIC::Schema.
758
759   Test Run The Application
760       First, let's enable an environment variable that causes DBIx::Class to
761       dump the SQL statements used to access the database.  This is a helpful
762       trick when you are trying to debug your database-oriented code.  Press
763       "Ctrl-C" to break out of the development server and enter:
764
765           $ export DBIC_TRACE=1
766           $ script/myapp_server.pl -r
767
768       This assumes you are using bash as your shell -- adjust accordingly if
769       you are using a different shell (for example, under tcsh, use "setenv
770       DBIC_TRACE 1").
771
772       NOTE: You can also set this in your code using
773       "$class->storage->debug(1);".  See DBIx::Class::Manual::Troubleshooting
774       for details (including options to log to a file instead of displaying
775       to the Catalyst development server log).
776
777       Then launch the Catalyst development server.  The log output should
778       display something like:
779
780           $ script/myapp_server.pl -r
781           [debug] Debug messages enabled
782           [debug] Statistics enabled
783           [debug] Loaded plugins:
784           .----------------------------------------------------------------------------.
785           | Catalyst::Plugin::ConfigLoader  0.27                                       |
786           | Catalyst::Plugin::StackTrace  0.11                                         |
787           '----------------------------------------------------------------------------'
788
789           [debug] Loaded dispatcher "Catalyst::Dispatcher"
790           [debug] Loaded engine "Catalyst::Engine::HTTP"
791           [debug] Found home "/home/me/MyApp"
792           [debug] Loaded Config "/home/me/MyApp/myapp.conf"
793           [debug] Loaded components:
794           .-----------------------------------------------------------------+----------.
795           | Class                                                           | Type     |
796           +-----------------------------------------------------------------+----------+
797           | MyApp::Controller::Books                                        | instance |
798           | MyApp::Controller::Root                                         | instance |
799           | MyApp::Model::DB                                                | instance |
800           | MyApp::Model::DB::Author                                        | class    |
801           | MyApp::Model::DB::Book                                          | class    |
802           | MyApp::Model::DB::BookAuthor                                    | class    |
803           | MyApp::View::TT                                                 | instance |
804           '-----------------------------------------------------------------+----------'
805
806           [debug] Loaded Private actions:
807           .----------------------+--------------------------------------+--------------.
808           | Private              | Class                                | Method       |
809           +----------------------+--------------------------------------+--------------+
810           | /default             | MyApp::Controller::Root              | default      |
811           | /end                 | MyApp::Controller::Root              | end          |
812           | /index               | MyApp::Controller::Root              | index        |
813           | /books/index         | MyApp::Controller::Books             | index        |
814           | /books/list          | MyApp::Controller::Books             | list         |
815           '----------------------+--------------------------------------+--------------'
816
817           [debug] Loaded Path actions:
818           .-------------------------------------+--------------------------------------.
819           | Path                                | Private                              |
820           +-------------------------------------+--------------------------------------+
821           | /                                   | /default                             |
822           | /                                   | /index                               |
823           | /books                              | /books/index                         |
824           | /books/list                         | /books/list                          |
825           '-------------------------------------+--------------------------------------'
826
827           [info] MyApp powered by Catalyst 5.80020
828           You can connect to your server at http://debian:3000
829
830       NOTE: Be sure you run the "script/myapp_server.pl" command from the
831       'base' directory of your application, not inside the "script" directory
832       itself or it will not be able to locate the "myapp.db" database file.
833       You can use a fully qualified or a relative path to locate the database
834       file, but we did not specify that when we ran the model helper earlier.
835
836       Some things you should note in the output above:
837
838       ·   Catalyst::Model::DBIC::Schema dynamically created three model
839           classes, one to represent each of the three tables in our database
840           ("MyApp::Model::DB::Author", "MyApp::Model::DB::BookAuthor", and
841           "MyApp::Model::DB::Book").
842
843       ·   The "list" action in our Books controller showed up with a path of
844           "/books/list".
845
846       Point your browser to <http://localhost:3000> and you should still get
847       the Catalyst welcome page.
848
849       Next, to view the book list, change the URL in your browser to
850       <http://localhost:3000/books/list>. You should get a list of the five
851       books loaded by the "myapp01.sql" script above without any formatting.
852       The rating for each book should appear on each row, but the "Author(s)"
853       column will still be blank (we will fill that in later).
854
855       Also notice in the output of the "script/myapp_server.pl" that
856       DBIx::Class used the following SQL to retrieve the data:
857
858           SELECT me.id, me.title, me.rating FROM book me
859
860       because we enabled DBIC_TRACE.
861
862       You now have the beginnings of a simple but workable web application.
863       Continue on to future sections and we will develop the application more
864       fully.
865

CREATE A WRAPPER FOR THE VIEW

867       When using TT, you can (and should) create a wrapper that will
868       literally wrap content around each of your templates.  This is
869       certainly useful as you have one main source for changing things that
870       will appear across your entire site/application instead of having to
871       edit many individual files.
872
873   Configure TT.pm For The Wrapper
874       In order to create a wrapper, you must first edit your TT view and tell
875       it where to find your wrapper file.
876
877       Edit you TT view in "lib/MyApp/View/TT.pm" and change it to match the
878       following:
879
880           __PACKAGE__->config(
881               # Change default TT extension
882               TEMPLATE_EXTENSION => '.tt2',
883               # Set the location for TT files
884               INCLUDE_PATH => [
885                       MyApp->path_to( 'root', 'src' ),
886                   ],
887               # Set to 1 for detailed timer stats in your HTML as comments
888               TIMER              => 0,
889               # This is your wrapper template located in the 'root/src'
890               WRAPPER => 'wrapper.tt2',
891           );
892
893   Create the Wrapper Template File and Stylesheet
894       Next you need to set up your wrapper template.  Basically, you'll want
895       to take the overall layout of your site and put it into this file.  For
896       the tutorial, open "root/src/wrapper.tt2" and input the following:
897
898           <?xml version="1.0" encoding="UTF-8"?>
899           <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
900           <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
901           <head>
902           <title>[% template.title or "My Catalyst App!" %]</title>
903           <link rel="stylesheet" href="[% c.uri_for('/static/css/main.css') %]" />
904           </head>
905
906           <body>
907           <div id="outer">
908           <div id="header">
909               [%# Your logo could go here -%]
910               <img src="[% c.uri_for('/static/images/btn_88x31_powered.png') %]" />
911               [%# Insert the page title -%]
912               <h1>[% template.title or site.title %]</h1>
913           </div>
914
915           <div id="bodyblock">
916           <div id="menu">
917               Navigation:
918               <ul>
919                   <li><a href="[% c.uri_for('/books/list') %]">Home</a></li>
920                   <li><a href="[% c.uri_for('/') %]" title="Catalyst Welcome Page">Welcome</a></li>
921               </ul>
922           </div><!-- end menu -->
923
924           <div id="content">
925               [%# Status and error messages %]
926               <span class="message">[% status_msg %]</span>
927               <span class="error">[% error_msg %]</span>
928               [%# This is where TT will stick all of your template's contents. -%]
929               [% content %]
930           </div><!-- end content -->
931           </div><!-- end bodyblock -->
932
933           <div id="footer">Copyright (c) your name goes here</div>
934           </div><!-- end outer -->
935
936           </body>
937           </html>
938
939       Notice the status and error message sections in the code above:
940
941           <span class="status">[% status_msg %]</span>
942           <span class="error">[% error_msg %]</span>
943
944       If we set either message in the Catalyst stash (e.g.,
945       "$c->stash->{status_msg} = 'Request was successful!'") it will be
946       displayed whenever any view used by that request is rendered.  The
947       "message" and "error" CSS styles can be customized to suit your needs
948       in the "root/static/css/main.css" file we create below.
949
950       Notes:
951
952       ·   The Catalyst stash only lasts for a single HTTP request.  If you
953           need to retain information across requests you can use
954           Catalyst::Plugin::Session (we will use Catalyst sessions in the
955           Authentication chapter of the tutorial).
956
957       ·   Although it is beyond the scope of this tutorial, you may wish to
958           use a JavaScript or AJAX tool such as jQuery
959           (<http://www.jquery.com>) or Dojo (<http://www.dojotoolkit.org>).
960
961       Create A Basic Stylesheet
962
963       First create a central location for stylesheets under the static
964       directory:
965
966           $ mkdir root/static/css
967
968       Then open the file "root/static/css/main.css" (the file referenced in
969       the stylesheet href link of our wrapper above) and add the following
970       content:
971
972           #header {
973               text-align: center;
974           }
975           #header h1 {
976               margin: 0;
977           }
978           #header img {
979               float: right;
980           }
981           #footer {
982               text-align: center;
983               font-style: italic;
984               padding-top: 20px;
985           }
986           #menu {
987               font-weight: bold;
988               background-color: #ddd;
989           }
990           #menu ul {
991               list-style: none;
992               float: left;
993               margin: 0;
994               padding: 0 0 50% 5px;
995               font-weight: normal;
996               background-color: #ddd;
997               width: 100px;
998           }
999           #content {
1000               margin-left: 120px;
1001           }
1002           .message {
1003               color: #390;
1004           }
1005           .error {
1006               color: #f00;
1007           }
1008
1009       You may wish to check out a "CSS Framework" like Emastic
1010       (<http://code.google.com/p/emastic/>) as a way to quickly provide lots
1011       of high-quality CSS functionality.
1012
1013   Test Run The Application
1014       Hit "Reload" in your web browser and you should now see a formatted
1015       version of our basic book list. (Again, the development server should
1016       have automatically restarted when you made changes to
1017       "lib/MyApp/View/TT.pm". If you are not using the "-r" option, you will
1018       need to hit "Ctrl-C" and manually restart it. Also note that the
1019       development server does NOT need to restart for changes to the TT and
1020       static files we created and edited in the "root" directory -- those
1021       updates are handled on a per-request basis.)
1022
1023       Although our wrapper and stylesheet are obviously very simple, you
1024       should see how it allows us to control the overall look of an entire
1025       website from two central files. To add new pages to the site, just
1026       provide a template that fills in the "content" section of our wrapper
1027       template -- the wrapper will provide the overall feel of the page.
1028
1029   Updating the Generated DBIx::Class Result Class Files
1030       If you take a look at the Schema files automatically generated by
1031       DBIx::Class::Schema::Loader, you will see that it has already defined
1032       "has_many" and "belongs_to" relationships on each side of our foreign
1033       keys. For example, take a look at "lib/MyApp/Schema/Result/Book.pm" and
1034       notice the following code:
1035
1036           =head1 RELATIONS
1037
1038           =head2 book_authors
1039
1040           Type: has_many
1041
1042           Related object: L<MyApp::Schema::Result::BookAuthor>
1043
1044           =cut
1045
1046           __PACKAGE__->has_many(
1047             "book_authors",
1048             "MyApp::Schema::Result::BookAuthor",
1049             { "foreign.book_id" => "self.id" },
1050           );
1051
1052       Each "Book" "has_many" "book_authors", where "BookAuthor" is the many-
1053       to-many table that allows each Book to have multiple Authors, and each
1054       Author to have mulitple books.  The arguments to "has_many" are:
1055
1056       ·   "book_authors" - The name for this relationship.  DBIC will create
1057           an accessor on the "Books" DBIC Row object with this name.
1058
1059       ·   "MyApp::Schema::Result::BookAuthor" - The name of the DBIC model
1060           class referenced by this "has_many" relationship.
1061
1062       ·   "foreign.book_id" - "book_id" is the name of the foreign key column
1063           in the foreign table that points back to this table.
1064
1065       ·   "self.id" - "id" is the name of the column in this table that is
1066           referenced by the foreign key.
1067
1068       See "has_many" in DBIx::Class::Relationship for additional information.
1069       Note that you might see a "hand coded" version of the "has_many"
1070       relationship above expressed as:
1071
1072           __PACKAGE__->has_many(
1073             "book_authors",
1074             "MyApp::Schema::Result::BookAuthor",
1075             "book_id",
1076           );
1077
1078       Where the third argument is simply the name of the column in the
1079       foreign table.  However, the hashref syntax used by
1080       DBIx::Class::Schema::Loader is more flexible (for example, it can
1081       handle "multi-column" foreign keys).
1082
1083       Note: If you are using older versions of SQLite and related DBIC tools,
1084       you will need to manually define your "has_many" and "belongs_to"
1085       relationships. We recommend upgrading to the versions specified above.
1086       :-)
1087
1088       Have a look at "lib/MyApp/Schema/Result/BookAuthor.pm" and notice that
1089       there is a "belongs_to" relationship defined that acts as the "mirror
1090       image" to the "has_many" relationship we just looked at above:
1091
1092           =head1 RELATIONS
1093
1094           =head2 book
1095
1096           Type: belongs_to
1097
1098           Related object: L<MyApp::Schema::Result::Book>
1099
1100           =cut
1101
1102           __PACKAGE__->belongs_to(
1103             "book",
1104             "MyApp::Schema::Result::Book",
1105             { id => "book_id" },
1106             { join_type => "LEFT" },
1107           );
1108
1109       The arguments are similar, but see "belongs_to" in
1110       DBIx::Class::Relationship for the details.
1111
1112       Although recent versions of SQLite and DBIx::Class::Schema::Loader
1113       automatically handle the "has_many" and "belongs_to" relationships,
1114       "many_to_many" relationships currently need to be manually inserted.
1115       To add a "many_to_many" relationship, first edit
1116       "lib/MyApp/Schema/Result/Book.pm" and add the following text below the
1117       "# You can replace this text..." comment:
1118
1119           # many_to_many():
1120           #   args:
1121           #     1) Name of relationship, DBIC will create accessor with this name
1122           #     2) Name of has_many() relationship this many_to_many() is shortcut for
1123           #     3) Name of belongs_to() relationship in model class of has_many() above
1124           #   You must already have the has_many() defined to use a many_to_many().
1125           __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
1126
1127       Note: Be careful to put this code above the "1;" at the end of the
1128       file.  As with any Perl package, we need to end the last line with a
1129       statement that evaluates to "true".  This is customarily done with "1;"
1130       on a line by itself.
1131
1132       The "many_to_many" relationship is optional, but it makes it easier to
1133       map a book to its collection of authors.  Without it, we would have to
1134       "walk" though the "book_author" table as in
1135       "$book->book_author->first->author->last_name" (we will see examples on
1136       how to use DBIx::Class objects in your code soon, but note that because
1137       "$book->book_author" can return multiple authors, we have to use
1138       "first" to display a single author).  "many_to_many" allows us to use
1139       the shorter "$book->author->first->last_name". Note that you cannot
1140       define a "many_to_many" relationship without also having the "has_many"
1141       relationship in place.
1142
1143       Then edit "lib/MyApp/Schema/Result/Author.pm" and add the reverse
1144       "many_to_many" relationship for "Author" as follows (again, be careful
1145       to put in above the "1;" but below the "# DO NOT MODIFY THIS OR
1146       ANYTHING ABOVE!" comment):
1147
1148           # many_to_many():
1149           #   args:
1150           #     1) Name of relationship, DBIC will create accessor with this name
1151           #     2) Name of has_many() relationship this many_to_many() is shortcut for
1152           #     3) Name of belongs_to() relationship in model class of has_many() above
1153           #   You must already have the has_many() defined to use a many_to_many().
1154           __PACKAGE__->many_to_many(books => 'book_authors', 'book');
1155
1156   Run The Application
1157       Run the Catalyst development server script with the "DBIC_TRACE" option
1158       (it might still be enabled from earlier in the tutorial, but here is an
1159       alternate way to specify the trace option just in case):
1160
1161           $ DBIC_TRACE=1 script/myapp_server.pl -r
1162
1163       Make sure that the application loads correctly and that you see the
1164       three dynamically created model class (one for each of the Result
1165       Classes we created).
1166
1167       Then hit the URL <http://localhost:3000/books/list> with your browser
1168       and be sure that the book list still displays correctly.
1169
1170       Note: You will not see the authors yet because the view does not yet
1171       use the new relations. Read on to the next section where we update the
1172       template to do that.
1173

UPDATING THE VIEW

1175       Let's add a new column to our book list page that takes advantage of
1176       the relationship information we manually added to our schema files in
1177       the previous section.  Edit "root/src/books/list.tt2" and replace the
1178       "empty" table cell "<td></td>" with the following:
1179
1180           ...
1181           <td>
1182             [% # NOTE: See Chapter 4 for a better way to do this!                      -%]
1183             [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
1184             [% # loop in 'side effect notation' to load just the last names of the     -%]
1185             [% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
1186             [% # a value, so nothing will be printed here.  But, if you have something -%]
1187             [% # in TT that does return a value and you don't want it printed, you     -%]
1188             [% # 1) assign it to a bogus value, or                                     -%]
1189             [% # 2) use the CALL keyword to call it and discard the return value.      -%]
1190             [% tt_authors = [ ];
1191                tt_authors.push(author.last_name) FOREACH author = book.authors %]
1192             [% # Now use a TT 'virtual method' to display the author count in parens   -%]
1193             [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
1194             ([% tt_authors.size | html %])
1195             [% # Use another TT vmethod to join & print the names & comma separators   -%]
1196             [% tt_authors.join(', ') | html %]
1197           </td>
1198           ...
1199
1200       IMPORTANT NOTE: Again, you should keep as much "logic code" as possible
1201       out of your views.  This kind of logic belongs in your model (the same
1202       goes for controllers -- keep them as "thin" as possible and push all of
1203       the "complicated code" out to your model objects).  Avoid code like you
1204       see in the previous example -- we are only using it here to show some
1205       extra features in TT until we get to the more advanced model features
1206       we will see in Chapter 4 (see "EXPLORING THE POWER OF DBIC" in
1207       Catalyst::Manual::Tutorial::04_BasicCRUD).
1208
1209       Then hit "Reload" in your browser (note that you don't need to reload
1210       the development server or use the "-r" option when updating TT
1211       templates) and you should now see the number of authors each book has
1212       along with a comma-separated list of the authors' last names.  (If you
1213       didn't leave the development server running from the previous step, you
1214       will obviously need to start it before you can refresh your browser
1215       window.)
1216
1217       If you are still running the development server with "DBIC_TRACE"
1218       enabled, you should also now see five more "SELECT" statements in the
1219       debug output (one for each book as the authors are being retrieved by
1220       DBIx::Class):
1221
1222           SELECT me.id, me.title, me.rating FROM book me:
1223           SELECT author.id, author.first_name, author.last_name FROM book_author me
1224           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '1'
1225           SELECT author.id, author.first_name, author.last_name FROM book_author me
1226           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '2'
1227           SELECT author.id, author.first_name, author.last_name FROM book_author me
1228           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '3'
1229           SELECT author.id, author.first_name, author.last_name FROM book_author me
1230           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '4'
1231           SELECT author.id, author.first_name, author.last_name FROM book_author me
1232           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '5'
1233
1234       Also note in "root/src/books/list.tt2" that we are using "| html", a
1235       type of TT filter, to escape characters such as < and > to &lt; and
1236       &gt; and avoid various types of dangerous hacks against your
1237       application.  In a real application, you would probably want to put "|
1238       html" at the end of every field where a user has control over the
1239       information that can appear in that field (and can therefore inject
1240       markup or code if you don't "neutralize" those fields).  In addition to
1241       "| html", Template Toolkit has a variety of other useful filters that
1242       can found in the documentation for Template::Filters.
1243

RUNNING THE APPLICATION FROM THE COMMAND LINE

1245       In some situations, it can be useful to run your application and
1246       display a page without using a browser.  Catalyst lets you do this
1247       using the "scripts/myapp_test.pl" script.  Just supply the URL you wish
1248       to display and it will run that request through the normal controller
1249       dispatch logic and use the appropriate view to render the output
1250       (obviously, complex pages may dump a lot of text to your terminal
1251       window).  For example, if you type:
1252
1253           $ script/myapp_test.pl "/books/list"
1254
1255       You should get the same text as if you visited
1256       <http://localhost:3000/books/list> with the normal development server
1257       and asked your browser to view the page source.
1258

OPTIONAL INFORMATION

1260       NOTE: The rest of this chapter of the tutorial is optional.  You can
1261       skip to Chapter 4, Basic CRUD, if you wish.
1262
1263   Using 'RenderView' for the Default View
1264       Once your controller logic has processed the request from a user, it
1265       forwards processing to your view in order to generate the appropriate
1266       response output.  Catalyst uses Catalyst::Action::RenderView by default
1267       to automatically perform this operation.  If you look in
1268       "lib/MyApp/Controller/Root.pm", you should see the empty definition for
1269       the "sub end" method:
1270
1271           sub end : ActionClass('RenderView') {}
1272
1273       The following bullet points provide a quick overview of the
1274       "RenderView" process:
1275
1276       ·   "Root.pm" is designed to hold application-wide logic.
1277
1278       ·   At the end of a given user request, Catalyst will call the most
1279           specific "end" method that's appropriate.  For example, if the
1280           controller for a request has an "end" method defined, it will be
1281           called.  However, if the controller does not define a controller-
1282           specific "end" method, the "global" "end" method in "Root.pm" will
1283           be called.
1284
1285       ·   Because the definition includes an "ActionClass" attribute, the
1286           Catalyst::Action::RenderView logic will be executed after any code
1287           inside the definition of "sub end" is run.  See
1288           Catalyst::Manual::Actions for more information on "ActionClass".
1289
1290       ·   Because "sub end" is empty, this effectively just runs the default
1291           logic in "RenderView".  However, you can easily extend the
1292           "RenderView" logic by adding your own code inside the empty method
1293           body ("{}") created by the Catalyst Helpers when we first ran the
1294           "catalyst.pl" to initialize our application.  See
1295           Catalyst::Action::RenderView for more detailed information on how
1296           to extend "RenderView" in "sub end".
1297
1298   RenderView's "dump_info" Feature
1299       One of the nice features of "RenderView" is that it automatically
1300       allows you to add "dump_info=1" to the end of any URL for your
1301       application and it will force the display of the "exception dump"
1302       screen to the client browser.  You can try this out by pointing your
1303       browser to this URL:
1304
1305           http://localhost:3000/books/list?dump_info=1
1306
1307       You should get a page with the following message at the top:
1308
1309           Caught exception in MyApp::Controller::Root->end "Forced debug -
1310           Scrubbed output at /usr/share/perl5/Catalyst/Action/RenderView.pm line 46."
1311
1312       Along with a summary of your application's state at the end of the
1313       processing for that request.  The "Stash" section should show a
1314       summarized version of the DBIC book model objects.  If desired, you can
1315       adjust the summarization logic (called "scrubbing" logic) -- see
1316       Catalyst::Action::RenderView for details.
1317
1318       Note that you shouldn't need to worry about "normal clients" using this
1319       technique to "reverse engineer" your application -- "RenderView" only
1320       supports the "dump_info=1" feature when your application is running in
1321       "-Debug" mode (something you won't do once you have your application
1322       deployed in production).
1323
1324   Using The Default Template Name
1325       By default, "Catalyst::View::TT" will look for a template that uses the
1326       same name as your controller action, allowing you to save the step of
1327       manually specifying the template name in each action.  For example,
1328       this would allow us to remove the "$c->stash->{template} =
1329       'books/list.tt2';" line of our "list" action in the Books controller.
1330       Open "lib/MyApp/Controller/Books.pm" in your editor and comment out
1331       this line to match the following (only the "$c->stash->{template}" line
1332       has changed):
1333
1334           =head2 list
1335
1336           Fetch all book objects and pass to books/list.tt2 in stash to be displayed
1337
1338           =cut
1339
1340           sub list :Local {
1341               # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
1342               # 'Context' that's used to 'glue together' the various components
1343               # that make up the application
1344               my ($self, $c) = @_;
1345
1346               # Retrieve all of the book records as book model objects and store in the
1347               # stash where they can be accessed by the TT template
1348               $c->stash(books => [$c->model('DB::Book')->all]);
1349
1350               # Set the TT template to use.  You will almost always want to do this
1351               # in your action methods (actions methods respond to user input in
1352               # your controllers).
1353               #$c->stash(template => 'books/list.tt2');
1354           }
1355
1356       You should now be able to access the <http://localhost:3000/books/list>
1357       URL as before.
1358
1359       NOTE: Please note that if you use the default template technique, you
1360       will not be able to use either the "$c->forward" or the "$c->detach"
1361       mechanisms (these are discussed in Chapter 2 and Chapter 9 of the
1362       Tutorial).
1363
1364       IMPORTANT: Make sure that you do NOT skip the following section before
1365       continuing to the next chapter 4 Basic CRUD.
1366
1367   Return To A Manually Specified Template
1368       In order to be able to use "$c->forward" and "$c->detach" later in the
1369       tutorial, you should remove the comment from the statement in "sub
1370       list" in "lib/MyApp/Controller/Books.pm":
1371
1372           $c->stash(template => 'books/list.tt2');
1373
1374       Then delete the "TEMPLATE_EXTENSION" line in "lib/MyApp/View/TT.pm".
1375
1376       Check the <http://localhost:3000/books/list> URL in your browser.  It
1377       should look the same manner as with earlier sections.
1378

AUTHOR

1380       Kennedy Clark, "hkclark@gmail.com"
1381
1382       Please report any errors, issues or suggestions to the author.  The
1383       most recent version of the Catalyst Tutorial can be found at
1384       http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/
1385       <http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-
1386       Manual/5.80/trunk/lib/Catalyst/Manual/Tutorial/>.
1387
1388       Copyright 2006-2008, Kennedy Clark, under Creative Commons License
1389       (http://creativecommons.org/licenses/by-sa/3.0/us/
1390       <http://creativecommons.org/licenses/by-sa/3.0/us/>).
1391
1392
1393
1394perl v5.12.0              Catalyst2:0:1M0a-n0u2a-l1:7:Tutorial::03_MoreCatalystBasics(3)
Impressum