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       Source code for the tutorial in included in the /home/catalyst/Final
44       directory of the Tutorial Virtual machine (one subdirectory per
45       chapter).  There are also instructions for downloading the code in
46       Catalyst::Manual::Tutorial::01_Intro.
47
48       Please take a look at "STARTING WITH THE TUTORIAL VIRTUAL MACHINE" in
49       Catalyst::Manual::Tutorial::01_Intro before doing the rest of this
50       tutorial.  Although the tutorial should work correctly under most any
51       recent version of Perl running on any operating system, the tutorial
52       has been written using the virtual machine that is available for
53       download.  The entire tutorial has been tested to be sure it runs
54       correctly in this environment, so it is the most trouble-free way to
55       get started with Catalyst.
56

CREATE A NEW APPLICATION

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

EDIT THE LIST OF CATALYST PLUGINS

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

CREATE A CATALYST CONTROLLER

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

CATALYST VIEWS

349       As mentioned in Chapter 2 of the tutorial, views are where you render
350       output, typically for display in the user's web browser (but can
351       generate other types of output such as PDF or JSON).  The code in
352       "lib/MyApp/View" selects the type of view to use, with the actual
353       rendering template found in the "root" directory.  As with virtually
354       every aspect of Catalyst, options abound when it comes to the specific
355       view technology you adopt inside your application. However, most
356       Catalyst applications use the Template Toolkit, known as TT (for more
357       information on TT, see <http://www.template-toolkit.org>). Other
358       somewhat popular view technologies include Mason
359       (<http://www.masonhq.com> and <http://www.masonbook.com>) and
360       HTML::Template (<http://html-template.sourceforge.net>).
361
362   Create a Catalyst View
363       When using TT for the Catalyst view, the main helper script is
364       Catalyst::Helper::View::TT.  You may also come across references to
365       Catalyst::Helper::View::TTSite, but its use is now deprecated.
366
367       For our book application, enter the following command to enable the
368       "TT" style of view rendering:
369
370           $ script/myapp_create.pl view HTML TT
371            exists "/home/catalyst/MyApp/script/../lib/MyApp/View"
372            exists "/home/catalyst/MyApp/script/../t"
373            created "/home/catalyst/MyApp/script/../lib/MyApp/View/HTML.pm"
374            created "/home/catalyst/MyApp/script/../t/view_HTML.t"
375
376       This creates a view called "HTML" (the first argument) in a file called
377       "HTML.pm" that uses Catalyst::View::TT (the second argument) as the
378       "rendering engine".
379
380       It is now up to you to decide how you want to structure your view
381       layout.  For the tutorial, we will start with a very simple TT template
382       to initially demonstrate the concepts, but quickly migrate to a more
383       typical "wrapper page" type of configuration (where the "wrapper"
384       controls the overall "look and feel" of your site from a single file or
385       set of files).
386
387       Edit "lib/MyApp/View/HTML.pm" and you should see something similar to
388       the following:
389
390           __PACKAGE__->config(
391               TEMPLATE_EXTENSION => '.tt',
392               render_die => 1,
393           );
394
395       And update it to match:
396
397           __PACKAGE__->config(
398               # Change default TT extension
399               TEMPLATE_EXTENSION => '.tt2',
400               render_die => 1,
401           );
402
403       This changes the default extension for Template Toolkit from '.tt' to
404       '.tt2'.
405
406       You can also configure components in your application class. For
407       example, Edit "lib/MyApp.pm" and you should see the default
408       configuration above the call to "_PACKAGE__->setup" (your defaults
409       could be different depending on the version of Catalyst you are using):
410
411           __PACKAGE__->config(
412               name => 'MyApp',
413               # Disable deprecated behavior needed by old applications
414               disable_component_resolution_regex_fallback => 1,
415           );
416
417       Change this to match the following (insert a new "__PACKAGE__->config"
418       below the existing statement):
419
420           __PACKAGE__->config(
421               name => 'MyApp',
422               # Disable deprecated behavior needed by old applications
423               disable_component_resolution_regex_fallback => 1,
424           );
425           __PACKAGE__->config(
426               # Configure the view
427               'View::HTML' => {
428                   #Set the location for TT files
429                   INCLUDE_PATH => [
430                       __PACKAGE__->path_to( 'root', 'src' ),
431                   ],
432               },
433           );
434
435       This changes the base directory for your template files from "root" to
436       "root/src".
437
438       Please stick with the settings above for the duration of the tutorial,
439       but feel free to use whatever options you desire in your applications
440       (as with most things in Perl, there's more than one way to do it...).
441
442       Note: We will use "root/src" as the base directory for our template
443       files, with a full naming convention of
444       "root/src/_controller_name_/_action_name_.tt2".  Another popular option
445       is to use "root/" as the base (with a full filename pattern of
446       "root/_controller_name_/_action_name_.tt2").
447
448   Create a TT Template Page
449       First create a directory for book-related TT templates:
450
451           $ mkdir -p root/src/books
452
453       Then create "root/src/books/list.tt2" in your editor and enter:
454
455           [% # This is a TT comment. -%]
456
457           [%- # Provide a title -%]
458           [% META title = 'Book List' -%]
459
460           [% # Note That the '-' at the beginning or end of TT code  -%]
461           [% # "chomps" the whitespace/newline at that end of the    -%]
462           [% # output (use View Source in browser to see the effect) -%]
463
464           [% # Some basic HTML with a loop to display books -%]
465           <table>
466           <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
467           [% # Display each book in a table row %]
468           [% FOREACH book IN books -%]
469             <tr>
470               <td>[% book.title %]</td>
471               <td>[% book.rating %]</td>
472               <td></td>
473             </tr>
474           [% END -%]
475           </table>
476
477       As indicated by the inline comments above, the "META title" line uses
478       TT's META feature to provide a title to the "wrapper" that we will
479       create later (and essentially does nothing at the moment). Meanwhile,
480       the "FOREACH" loop iterates through each "book" model object and prints
481       the "title" and "rating" fields.
482
483       The "[%" and "%]" tags are used to delimit Template Toolkit code.  TT
484       supports a wide variety of directives for "calling" other files,
485       looping, conditional logic, etc.  In general, TT simplifies the usual
486       range of Perl operators down to the single dot (".") operator.  This
487       applies to operations as diverse as method calls, hash lookups, and
488       list index values (see Template::Manual::Variables for details and
489       examples).  In addition to the usual Template::Toolkit module Pod
490       documentation, you can access the TT manual at
491       <https://metacpan.org/module/Template::Manual>.
492
493       TIP: While you can build all sorts of complex logic into your TT
494       templates, you should in general keep the "code" part of your templates
495       as simple as possible.  If you need more complex logic, create helper
496       methods in your model that abstract out a set of code into a single
497       call from your TT template.  (Note that the same is true of your
498       controller logic as well -- complex sections of code in your
499       controllers should often be pulled out and placed into your model
500       objects.)  In Chapter 4 of the tutorial we will explore some extremely
501       helpful and powerful features of DBIx::Class that allow you to pull
502       code out of your views and controllers and place it where it rightfully
503       belongs in a model class.
504
505   Test Run The Application
506       To test your work so far, first start the development server:
507
508           $ script/myapp_server.pl -r
509
510       Then point your browser to <http://localhost:3000> and you should still
511       get the Catalyst welcome page.  Next, change the URL in your browser to
512       <http://localhost:3000/books/list>.  If you have everything working so
513       far, you should see a web page that displays nothing other than our
514       column headers for "Title", "Rating", and "Author(s)" -- we will not
515       see any books until we get the database and model working below.
516
517       If you run into problems getting your application to run correctly, it
518       might be helpful to refer to some of the debugging techniques covered
519       in the Debugging chapter of the tutorial.
520

CREATE A SQLITE DATABASE

522       In this step, we make a text file with the required SQL commands to
523       create a database table and load some sample data.  We will use SQLite
524       (<http://www.sqlite.org>), a popular database that is lightweight and
525       easy to use. Be sure to get at least version 3. Open "myapp01.sql" in
526       your editor and enter:
527
528           --
529           -- Create a very simple database to hold book and author information
530           --
531           PRAGMA foreign_keys = ON;
532           CREATE TABLE book (
533                   id          INTEGER PRIMARY KEY,
534                   title       TEXT ,
535                   rating      INTEGER
536           );
537           -- 'book_author' is a many-to-many join table between books & authors
538           CREATE TABLE book_author (
539                   book_id     INTEGER REFERENCES book(id) ON DELETE CASCADE ON UPDATE CASCADE,
540                   author_id   INTEGER REFERENCES author(id) ON DELETE CASCADE ON UPDATE CASCADE,
541                   PRIMARY KEY (book_id, author_id)
542           );
543           CREATE TABLE author (
544                   id          INTEGER PRIMARY KEY,
545                   first_name  TEXT,
546                   last_name   TEXT
547           );
548           ---
549           --- Load some sample data
550           ---
551           INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
552           INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
553           INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
554           INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
555           INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
556           INSERT INTO author VALUES (1, 'Greg', 'Bastien');
557           INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
558           INSERT INTO author VALUES (3, 'Christian', 'Degu');
559           INSERT INTO author VALUES (4, 'Richard', 'Stevens');
560           INSERT INTO author VALUES (5, 'Douglas', 'Comer');
561           INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
562           INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
563           INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
564           INSERT INTO book_author VALUES (1, 1);
565           INSERT INTO book_author VALUES (1, 2);
566           INSERT INTO book_author VALUES (1, 3);
567           INSERT INTO book_author VALUES (2, 4);
568           INSERT INTO book_author VALUES (3, 5);
569           INSERT INTO book_author VALUES (4, 6);
570           INSERT INTO book_author VALUES (4, 7);
571           INSERT INTO book_author VALUES (5, 8);
572
573       Then use the following command to build a "myapp.db" SQLite database:
574
575           $ sqlite3 myapp.db < myapp01.sql
576
577       If you need to create the database more than once, you probably want to
578       issue the "rm myapp.db" command to delete the database before you use
579       the "sqlite3 myapp.db < myapp01.sql" command.
580
581       Once the "myapp.db" database file has been created and initialized, you
582       can use the SQLite command line environment to do a quick dump of the
583       database contents:
584
585           $ sqlite3 myapp.db
586           SQLite version 3.7.3
587           Enter ".help" for instructions
588           Enter SQL statements terminated with a ";"
589           sqlite> select * from book;
590           1|CCSP SNRS Exam Certification Guide|5
591           2|TCP/IP Illustrated, Volume 1|5
592           3|Internetworking with TCP/IP Vol.1|4
593           4|Perl Cookbook|5
594           5|Designing with Web Standards|5
595           sqlite> .q
596           $
597
598       Or:
599
600           $ sqlite3 myapp.db "select * from book"
601           1|CCSP SNRS Exam Certification Guide|5
602           2|TCP/IP Illustrated, Volume 1|5
603           3|Internetworking with TCP/IP Vol.1|4
604           4|Perl Cookbook|5
605           5|Designing with Web Standards|5
606
607       As with most other SQL tools, if you are using the full "interactive"
608       environment you need to terminate your SQL commands with a ";" (it's
609       not required if you do a single SQL statement on the command line).
610       Use ".q" to exit from SQLite from the SQLite interactive mode and
611       return to your OS command prompt.
612
613       Please note that here we have chosen to use 'singular' table names.
614       This is because the default inflection code for older versions of
615       DBIx::Class::Schema::Loader does NOT handle plurals. There has been
616       much philosophical discussion on whether table names should be plural
617       or singular.  There is no one correct answer, as long as one makes a
618       choice and remains consistent with it. If you prefer plural table names
619       (e.g.  you think that they are easier to read) then see the
620       documentation in "naming" in DBIx::Class::Schema::Loader::Base (version
621       0.05 or greater).
622
623       For using other databases, such as PostgreSQL or MySQL, see Appendix 2.
624

DATABASE ACCESS WITH DBIx::Class

626       Catalyst can be used with virtually any form of datastore available via
627       Perl.  For example, Catalyst::Model::DBI can be used to access
628       databases through the traditional Perl DBI interface or you can use a
629       model to access files of any type on the filesystem.  However, most
630       Catalyst applications use some form of object-relational mapping (ORM)
631       technology to create objects associated with tables in a relational
632       database, and Matt Trout's DBIx::Class (abbreviated as "DBIC") is the
633       usual choice (this tutorial will use DBIx::Class).
634
635       Although DBIx::Class has included support for a "create=dynamic" mode
636       to automatically read the database structure every time the application
637       starts, its use is no longer recommended.  While it can make for
638       "flashy" demos, the use of the "create=static" mode we use below can be
639       implemented just as quickly and provides many advantages (such as the
640       ability to add your own methods to the overall DBIC framework, a
641       technique that we see in Chapter 4).
642
643   Create Static DBIx::Class Schema Files
644       Note: If you are not following along in the Tutorial Virtual Machine,
645       please be sure that you have version 1.27 or higher of DBD::SQLite and
646       version 0.39 or higher of Catalyst::Model::DBIC::Schema.  (The Tutorial
647       VM already has versions that are known to work.)  You can get your
648       currently installed version numbers with the following commands.
649
650           $ perl -MCatalyst::Model::DBIC::Schema\ 999
651           $ perl -MDBD::SQLite\ 999
652
653       Before you continue, make sure your "myapp.db" database file is in the
654       application's topmost directory. Now use the model helper with the
655       "create=static" option to read the database with
656       DBIx::Class::Schema::Loader and automatically build the required files
657       for us:
658
659           $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
660               create=static dbi:SQLite:myapp.db \
661               on_connect_do="PRAGMA foreign_keys = ON"
662            exists "/home/catalyst/MyApp/script/../lib/MyApp/Model"
663            exists "/home/catalyst/MyApp/script/../t"
664           Dumping manual schema for MyApp::Schema to directory /home/catalyst/MyApp/script/../lib ...
665           Schema dump completed.
666           created "/home/catalyst/MyApp/script/../lib/MyApp/Model/DB.pm"
667           created "/home/catalyst/MyApp/script/../t/model_DB.t"
668
669       Please note the '\' above.  Depending on your environment, you might be
670       able to cut and paste the text as shown or need to remove the '\'
671       character to that the command is all on a single line.
672
673       The "script/myapp_create.pl" command breaks down like this:
674
675       ·   "DB" is the name of the model class to be created by the helper in
676           the "lib/MyApp/Model" directory.
677
678       ·   "DBIC::Schema" is the type of the model to create.  This equates to
679           Catalyst::Model::DBIC::Schema, the standard way to use a DBIC-based
680           model inside of Catalyst.
681
682       ·   "MyApp::Schema" is the name of the DBIC schema file written to
683           "lib/MyApp/Schema.pm".
684
685       ·   "create=static" causes DBIx::Class::Schema::Loader to load the
686           schema as it runs and then write that information out into
687           "lib/MyApp/Schema.pm" and files under the "lib/MyApp/Schema"
688           directory.
689
690       ·   "dbi:SQLite:myapp.db" is the standard DBI connect string for use
691           with SQLite.
692
693       ·   And finally, the "on_connect_do" string requests that
694           DBIx::Class::Schema::Loader create foreign key relationships for us
695           (this is not needed for databases such as PostgreSQL and MySQL, but
696           is required for SQLite). If you take a look at
697           "lib/MyApp/Model/DB.pm", you will see that the SQLite pragma is
698           propagated to the Model, so that SQLite's recent (and optional)
699           foreign key enforcement is enabled at the start of every database
700           connection.
701
702       If you look in the "lib/MyApp/Schema.pm" file, you will find that it
703       only contains a call to the "load_namespaces" method.  You will also
704       find that "lib/MyApp" contains a "Schema" subdirectory, which then has
705       a subdirectory called "Result".  This "Result" subdirectory then has
706       files named according to each of the tables in our simple database
707       ("Author.pm", "BookAuthor.pm", and "Book.pm").  These three files are
708       called "Result Classes" (or "ResultSource Classes") in DBIx::Class
709       nomenclature. Although the Result Class files are named after tables in
710       our database, the classes correspond to the row-level data that is
711       returned by DBIC (more on this later, especially in "EXPLORING THE
712       POWER OF DBIC" in Catalyst::Manual::Tutorial::04_BasicCRUD).
713
714       The idea with the Result Source files created under
715       "lib/MyApp/Schema/Result" by the "create=static" option is to only edit
716       the files below the "# DO NOT MODIFY THIS OR ANYTHING ABOVE!"  warning.
717       If you place all of your changes below that point in the file, you can
718       regenerate the automatically created information at the top of each
719       file should your database structure get updated.
720
721       Also note the "flow" of the model information across the various files
722       and directories.  Catalyst will initially load the model from
723       "lib/MyApp/Model/DB.pm".  This file contains a reference to
724       "lib/MyApp/Schema.pm", so that file is loaded next.  Finally, the call
725       to "load_namespaces" in "Schema.pm" will load each of the "Result
726       Class" files from the "lib/MyApp/Schema/Result" subdirectory.  The
727       final outcome is that Catalyst will dynamically create three table-
728       specific Catalyst models every time the application starts (you can see
729       these three model files listed in the debug output generated when you
730       launch the application).
731
732       Additionally, the "lib/MyApp/Schema.pm" model can easily be loaded
733       outside of Catalyst, for example, in command-line utilities and/or cron
734       jobs. "lib/MyApp/Model/DB.pm" provides a very thin "bridge" between
735       Catalyst and this external database model.  Once you see how we can add
736       some powerful features to our DBIC model in Chapter 4, the elegance of
737       this approach will start to become more obvious.
738
739       NOTE: Older versions of Catalyst::Model::DBIC::Schema use the
740       deprecated DBIx::Class "load_classes" technique instead of the newer
741       "load_namespaces".  For new applications, please try to use
742       "load_namespaces" since it more easily supports a very useful DBIC
743       technique called "ResultSet Classes."  If you need to convert an
744       existing application from "load_classes" to "load_namespaces," you can
745       use this process to automate the migration, but first make sure you
746       have version 0.39 of Catalyst::Model::DBIC::Schema and
747       DBIx::Class::Schema::Loader version 0.05000 or later.
748
749           $ # Re-run the helper to upgrade for you
750           $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
751               create=static naming=current use_namespaces=1 \
752               dbi:SQLite:myapp.db \
753               on_connect_do="PRAGMA foreign_keys = ON"
754

ENABLE THE MODEL IN THE CONTROLLER

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

CREATE A WRAPPER FOR THE VIEW

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

UPDATING THE VIEW

1222       Let's add a new column to our book list page that takes advantage of
1223       the relationship information we manually added to our schema files in
1224       the previous section.  Edit "root/src/books/list.tt2" and replace the
1225       "empty" table cell "<td></td>" with the following:
1226
1227           ...
1228           <td>
1229             [% # NOTE: See Chapter 4 for a better way to do this!                      -%]
1230             [% # First initialize a TT variable to hold a list.  Then use a TT FOREACH -%]
1231             [% # loop in 'side effect notation' to load just the last names of the     -%]
1232             [% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
1233             [% # a value, so nothing will be printed here.  But, if you have something -%]
1234             [% # in TT that does return a value and you don't want it printed, you     -%]
1235             [% # 1) assign it to a bogus value, or                                     -%]
1236             [% # 2) use the CALL keyword to call it and discard the return value.      -%]
1237             [% tt_authors = [ ];
1238                tt_authors.push(author.last_name) FOREACH author = book.authors %]
1239             [% # Now use a TT 'virtual method' to display the author count in parens   -%]
1240             [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
1241             ([% tt_authors.size | html %])
1242             [% # Use another TT vmethod to join & print the names & comma separators   -%]
1243             [% tt_authors.join(', ') | html %]
1244           </td>
1245           ...
1246
1247       IMPORTANT NOTE: Again, you should keep as much "logic code" as possible
1248       out of your views.  This kind of logic belongs in your model (the same
1249       goes for controllers -- keep them as "thin" as possible and push all of
1250       the "complicated code" out to your model objects).  Avoid code like you
1251       see in the previous example -- we are only using it here to show some
1252       extra features in TT until we get to the more advanced model features
1253       we will see in Chapter 4 (see "EXPLORING THE POWER OF DBIC" in
1254       Catalyst::Manual::Tutorial::04_BasicCRUD).
1255
1256       Then hit "Reload" in your browser (note that you don't need to reload
1257       the development server or use the "-r" option when updating TT
1258       templates) and you should now see the number of authors each book has
1259       along with a comma-separated list of the authors' last names.  (If you
1260       didn't leave the development server running from the previous step, you
1261       will obviously need to start it before you can refresh your browser
1262       window.)
1263
1264       If you are still running the development server with "DBIC_TRACE"
1265       enabled, you should also now see five more "SELECT" statements in the
1266       debug output (one for each book as the authors are being retrieved by
1267       DBIx::Class):
1268
1269           SELECT me.id, me.title, me.rating FROM book me:
1270           SELECT author.id, author.first_name, author.last_name FROM book_author me
1271           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '1'
1272           SELECT author.id, author.first_name, author.last_name FROM book_author me
1273           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '2'
1274           SELECT author.id, author.first_name, author.last_name FROM book_author me
1275           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '3'
1276           SELECT author.id, author.first_name, author.last_name FROM book_author me
1277           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '4'
1278           SELECT author.id, author.first_name, author.last_name FROM book_author me
1279           JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '5'
1280
1281       Also note in "root/src/books/list.tt2" that we are using "| html", a
1282       type of TT filter, to escape characters such as < and > to &lt; and
1283       &gt; and avoid various types of dangerous hacks against your
1284       application.  In a real application, you would probably want to put "|
1285       html" at the end of every field where a user has control over the
1286       information that can appear in that field (and can therefore inject
1287       markup or code if you don't "neutralize" those fields).  In addition to
1288       "| html", Template Toolkit has a variety of other useful filters that
1289       can be found in the documentation for Template::Filters.  (While we are
1290       on the topic of security and escaping of dangerous values, one of the
1291       advantages of using tools like DBIC for database access or HTML::FormFu
1292       for form management [see Chapter 9] is that they automatically handle
1293       most escaping for you and therefore dramatically increase the security
1294       of your app.)
1295

RUNNING THE APPLICATION FROM THE COMMAND LINE

1297       In some situations, it can be useful to run your application and
1298       display a page without using a browser.  Catalyst lets you do this
1299       using the "script/myapp_test.pl" script.  Just supply the URL you wish
1300       to display and it will run that request through the normal controller
1301       dispatch logic and use the appropriate view to render the output
1302       (obviously, complex pages may dump a lot of text to your terminal
1303       window).  For example, if "Ctrl+C" out of the development server and
1304       then type:
1305
1306           $ script/myapp_test.pl "/books/list"
1307
1308       You should get the same text as if you visited
1309       <http://localhost:3000/books/list> with the normal development server
1310       and asked your browser to view the page source.  You can even pipe this
1311       HTML text output to a text-based browser using a command like:
1312
1313           $ script/myapp_test.pl "/books/list" | lynx -stdin
1314
1315       And you should see a fully rendered text-based view of your page.  (If
1316       you are following along in Debian 6, type "sudo aptitude -y install
1317       lynx" to install lynx.)  If you do start lynx, you can use the "Q" key
1318       to quit.
1319

OPTIONAL INFORMATION

1321       NOTE: The rest of this chapter of the tutorial is optional.  You can
1322       skip to Chapter 4, Basic CRUD, if you wish.
1323
1324   Using 'RenderView' for the Default View
1325       Once your controller logic has processed the request from a user, it
1326       forwards processing to your view in order to generate the appropriate
1327       response output.  Catalyst uses Catalyst::Action::RenderView by default
1328       to automatically perform this operation.  If you look in
1329       "lib/MyApp/Controller/Root.pm", you should see the empty definition for
1330       the "sub end" method:
1331
1332           sub end : ActionClass('RenderView') {}
1333
1334       The following bullet points provide a quick overview of the
1335       "RenderView" process:
1336
1337       ·   "Root.pm" is designed to hold application-wide logic.
1338
1339       ·   At the end of a given user request, Catalyst will call the most
1340           specific "end" method that's appropriate.  For example, if the
1341           controller for a request has an "end" method defined, it will be
1342           called.  However, if the controller does not define a controller-
1343           specific "end" method, the "global" "end" method in "Root.pm" will
1344           be called.
1345
1346       ·   Because the definition includes an "ActionClass" attribute, the
1347           Catalyst::Action::RenderView logic will be executed after any code
1348           inside the definition of "sub end" is run.  See
1349           Catalyst::Manual::Actions for more information on "ActionClass".
1350
1351       ·   Because "sub end" is empty, this effectively just runs the default
1352           logic in "RenderView".  However, you can easily extend the
1353           "RenderView" logic by adding your own code inside the empty method
1354           body ("{}") created by the Catalyst Helpers when we first ran the
1355           "catalyst.pl" to initialize our application.  See
1356           Catalyst::Action::RenderView for more detailed information on how
1357           to extend "RenderView" in "sub end".
1358
1359   RenderView's "dump_info" Feature
1360       One of the nice features of "RenderView" is that it automatically
1361       allows you to add "dump_info=1" to the end of any URL for your
1362       application and it will force the display of the "exception dump"
1363       screen to the client browser.  You can try this out by pointing your
1364       browser to this URL:
1365
1366           http://localhost:3000/books/list?dump_info=1
1367
1368       You should get a page with the following message at the top:
1369
1370           Caught exception in MyApp::Controller::Root->end "Forced debug -
1371           Scrubbed output at /usr/share/perl5/Catalyst/Action/RenderView.pm line 46."
1372
1373       Along with a summary of your application's state at the end of the
1374       processing for that request.  The "Stash" section should show a
1375       summarized version of the DBIC book model objects.  If desired, you can
1376       adjust the summarization logic (called "scrubbing" logic) -- see
1377       Catalyst::Action::RenderView for details.
1378
1379       Note that you shouldn't need to worry about "normal clients" using this
1380       technique to "reverse engineer" your application -- "RenderView" only
1381       supports the "dump_info=1" feature when your application is running in
1382       "-Debug" mode (something you won't do once you have your application
1383       deployed in production).
1384
1385   Using The Default Template Name
1386       By default, "Catalyst::View::TT" will look for a template that uses the
1387       same name as your controller action, allowing you to save the step of
1388       manually specifying the template name in each action.  For example,
1389       this would allow us to remove the "$c->stash->{template} =
1390       'books/list.tt2';" line of our "list" action in the Books controller.
1391       Open "lib/MyApp/Controller/Books.pm" in your editor and comment out
1392       this line to match the following (only the "$c->stash->{template}" line
1393       has changed):
1394
1395           =head2 list
1396
1397           Fetch all book objects and pass to books/list.tt2 in stash to be displayed
1398
1399           =cut
1400
1401           sub list :Local {
1402               # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
1403               # 'Context' that's used to 'glue together' the various components
1404               # that make up the application
1405               my ($self, $c) = @_;
1406
1407               # Retrieve all of the book records as book model objects and store in the
1408               # stash where they can be accessed by the TT template
1409               $c->stash(books => [$c->model('DB::Book')->all]);
1410
1411               # Set the TT template to use.  You will almost always want to do this
1412               # in your action methods (actions methods respond to user input in
1413               # your controllers).
1414               #$c->stash(template => 'books/list.tt2');
1415           }
1416
1417       You should now be able to access the <http://localhost:3000/books/list>
1418       URL as before.
1419
1420       NOTE: If you use the default template technique, you will not be able
1421       to use either the "$c->forward" or the "$c->detach" mechanisms (these
1422       are discussed in Chapter 2 and Chapter 9 of the Tutorial).
1423
1424       IMPORTANT: Make sure that you do not skip the following section before
1425       continuing to the next chapter 4 Basic CRUD.
1426
1427   Return To A Manually Specified Template
1428       In order to be able to use "$c->forward" and "$c->detach" later in the
1429       tutorial, you should remove the comment from the statement in "sub
1430       list" in "lib/MyApp/Controller/Books.pm":
1431
1432           $c->stash(template => 'books/list.tt2');
1433
1434       Then delete the "TEMPLATE_EXTENSION" line in "lib/MyApp/View/HTML.pm".
1435
1436       Check the <http://localhost:3000/books/list> URL in your browser.  It
1437       should look the same manner as with earlier sections.
1438
1439       You can jump to the next chapter of the tutorial here: Basic CRUD
1440

AUTHOR

1442       Kennedy Clark, "hkclark@gmail.com"
1443
1444       Feel free to contact the author for any errors or suggestions, but the
1445       best way to report issues is via the CPAN RT Bug system at
1446       <https://rt.cpan.org/Public/Dist/Display.html?Name=Catalyst-Manual>.
1447
1448       Copyright 2006-2011, Kennedy Clark, under the Creative Commons
1449       Attribution Share-Alike License Version 3.0
1450       (<http://creativecommons.org/licenses/by-sa/3.0/us/>).
1451
1452
1453
1454perl v5.28.1              Catalyst2:0:1M4a-n1u2a-l1:3:Tutorial::03_MoreCatalystBasics(3)
Impressum