Release commit for 5.9013
[catagits/Catalyst-Manual.git] / lib / Catalyst / Manual / Tutorial / 03_MoreCatalystBasics.pod
CommitLineData
3533daff 1=head1 NAME
2
3ab6187c 3Catalyst::Manual::Tutorial::03_MoreCatalystBasics - Catalyst Tutorial - Chapter 3: More Catalyst Application Development Basics
3533daff 4
5
6=head1 OVERVIEW
7
4b4d3884 8This is B<Chapter 3 of 10> for the Catalyst tutorial.
3533daff 9
10L<Tutorial Overview|Catalyst::Manual::Tutorial>
11
12=over 4
13
14=item 1
15
3ab6187c 16L<Introduction|Catalyst::Manual::Tutorial::01_Intro>
3533daff 17
18=item 2
19
3ab6187c 20L<Catalyst Basics|Catalyst::Manual::Tutorial::02_CatalystBasics>
3533daff 21
22=item 3
23
3ab6187c 24B<03_More Catalyst Basics>
3533daff 25
26=item 4
27
3ab6187c 28L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
3533daff 29
30=item 5
31
3ab6187c 32L<Authentication|Catalyst::Manual::Tutorial::05_Authentication>
3533daff 33
34=item 6
35
3ab6187c 36L<Authorization|Catalyst::Manual::Tutorial::06_Authorization>
3533daff 37
38=item 7
39
3ab6187c 40L<Debugging|Catalyst::Manual::Tutorial::07_Debugging>
3533daff 41
42=item 8
43
3ab6187c 44L<Testing|Catalyst::Manual::Tutorial::08_Testing>
3533daff 45
46=item 9
47
3ab6187c 48L<Advanced CRUD|Catalyst::Manual::Tutorial::09_AdvancedCRUD>
3533daff 49
50=item 10
51
3ab6187c 52L<Appendices|Catalyst::Manual::Tutorial::10_Appendices>
3533daff 53
54=back
55
56
57=head1 DESCRIPTION
58
a8f4e284 59This chapter of the tutorial builds on the work done in Chapter 2 to
60explore some features that are more typical of "real world" web
61applications. From this chapter of the tutorial onward, we will be
62building a simple book database application. Although the application
63will be too limited to be of use to anyone, it should provide a basic
64environment where we can explore a variety of features used in virtually
65all web applications.
3533daff 66
477a6d5b 67Source code for the tutorial in included in the F</home/catalyst/Final>
68directory of the Tutorial Virtual machine (one subdirectory per
69chapter). There are also instructions for downloading the code in
2217b252 70L<Catalyst::Manual::Tutorial::01_Intro>.
3533daff 71
a8f4e284 72Please take a look at
01df1cc9 73L<Catalyst::Manual::Tutorial::01_Intro/STARTING WITH THE TUTORIAL VIRTUAL MACHINE>
74before doing the rest of this tutorial. Although the tutorial should
75work correctly under most any recent version of Perl running on any
76operating system, the tutorial has been written using the virtual
77machine that is available for download. The entire tutorial has been
78tested to be sure it runs correctly in this environment, so it is
79the most trouble-free way to get started with Catalyst.
a586a09f 80
3533daff 81
82=head1 CREATE A NEW APPLICATION
83
1390ef0e 84The remainder of the tutorial will build an application called C<MyApp>.
f4e9de4a 85First use the Catalyst F<catalyst.pl> script to initialize the framework
1390ef0e 86for the C<MyApp> application (make sure you aren't still inside the
4b4d3884 87directory of the C<Hello> application from the previous chapter of the
acbd7bdd 88tutorial or in a directory that already has a "MyApp" subdirectory):
3533daff 89
90 $ catalyst.pl MyApp
91 created "MyApp"
92 created "MyApp/script"
93 created "MyApp/lib"
94 created "MyApp/root"
95 ...
96 created "MyApp/script/myapp_create.pl"
444d6b27 97 Change to application directory and Run "perl Makefile.PL" to make sure your install is complete
c988c8b0 98
99And change the "MyApp" directory the helper created:
100
3533daff 101 $ cd MyApp
102
4b4d3884 103This creates a similar skeletal structure to what we saw in Chapter 2 of
a8f4e284 104the tutorial, except with C<MyApp> and C<myapp> substituted for C<Hello>
105and C<hello>. (As noted in Chapter 2, omit the ".pl" from the command
106if you are using Strawberry Perl.)
3533daff 107
108
109=head1 EDIT THE LIST OF CATALYST PLUGINS
110
a8f4e284 111One of the greatest benefits of Catalyst is that it has such a large
be093944 112library of base classes and plugins available that you can use to easily
a8f4e284 113add functionality to your application. Plugins are used to seamlessly
114integrate existing Perl modules into the overall Catalyst framework. In
115general, they do this by adding additional methods to the C<context>
116object (generally written as C<$c>) that Catalyst passes to every
117component throughout the framework.
f058768a 118
f4e9de4a 119Take a look at the file F<lib/MyApp.pm> that the helper created above.
3533daff 120By default, Catalyst enables three plugins/flags:
121
122=over 4
123
1390ef0e 124=item *
3533daff 125
126C<-Debug> Flag
127
128Enables the Catalyst debug output you saw when we started the
f4e9de4a 129F<script/myapp_server.pl> development server earlier. You can remove
79a529cc 130this item when you place your application into production.
3533daff 131
a8f4e284 132To be technically correct, it turns out that C<-Debug> is not a plugin,
c988c8b0 133but a I<flag>. Although most of the items specified on the C<use
134Catalyst> line of your application class will be plugins, Catalyst
135supports a limited number of flag options (of these, C<-Debug> is the
136most common). See the documentation for
6f660c96 137L<Catalyst.pm|Catalyst> to get details on
c988c8b0 138other flags (currently C<-Engine>, C<-Home>, C<-Log>, and C<-Stats>).
3533daff 139
444d6b27 140If you prefer, there are several other ways to enable debug output:
141
142=over 4
143
144=item *
145
429d1caf 146the C<< $c->debug >> method on the C<$c> Catalyst context object
444d6b27 147
148=item *
149
f4e9de4a 150the C<-d> option on the F<script/myapp_server.pl> script
444d6b27 151
152=item *
153
be093944 154the C<CATALYST_DEBUG=1> environment variable (or C<CATALYST_DEBUG=0>
155to temporarily disable debug output)
444d6b27 156
157=back
3533daff 158
a8f4e284 159B<TIP>: Depending on your needs, it can be helpful to permanently remove
160C<-Debug> from C<lib/MyApp.pm> and then use the C<-d> option to
f4e9de4a 161F<script/myapp_server.pl> to re-enable it when needed. We will not be
c988c8b0 162using that approach in the tutorial, but feel free to make use of it in
163your own projects.
3533daff 164
165=item *
166
2217b252 167L<Catalyst::Plugin::ConfigLoader>
3533daff 168
169C<ConfigLoader> provides an automatic way to load configurable
c010ae0d 170parameters for your application from a central
2217b252 171L<Config::General> file (versus having the values
56a12748 172hard-coded inside your Perl modules). L<Config::General> uses syntax very
a8f4e284 173similar to Apache configuration files. We will see how to use this
174feature of Catalyst during the authentication and authorization sections
c988c8b0 175(L<Chapter 5|Catalyst::Manual::Tutorial::05_Authentication> and
176L<Chapter 6|Catalyst::Manual::Tutorial::06_Authorization>).
a8f4e284 177
178B<IMPORTANT NOTE:> If you are using a version of
2217b252 179L<Catalyst::Devel> prior to version 1.06, be aware that
a8f4e284 180Catalyst changed the default format from YAML to the more
56a12748 181straightforward L<Config::General> style. This tutorial uses the newer
182C<myapp.conf> file for L<Config::General>. However, Catalyst supports
f4e9de4a 183both formats and will automatically use either F<myapp.conf> or
184F<myapp.yml> (or any other format supported by
2217b252 185L<Catalyst::Plugin::ConfigLoader> and
186L<Config::Any>). If you are using a version of
56a12748 187L<Catalyst::Devel> prior to 1.06, you can convert to the newer format by
f4e9de4a 188simply creating the F<myapp.conf> file manually and deleting
189F<myapp.yml>. The default contents of the F<myapp.conf> you create
a8f4e284 190should only consist of one line:
1435672d 191
192 name MyApp
15e1d0b2 193
1390ef0e 194B<TIP>: This script can be useful for converting between configuration
15e1d0b2 195formats:
196
1390ef0e 197 perl -Ilib -e 'use MyApp; use Config::General;
15e1d0b2 198 Config::General->new->save_file("myapp.conf", MyApp->config);'
199
3533daff 200=item *
201
2217b252 202L<Catalyst::Plugin::Static::Simple>
3533daff 203
a8f4e284 204C<Static::Simple> provides an easy way to serve static content, such as
205images and CSS files, from the development server.
3533daff 206
207=back
208
be093944 209For our application, we want to add one new plugin to the mix. To do
f4e9de4a 210this, edit F<lib/MyApp.pm> (this file is generally referred to as your
a8f4e284 211I<application class>) and delete the lines with:
3533daff 212
1dc333c7 213 use Catalyst qw/
214 -Debug
215 ConfigLoader
216 Static::Simple
217 /;
3533daff 218
1390ef0e 219Then replace it with:
b411df01 220
acbd7bdd 221 # Load plugins
fce83e5f 222 use Catalyst qw/
1dc333c7 223 -Debug
224 ConfigLoader
225 Static::Simple
7ce05098 226
1dc333c7 227 StackTrace
228 /;
1390ef0e 229
56a12748 230B<Note:> Recent versions of L<Catalyst::Devel> have used a variety of
a8f4e284 231techniques to load these plugins/flags. For example, you might see the
232following:
94d8da41 233
acbd7bdd 234 __PACKAGE__->setup(qw/-Debug ConfigLoader Static::Simple/);
94d8da41 235
a8f4e284 236Don't let these variations confuse you -- they all accomplish the same
94d8da41 237result.
238
a8f4e284 239This tells Catalyst to start using one additional plugin,
462f687d 240L<Catalyst::Plugin::StackTrace>, to add a stack trace near the top of
241the standard Catalyst "debug screen" (the screen Catalyst sends to your
242browser when an error occurs). Be aware that
a8f4e284 243L<StackTrace|Catalyst::Plugin::StackTrace> output appears in your
244browser, not in the console window from which you're running your
1390ef0e 245application, which is where logging output usually goes.
3533daff 246
444d6b27 247Make sure when adding new plugins you also include them as a new
a8f4e284 248dependency within the Makefile.PL file. For example, after adding the
249StackTrace plugin the Makefile.PL should include the following line:
3b1fa91b 250
251 requires 'Catalyst::Plugin::StackTrace';
252
253
a8f4e284 254B<Notes:>
3533daff 255
256=over 4
257
1390ef0e 258=item *
259
a8f4e284 260C<__PACKAGE__> is just a shorthand way of referencing the name of the
f4e9de4a 261package where it is used. Therefore, in F<MyApp.pm>, C<__PACKAGE__> is
a8f4e284 262equivalent to C<MyApp>.
3533daff 263
1390ef0e 264=item *
3533daff 265
a8f4e284 266You will want to disable L<StackTrace|Catalyst::Plugin::StackTrace>
267before you put your application into production, but it can be helpful
1390ef0e 268during development.
3533daff 269
1390ef0e 270=item *
3533daff 271
a8f4e284 272When specifying plugins, you can omit C<Catalyst::Plugin::> from the
273name. Additionally, you can spread the plugin names across multiple
444d6b27 274lines as shown here or place them all on one line.
cca5cd98 275
c988c8b0 276=item *
277
278If you want to see what the StackTrace error screen looks like, edit
f4e9de4a 279F<lib/MyApp/Controller/Root.pm> and put a C<die "Oops";> command in the
c988c8b0 280C<sub index :Path :Args(0)> method. Then start the development server
281and open C<http://localhost:3000/> in your browser. You should get a
282screen that starts with "Caught exception in
283MyApp::Controller::Root->index" with sections showing a stacktrace,
284information about the Request and Response objects, the stash (something
5336f546 285we will learn about soon), and the applications configuration.
c988c8b0 286B<Just don't forget to remove the die before you continue the tutorial!>
287:-)
288
3533daff 289=back
290
3533daff 291
292=head1 CREATE A CATALYST CONTROLLER
293
1390ef0e 294As discussed earlier, controllers are where you write methods that
295interact with user input. Typically, controller methods respond to
4d63a0d5 296C<GET> and C<POST> requests from the user's web browser.
3533daff 297
298Use the Catalyst C<create> script to add a controller for book-related
299actions:
300
301 $ script/myapp_create.pl controller Books
477a6d5b 302 exists "/home/catalyst/MyApp/script/../lib/MyApp/Controller"
303 exists "/home/catalyst/MyApp/script/../t"
304 created "/home/catalyst/MyApp/script/../lib/MyApp/Controller/Books.pm"
305 created "/home/catalyst/MyApp/script/../t/controller_Books.t"
3533daff 306
f4e9de4a 307Then edit F<lib/MyApp/Controller/Books.pm> (as discussed in
c988c8b0 308L<Chapter 2|Catalyst::Manual::Tutorial::02_CatalystBasics> of
f4e9de4a 309the Tutorial, Catalyst has a separate directory under F<lib/MyApp> for
be093944 310each of the three parts of MVC: C<Model>, C<View> and C<Controller>)
1390ef0e 311and add the following method to the controller:
3533daff 312
313 =head2 list
7ce05098 314
3533daff 315 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
7ce05098 316
3533daff 317 =cut
7ce05098 318
f058768a 319 sub list :Local {
3533daff 320 # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
321 # 'Context' that's used to 'glue together' the various components
322 # that make up the application
323 my ($self, $c) = @_;
7ce05098 324
3533daff 325 # Retrieve all of the book records as book model objects and store in the
326 # stash where they can be accessed by the TT template
0ed3df53 327 # $c->stash(books => [$c->model('DB::Book')->all]);
1390ef0e 328 # But, for now, use this code until we create the model later
0ed3df53 329 $c->stash(books => '');
7ce05098 330
3533daff 331 # Set the TT template to use. You will almost always want to do this
332 # in your action methods (action methods respond to user input in
333 # your controllers).
61cb69fd 334 $c->stash(template => 'books/list.tt2');
3533daff 335 }
336
56a12748 337B<TIP>: See L<Appendix 1|Catalyst::Manual::Tutorial::10_Appendices/APPENDIX 1: CUT AND PASTE FOR POD-BASED EXAMPLES>
338for tips on removing the leading spaces when cutting and pasting example
c988c8b0 339code from POD-based documents.
3533daff 340
a8f4e284 341Programmers experienced with object-oriented Perl should recognize
342C<$self> as a reference to the object where this method was called. On
343the other hand, C<$c> will be new to many Perl programmers who have not
c988c8b0 344used Catalyst before. This is the "Catalyst Context object", and it is
345automatically passed as the second argument to all Catalyst action
346methods. It is used to pass information between components and provide
347access to Catalyst and plugin functionality.
348
349Catalyst Controller actions are regular Perl methods, but they make use
350of attributes (the "C<:Local>" next to the "C<sub list>" in the code
351above) to provide additional information to the Catalyst dispatcher
352logic (note that there can be an optional space between the colon and
353the attribute name; you will see attributes written both ways). Most
354Catalyst Controllers use one of five action types:
0416017e 355
356=over 4
357
358=item *
359
a8f4e284 360B<:Private> -- Use C<:Private> for methods that you want to make into an
c988c8b0 361action, but you do not want Catalyst to directly expose the method to
a8f4e284 362your users. Catalyst will not map C<:Private> methods to a URI. Use
363them for various sorts of "special" methods (the C<begin>, C<auto>, etc.
364discussed below) or for methods you want to be able to C<forward> or
c988c8b0 365C<detach> to. (If the method is a "plain old method" that you
a8f4e284 366don't want to be an action at all, then just define the method without
367any attribute -- you can call it in your code, but the Catalyst
c988c8b0 368dispatcher will ignore it. You will also have to manually include
369C<$c> if you want access to the context object in the method vs. having
370Catalyst automatically include C<$c> in the argument list for you
371if it's a full-fledged action.)
0416017e 372
8fd01b0e 373There are five types of "special" built-in C<:Private> actions:
245b41d1 374C<begin>, C<end>, C<default>, C<index>, and C<auto>.
0416017e 375
26c9cad5 376=over 4
377
0416017e 378=item *
379
380With C<begin>, C<end>, C<default>, C<index> private actions, only the
381most specific action of each type will be called. For example, if you
382define a C<begin> action in your controller it will I<override> a
383C<begin> action in your application/root controller -- I<only> the
384action in your controller will be called.
385
386=item *
387
388Unlike the other actions where only a single method is called for each
389request, I<every> auto action along the chain of namespaces will be
390called. Each C<auto> action will be called I<from the application/root
391controller down through the most specific class>.
392
393=back
394
395=item *
396
a8f4e284 397B<:Path> -- C<:Path> actions let you map a method to an explicit URI
398path. For example, "C<:Path('list')>" in
f4e9de4a 399F<lib/MyApp/Controller/Books.pm> would match on the URL
a8f4e284 400C<http://localhost:3000/books/list>, but "C<:Path('/list')>" would match
401on C<http://localhost:3000/list> (because of the leading slash). You
402can use C<:Args()> to specify how many arguments an action should
4ad342ef 403accept. See L<Catalyst::Manual::Intro/Action-types> for more
444d6b27 404information and examples.
0416017e 405
406=item *
407
a8f4e284 408B<:Local> -- C<:Local> is merely a shorthand for
245b41d1 409"C<:Path('_name_of_method_')>". For example, these are equivalent:
c988c8b0 410"C<sub create_book :Local {...}>" and
411"C<sub create_book :Path('create_book') {...}>".
245b41d1 412
413=item *
414
a8f4e284 415B<:Global> -- C<:Global> is merely a shorthand for
245b41d1 416"C<:Path('/_name_of_method_')>". For example, these are equivalent:
a8f4e284 417"C<sub create_book :Global {...}>" and "C<sub create_book
418:Path('/create_book') {...}>".
245b41d1 419
420=item *
421
a8f4e284 422B<:Chained> -- Newer Catalyst applications tend to use the Chained
423dispatch form of action types because of its power and flexibility. It
c988c8b0 424allows a series of controller methods to be automatically dispatched
425when servicing a single user request. See
426L<Catalyst::Manual::Tutorial::04_BasicCRUD> and
427L<Catalyst::DispatchType::Chained> for more information on chained
428actions.
0416017e 429
430=back
431
c988c8b0 432You should refer to L<Catalyst::Manual::Intro/Action-types> for
a8f4e284 433additional information and for coverage of some lesser-used action types
434not discussed here (C<Regex> and C<LocalRegex>).
3533daff 435
436
437=head1 CATALYST VIEWS
438
c988c8b0 439As mentioned in L<Chapter 2|Catalyst::Manual::Tutorial::02_CatalystBasics>
440of the tutorial, views are where you render output, typically for
441display in the user's web browser (but can generate other types of
f4e9de4a 442output such as PDF or JSON). The code in F<lib/MyApp/View> selects the
c988c8b0 443I<type> of view to use, with the actual rendering template found in the
444C<root> directory. As with virtually every aspect of Catalyst, options
445abound when it comes to the specific view technology you adopt inside
446your application. However, most Catalyst applications use the Template
447Toolkit, known as TT (for more information on TT, see
448L<http://www.template-toolkit.org>). Other somewhat popular view
449technologies include Mason (L<http://www.masonhq.com> and
56a12748 450L<https://masonbook.houseabsolute.com/book/>) and L<HTML::Template>.
1390ef0e 451
452
453=head2 Create a Catalyst View
3533daff 454
a8f4e284 455When using TT for the Catalyst view, the main helper script is
c988c8b0 456L<Catalyst::Helper::View::TT>. You may also come across references to
457L<Catalyst::Helper::View::TTSite>, but its use is now deprecated.
1390ef0e 458
c988c8b0 459For our book application, enter the following command to enable the
460C<TT> style of view rendering:
3533daff 461
1edbdee6 462 $ script/myapp_create.pl view HTML TT
477a6d5b 463 exists "/home/catalyst/MyApp/script/../lib/MyApp/View"
464 exists "/home/catalyst/MyApp/script/../t"
465 created "/home/catalyst/MyApp/script/../lib/MyApp/View/HTML.pm"
466 created "/home/catalyst/MyApp/script/../t/view_HTML.t"
1edbdee6 467
c988c8b0 468This creates a view called C<HTML> (the first argument) in a file called
469C<HTML.pm> that uses L<Catalyst::View::TT> (the second argument) as the
470"rendering engine".
471
472It is now up to you to decide how you want to structure your view
473layout. For the tutorial, we will start with a very simple TT template
474to initially demonstrate the concepts, but quickly migrate to a more
475typical "wrapper page" type of configuration (where the "wrapper"
476controls the overall "look and feel" of your site from a single file or
477set of files).
1edbdee6 478
f4e9de4a 479Edit F<lib/MyApp/View/HTML.pm> and you should see something similar to
a8f4e284 480the following:
3533daff 481
c062293d 482 __PACKAGE__->config(
483 TEMPLATE_EXTENSION => '.tt',
484 render_die => 1,
485 );
3533daff 486
1390ef0e 487And update it to match:
488
489 __PACKAGE__->config(
490 # Change default TT extension
491 TEMPLATE_EXTENSION => '.tt2',
c062293d 492 render_die => 1,
493 );
494
495This changes the default extension for Template Toolkit from '.tt' to
496'.tt2'.
497
a8f4e284 498You can also configure components in your application class. For
f4e9de4a 499example, Edit F<lib/MyApp.pm> and you should see the default
429d1caf 500configuration above the call to C<< _PACKAGE__->setup >> (your defaults
c988c8b0 501could be different depending on the version of Catalyst you are using):
502
503 __PACKAGE__->config(
504 name => 'MyApp',
505 # Disable deprecated behavior needed by old applications
506 disable_component_resolution_regex_fallback => 1,
507 );
c062293d 508
c062293d 509
01df1cc9 510Change this to match the following (insert a new
429d1caf 511C<< __PACKAGE__->config >> below the existing statement):
c062293d 512
513 __PACKAGE__->config(
c988c8b0 514 name => 'MyApp',
515 # Disable deprecated behavior needed by old applications
516 disable_component_resolution_regex_fallback => 1,
01df1cc9 517 );
518 __PACKAGE__->config(
c988c8b0 519 # Configure the view
c062293d 520 'View::HTML' => {
521 #Set the location for TT files
522 INCLUDE_PATH => [
523 __PACKAGE__->path_to( 'root', 'src' ),
1390ef0e 524 ],
c062293d 525 },
1390ef0e 526 );
3533daff 527
a8f4e284 528This changes the base directory for your template files from C<root> to
f4e9de4a 529F<root/src>.
1390ef0e 530
a8f4e284 531Please stick with the settings above for the duration of the tutorial,
532but feel free to use whatever options you desire in your applications
69d57cda 533(as with most things in Perl, there's more than one way to do it...).
1390ef0e 534
f4e9de4a 535B<Note:> We will use F<root/src> as the base directory for our template
a8f4e284 536files, with a full naming convention of
f4e9de4a 537F<root/src/_controller_name_/_action_name_.tt2>. Another popular option
538is to use F<root/> as the base (with a full filename pattern of
539F<root/_controller_name_/_action_name_.tt2>).
acbd7bdd 540
a8f4e284 541
1390ef0e 542=head2 Create a TT Template Page
3533daff 543
544First create a directory for book-related TT templates:
545
1390ef0e 546 $ mkdir -p root/src/books
3533daff 547
f4e9de4a 548Then create F<root/src/books/list.tt2> in your editor and enter:
3533daff 549
c988c8b0 550 [% # This is a TT comment. -%]
7ce05098 551
c988c8b0 552 [%- # Provide a title -%]
3533daff 553 [% META title = 'Book List' -%]
7ce05098 554
c988c8b0 555 [% # Note That the '-' at the beginning or end of TT code -%]
556 [% # "chomps" the whitespace/newline at that end of the -%]
557 [% # output (use View Source in browser to see the effect) -%]
7ce05098 558
c988c8b0 559 [% # Some basic HTML with a loop to display books -%]
3533daff 560 <table>
561 <tr><th>Title</th><th>Rating</th><th>Author(s)</th></tr>
562 [% # Display each book in a table row %]
563 [% FOREACH book IN books -%]
564 <tr>
565 <td>[% book.title %]</td>
566 <td>[% book.rating %]</td>
a46b474e 567 <td></td>
3533daff 568 </tr>
569 [% END -%]
570 </table>
571
572As indicated by the inline comments above, the C<META title> line uses
1390ef0e 573TT's META feature to provide a title to the "wrapper" that we will
c988c8b0 574create later (and essentially does nothing at the moment). Meanwhile,
575the C<FOREACH> loop iterates through each C<book> model object and
576prints the C<title> and C<rating> fields.
3533daff 577
4d63a0d5 578The C<[%> and C<%]> tags are used to delimit Template Toolkit code. TT
579supports a wide variety of directives for "calling" other files,
580looping, conditional logic, etc. In general, TT simplifies the usual
444d6b27 581range of Perl operators down to the single dot (".") operator. This
4d63a0d5 582applies to operations as diverse as method calls, hash lookups, and list
c988c8b0 583index values (see L<Template::Manual::Variables> for details and
89a65964 584examples). In addition to the usual L<Template::Toolkit> module Pod
4d63a0d5 585documentation, you can access the TT manual at
6f660c96 586L<Template::Manual>.
3533daff 587
a8f4e284 588B<TIP:> While you can build all sorts of complex logic into your TT
589templates, you should in general keep the "code" part of your templates
590as simple as possible. If you need more complex logic, create helper
591methods in your model that abstract out a set of code into a single call
592from your TT template. (Note that the same is true of your controller
593logic as well -- complex sections of code in your controllers should
c988c8b0 594often be pulled out and placed into your model objects.) In
595L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD> of the tutorial we
596will explore some extremely helpful and powerful features of
597L<DBIx::Class> that allow you to pull code out of your views and
598controllers and place it where it rightfully belongs in a model class.
1390ef0e 599
600
601=head2 Test Run The Application
602
603To test your work so far, first start the development server:
604
f058768a 605 $ script/myapp_server.pl -r
1390ef0e 606
a8f4e284 607Then point your browser to L<http://localhost:3000> and you should still
608get the Catalyst welcome page. Next, change the URL in your browser to
609L<http://localhost:3000/books/list>. If you have everything working so
610far, you should see a web page that displays nothing other than our
611column headers for "Title", "Rating", and "Author(s)" -- we will not see
612any books until we get the database and model working below.
1390ef0e 613
614If you run into problems getting your application to run correctly, it
615might be helpful to refer to some of the debugging techniques covered in
fce83e5f 616the L<Debugging|Catalyst::Manual::Tutorial::07_Debugging> chapter of the
1390ef0e 617tutorial.
3533daff 618
619
620=head1 CREATE A SQLITE DATABASE
621
622In this step, we make a text file with the required SQL commands to
a8f4e284 623create a database table and load some sample data. We will use SQLite
56a12748 624(L<https://www.sqlite.org>), a popular database that is lightweight and
f4e9de4a 625easy to use. Be sure to get at least version 3. Open F<myapp01.sql> in
a8f4e284 626your editor and enter:
3533daff 627
628 --
629 -- Create a very simple database to hold book and author information
630 --
f058768a 631 PRAGMA foreign_keys = ON;
3b1fa91b 632 CREATE TABLE book (
3533daff 633 id INTEGER PRIMARY KEY,
634 title TEXT ,
635 rating INTEGER
636 );
3b1fa91b 637 -- 'book_author' is a many-to-many join table between books & authors
638 CREATE TABLE book_author (
b66dd084 639 book_id INTEGER REFERENCES book(id) ON DELETE CASCADE ON UPDATE CASCADE,
640 author_id INTEGER REFERENCES author(id) ON DELETE CASCADE ON UPDATE CASCADE,
3533daff 641 PRIMARY KEY (book_id, author_id)
642 );
3b1fa91b 643 CREATE TABLE author (
3533daff 644 id INTEGER PRIMARY KEY,
645 first_name TEXT,
646 last_name TEXT
647 );
648 ---
649 --- Load some sample data
650 ---
3b1fa91b 651 INSERT INTO book VALUES (1, 'CCSP SNRS Exam Certification Guide', 5);
652 INSERT INTO book VALUES (2, 'TCP/IP Illustrated, Volume 1', 5);
653 INSERT INTO book VALUES (3, 'Internetworking with TCP/IP Vol.1', 4);
654 INSERT INTO book VALUES (4, 'Perl Cookbook', 5);
655 INSERT INTO book VALUES (5, 'Designing with Web Standards', 5);
656 INSERT INTO author VALUES (1, 'Greg', 'Bastien');
657 INSERT INTO author VALUES (2, 'Sara', 'Nasseh');
658 INSERT INTO author VALUES (3, 'Christian', 'Degu');
659 INSERT INTO author VALUES (4, 'Richard', 'Stevens');
660 INSERT INTO author VALUES (5, 'Douglas', 'Comer');
661 INSERT INTO author VALUES (6, 'Tom', 'Christiansen');
662 INSERT INTO author VALUES (7, 'Nathan', 'Torkington');
663 INSERT INTO author VALUES (8, 'Jeffrey', 'Zeldman');
664 INSERT INTO book_author VALUES (1, 1);
665 INSERT INTO book_author VALUES (1, 2);
666 INSERT INTO book_author VALUES (1, 3);
667 INSERT INTO book_author VALUES (2, 4);
668 INSERT INTO book_author VALUES (3, 5);
669 INSERT INTO book_author VALUES (4, 6);
670 INSERT INTO book_author VALUES (4, 7);
671 INSERT INTO book_author VALUES (5, 8);
3533daff 672
f4e9de4a 673Then use the following command to build a F<myapp.db> SQLite database:
3533daff 674
675 $ sqlite3 myapp.db < myapp01.sql
676
677If you need to create the database more than once, you probably want to
678issue the C<rm myapp.db> command to delete the database before you use
429d1caf 679the C<< sqlite3 myapp.db < myapp01.sql >> command.
3533daff 680
f4e9de4a 681Once the F<myapp.db> database file has been created and initialized, you
3533daff 682can use the SQLite command line environment to do a quick dump of the
683database contents:
684
685 $ sqlite3 myapp.db
c988c8b0 686 SQLite version 3.7.3
3533daff 687 Enter ".help" for instructions
f058768a 688 Enter SQL statements terminated with a ";"
3b1fa91b 689 sqlite> select * from book;
3533daff 690 1|CCSP SNRS Exam Certification Guide|5
691 2|TCP/IP Illustrated, Volume 1|5
692 3|Internetworking with TCP/IP Vol.1|4
693 4|Perl Cookbook|5
694 5|Designing with Web Standards|5
695 sqlite> .q
696 $
697
698Or:
699
3b1fa91b 700 $ sqlite3 myapp.db "select * from book"
3533daff 701 1|CCSP SNRS Exam Certification Guide|5
702 2|TCP/IP Illustrated, Volume 1|5
703 3|Internetworking with TCP/IP Vol.1|4
704 4|Perl Cookbook|5
705 5|Designing with Web Standards|5
706
707As with most other SQL tools, if you are using the full "interactive"
708environment you need to terminate your SQL commands with a ";" (it's not
709required if you do a single SQL statement on the command line). Use
710".q" to exit from SQLite from the SQLite interactive mode and return to
711your OS command prompt.
712
a8f4e284 713Please note that here we have chosen to use 'singular' table names. This
714is because the default inflection code for older versions of
715L<DBIx::Class::Schema::Loader> does NOT handle plurals. There has been
716much philosophical discussion on whether table names should be plural or
717singular. There is no one correct answer, as long as one makes a choice
718and remains consistent with it. If you prefer plural table names (e.g.
719you think that they are easier to read) then see the documentation in
658b8c29 720L<DBIx::Class::Schema::Loader::Base/naming> (version 0.05 or greater).
3b1fa91b 721
a8f4e284 722For using other databases, such as PostgreSQL or MySQL, see
56a12748 723L<Appendix 2|Catalyst::Manual::Tutorial::10_Appendices/APPENDIX 2: USING POSTGRESQL AND MYSQL>.
3533daff 724
acbd7bdd 725
8a472b34 726=head1 DATABASE ACCESS WITH DBIx::Class
3533daff 727
a8f4e284 728Catalyst can be used with virtually any form of datastore available via
c988c8b0 729Perl. For example, L<Catalyst::Model::DBI> can be used to access
730databases through the traditional Perl L<DBI> interface or you can use a
731model to access files of any type on the filesystem. However, most
732Catalyst applications use some form of object-relational mapping (ORM)
733technology to create objects associated with tables in a relational
734database, and Matt Trout's L<DBIx::Class> (abbreviated as "DBIC") is the
735usual choice (this tutorial will use L<DBIx::Class>).
a8f4e284 736
737Although DBIx::Class has included support for a C<create=dynamic> mode
738to automatically read the database structure every time the application
739starts, its use is no longer recommended. While it can make for
740"flashy" demos, the use of the C<create=static> mode we use below can be
741implemented just as quickly and provides many advantages (such as the
742ability to add your own methods to the overall DBIC framework, a
c988c8b0 743technique that we see in
744L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD>).
3533daff 745
1390ef0e 746
01df1cc9 747=head2 Create Static DBIx::Class Schema Files
27909ed4 748
01df1cc9 749B<Note:> If you are not following along in the Tutorial Virtual Machine,
cacb3819 750please be sure that you have version 1.27 or higher of L<DBD::SQLite> and
751version 0.39 or higher of L<Catalyst::Model::DBIC::Schema>. (The Tutorial
01df1cc9 752VM already has versions that are known to work.) You can get your
753currently installed version numbers with the following commands.
27909ed4 754
c988c8b0 755 $ perl -MCatalyst::Model::DBIC::Schema\ 999
c988c8b0 756 $ perl -MDBD::SQLite\ 999
27909ed4 757
f4e9de4a 758Before you continue, make sure your F<myapp.db> database file is in the
a8f4e284 759application's topmost directory. Now use the model helper with the
760C<create=static> option to read the database with
2217b252 761L<DBIx::Class::Schema::Loader> and
27909ed4 762automatically build the required files for us:
3533daff 763
4ab6212d 764 $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
b66dd084 765 create=static dbi:SQLite:myapp.db \
766 on_connect_do="PRAGMA foreign_keys = ON"
477a6d5b 767 exists "/home/catalyst/MyApp/script/../lib/MyApp/Model"
768 exists "/home/catalyst/MyApp/script/../t"
769 Dumping manual schema for MyApp::Schema to directory /home/catalyst/MyApp/script/../lib ...
27909ed4 770 Schema dump completed.
477a6d5b 771 created "/home/catalyst/MyApp/script/../lib/MyApp/Model/DB.pm"
772 created "/home/catalyst/MyApp/script/../t/model_DB.t"
3533daff 773
a8f4e284 774Please note the '\' above. Depending on your environment, you might be
775able to cut and paste the text as shown or need to remove the '\'
fce83e5f 776character to that the command is all on a single line.
3b1fa91b 777
f4e9de4a 778The F<script/myapp_create.pl> command breaks down like this:
27909ed4 779
780=over 4
781
782=item *
783
a8f4e284 784C<DB> is the name of the model class to be created by the helper in
f4e9de4a 785the F<lib/MyApp/Model> directory.
27909ed4 786
787=item *
788
c988c8b0 789C<DBIC::Schema> is the type of the model to create. This equates to
790L<Catalyst::Model::DBIC::Schema>, the standard way to use a DBIC-based
791model inside of Catalyst.
27909ed4 792
793=item *
794
795C<MyApp::Schema> is the name of the DBIC schema file written to
f4e9de4a 796F<lib/MyApp/Schema.pm>.
27909ed4 797
798=item *
799
c988c8b0 800C<create=static> causes L<DBIx::Class::Schema::Loader> to load the
801schema as it runs and then write that information out into
f4e9de4a 802F<lib/MyApp/Schema.pm> and files under the F<lib/MyApp/Schema>
c988c8b0 803directory.
27909ed4 804
805=item *
806
a8f4e284 807C<dbi:SQLite:myapp.db> is the standard DBI connect string for use with
808SQLite.
27909ed4 809
f058768a 810=item *
811
a8f4e284 812And finally, the C<on_connect_do> string requests that
2217b252 813L<DBIx::Class::Schema::Loader> create
a8f4e284 814foreign key relationships for us (this is not needed for databases such
815as PostgreSQL and MySQL, but is required for SQLite). If you take a look
f4e9de4a 816at F<lib/MyApp/Model/DB.pm>, you will see that the SQLite pragma is
c988c8b0 817propagated to the Model, so that SQLite's recent (and optional) foreign
a8f4e284 818key enforcement is enabled at the start of every database connection.
f058768a 819
27909ed4 820=back
821
01df1cc9 822
f4e9de4a 823If you look in the F<lib/MyApp/Schema.pm> file, you will find that it
a8f4e284 824only contains a call to the C<load_namespaces> method. You will also
f4e9de4a 825find that F<lib/MyApp> contains a C<Schema> subdirectory, which then has
a8f4e284 826a subdirectory called "Result". This "Result" subdirectory then has
827files named according to each of the tables in our simple database
f4e9de4a 828(F<Author.pm>, F<BookAuthor.pm>, and F<Book.pm>). These three files are
c988c8b0 829called "Result Classes" (or
830"L<ResultSource Classes|DBIx::Class::ResultSource>") in DBIx::Class
831nomenclature. Although the Result Class files are named after tables in
832our database, the classes correspond to the I<row-level data> that is
833returned by DBIC (more on this later, especially in
3ab6187c 834L<Catalyst::Manual::Tutorial::04_BasicCRUD/EXPLORING THE POWER OF DBIC>).
27909ed4 835
a8f4e284 836The idea with the Result Source files created under
f4e9de4a 837F<lib/MyApp/Schema/Result> by the C<create=static> option is to only
a8f4e284 838edit the files below the C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
839warning. If you place all of your changes below that point in the file,
840you can regenerate the automatically created information at the top of
841each file should your database structure get updated.
842
843Also note the "flow" of the model information across the various files
844and directories. Catalyst will initially load the model from
f4e9de4a 845F<lib/MyApp/Model/DB.pm>. This file contains a reference to
846F<lib/MyApp/Schema.pm>, so that file is loaded next. Finally, the call
a8f4e284 847to C<load_namespaces> in C<Schema.pm> will load each of the "Result
f4e9de4a 848Class" files from the F<lib/MyApp/Schema/Result> subdirectory. The
a8f4e284 849final outcome is that Catalyst will dynamically create three
850table-specific Catalyst models every time the application starts (you
851can see these three model files listed in the debug output generated
27909ed4 852when you launch the application).
853
f4e9de4a 854Additionally, the F<lib/MyApp/Schema.pm> model can easily be loaded
c988c8b0 855outside of Catalyst, for example, in command-line utilities and/or cron
f4e9de4a 856jobs. F<lib/MyApp/Model/DB.pm> provides a very thin "bridge" between
69d57cda 857Catalyst and this external database model. Once you see how we can
858add some powerful features to our DBIC model in
c988c8b0 859L<Chapter 4|Catalyst::Manual::Tutorial::04_BasicCRUD>, the elegance
860of this approach will start to become more obvious.
861
a8f4e284 862B<NOTE:> Older versions of
2217b252 863L<Catalyst::Model::DBIC::Schema> use the
a8f4e284 864deprecated DBIx::Class C<load_classes> technique instead of the newer
865C<load_namespaces>. For new applications, please try to use
866C<load_namespaces> since it more easily supports a very useful DBIC
867technique called "ResultSet Classes." If you need to convert an
868existing application from "load_classes" to "load_namespaces," you can
b66dd084 869use this process to automate the migration, but first make sure you have
870version C<0.39> of L<Catalyst::Model::DBIC::Schema> and
871L<DBIx::Class::Schema::Loader> version C<0.05000> or later.
27909ed4 872
b66dd084 873 $ # Re-run the helper to upgrade for you
27909ed4 874 $ script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
b66dd084 875 create=static naming=current use_namespaces=1 \
876 dbi:SQLite:myapp.db \
877 on_connect_do="PRAGMA foreign_keys = ON"
dc9a0503 878
f058768a 879
1390ef0e 880=head1 ENABLE THE MODEL IN THE CONTROLLER
881
f4e9de4a 882Open F<lib/MyApp/Controller/Books.pm> and un-comment the model code we
a1de5b65 883left disabled earlier so that your version matches the following
429d1caf 884(un-comment the line containing C<< [$c->model('DB::Book')->all] >>
a1de5b65 885and delete the next 2 lines):
1390ef0e 886
887 =head2 list
7ce05098 888
1390ef0e 889 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
7ce05098 890
1390ef0e 891 =cut
7ce05098 892
f058768a 893 sub list :Local {
1390ef0e 894 # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
895 # 'Context' that's used to 'glue together' the various components
896 # that make up the application
897 my ($self, $c) = @_;
7ce05098 898
f058768a 899 # Retrieve all of the book records as book model objects and store
900 # in the stash where they can be accessed by the TT template
0ed3df53 901 $c->stash(books => [$c->model('DB::Book')->all]);
7ce05098 902
1390ef0e 903 # Set the TT template to use. You will almost always want to do this
904 # in your action methods (action methods respond to user input in
905 # your controllers).
61cb69fd 906 $c->stash(template => 'books/list.tt2');
1390ef0e 907 }
908
429d1caf 909B<TIP>: You may see the C<< $c->model('DB::Book') >> un-commented above
910written as C<< $c->model('DB')->resultset('Book') >>. The two are
911equivalent. Either way, C<< $c->model >> returns a
2217b252 912L<DBIx::Class::ResultSet> which handles queries
a8f4e284 913against the database and iterating over the set of results that is
c93b5eaa 914returned.
915
429d1caf 916We are using the C<< ->all >> to fetch all of the books. DBIC supports
a8f4e284 917a wide variety of more advanced operations to easily do things like
918filtering and sorting the results. For example, the following could be
919used to sort the results by descending title:
c93b5eaa 920
3b1fa91b 921 $c->model('DB::Book')->search({}, {order_by => 'title DESC'});
c93b5eaa 922
a8f4e284 923Some other examples are provided in
924L<DBIx::Class::Manual::Cookbook/Complex WHERE clauses>, with additional
925information found at L<DBIx::Class::ResultSet/search>,
c988c8b0 926L<DBIx::Class::Manual::FAQ/Searching>, L<DBIx::Class::Manual::Intro> and
2217b252 927L<Catalyst::Model::DBIC::Schema>.
1390ef0e 928
929
930=head2 Test Run The Application
3533daff 931
c988c8b0 932First, let's enable an environment variable that causes L<DBIx::Class>
933to dump the SQL statements used to access the database. This is a
934helpful trick when you are trying to debug your database-oriented code.
935Press C<Ctrl-C> to break out of the development server and enter:
3533daff 936
937 $ export DBIC_TRACE=1
c988c8b0 938 $ script/myapp_server.pl -r
f33d1dd7 939
4d63a0d5 940This assumes you are using bash as your shell -- adjust accordingly if
3533daff 941you are using a different shell (for example, under tcsh, use
942C<setenv DBIC_TRACE 1>).
943
d0496197 944B<NOTE:> You can also set this in your code using
429d1caf 945C<< $class->storage->debug(1); >>. See
3533daff 946L<DBIx::Class::Manual::Troubleshooting> for details (including options
a8f4e284 947to log to a file instead of displaying to the Catalyst development
948server log).
3533daff 949
1390ef0e 950Then launch the Catalyst development server. The log output should
951display something like:
3533daff 952
f058768a 953 $ script/myapp_server.pl -r
3533daff 954 [debug] Debug messages enabled
1390ef0e 955 [debug] Statistics enabled
3533daff 956 [debug] Loaded plugins:
957 .----------------------------------------------------------------------------.
01df1cc9 958 | Catalyst::Plugin::ConfigLoader 0.30 |
a467a714 959 | Catalyst::Plugin::StackTrace 0.11 |
3533daff 960 '----------------------------------------------------------------------------'
7ce05098 961
3533daff 962 [debug] Loaded dispatcher "Catalyst::Dispatcher"
01df1cc9 963 [debug] Loaded engine "Catalyst::Engine"
477a6d5b 964 [debug] Found home "/home/catalyst/MyApp"
965 [debug] Loaded Config "/home/catalyst/MyApp/myapp.conf"
3533daff 966 [debug] Loaded components:
967 .-----------------------------------------------------------------+----------.
968 | Class | Type |
969 +-----------------------------------------------------------------+----------+
970 | MyApp::Controller::Books | instance |
971 | MyApp::Controller::Root | instance |
d0496197 972 | MyApp::Model::DB | instance |
3b1fa91b 973 | MyApp::Model::DB::Author | class |
974 | MyApp::Model::DB::Book | class |
975 | MyApp::Model::DB::BookAuthor | class |
1edbdee6 976 | MyApp::View::HTML | instance |
3533daff 977 '-----------------------------------------------------------------+----------'
7ce05098 978
3533daff 979 [debug] Loaded Private actions:
980 .----------------------+--------------------------------------+--------------.
981 | Private | Class | Method |
982 +----------------------+--------------------------------------+--------------+
983 | /default | MyApp::Controller::Root | default |
984 | /end | MyApp::Controller::Root | end |
1390ef0e 985 | /index | MyApp::Controller::Root | index |
3533daff 986 | /books/index | MyApp::Controller::Books | index |
987 | /books/list | MyApp::Controller::Books | list |
988 '----------------------+--------------------------------------+--------------'
7ce05098 989
3533daff 990 [debug] Loaded Path actions:
991 .-------------------------------------+--------------------------------------.
992 | Path | Private |
993 +-------------------------------------+--------------------------------------+
1390ef0e 994 | / | /default |
995 | / | /index |
996 | /books | /books/index |
3533daff 997 | /books/list | /books/list |
998 '-------------------------------------+--------------------------------------'
7ce05098 999
f058768a 1000 [info] MyApp powered by Catalyst 5.80020
01df1cc9 1001 HTTP::Server::PSGI: Accepting connections at http://0:3000
3533daff 1002
f4e9de4a 1003B<NOTE:> Be sure you run the F<script/myapp_server.pl> command from the
1004'base' directory of your application, not inside the F<script> directory
1005itself or it will not be able to locate the F<myapp.db> database file.
a8f4e284 1006You can use a fully qualified or a relative path to locate the database
1007file, but we did not specify that when we ran the model helper earlier.
3533daff 1008
1009Some things you should note in the output above:
1010
1011=over 4
1012
1390ef0e 1013=item *
3533daff 1014
c988c8b0 1015L<Catalyst::Model::DBIC::Schema> dynamically created three model
1016classes, one to represent each of the three tables in our database
a8f4e284 1017(C<MyApp::Model::DB::Author>, C<MyApp::Model::DB::BookAuthor>, and
1018C<MyApp::Model::DB::Book>).
3533daff 1019
1390ef0e 1020=item *
3533daff 1021
1022The "list" action in our Books controller showed up with a path of
1023C</books/list>.
1024
1025=back
1026
1027Point your browser to L<http://localhost:3000> and you should still get
1028the Catalyst welcome page.
1029
1030Next, to view the book list, change the URL in your browser to
1031L<http://localhost:3000/books/list>. You should get a list of the five
f4e9de4a 1032books loaded by the F<myapp01.sql> script above without any formatting.
1390ef0e 1033The rating for each book should appear on each row, but the "Author(s)"
191dee29 1034column will still be blank (we will fill that in later).
3533daff 1035
f4e9de4a 1036Also notice in the output of the F<script/myapp_server.pl> that
c988c8b0 1037L<DBIx::Class> used the following SQL to retrieve the data:
3533daff 1038
fce83e5f 1039 SELECT me.id, me.title, me.rating FROM book me
3533daff 1040
1041because we enabled DBIC_TRACE.
1042
0c51850e 1043You now have the beginnings of a simple but workable web application.
a8f4e284 1044Continue on to future sections and we will develop the application more
1045fully.
3533daff 1046
1047
1390ef0e 1048=head1 CREATE A WRAPPER FOR THE VIEW
1049
a8f4e284 1050When using TT, you can (and should) create a wrapper that will literally
1051wrap content around each of your templates. This is certainly useful as
1052you have one main source for changing things that will appear across
1053your entire site/application instead of having to edit many individual
1054files.
1390ef0e 1055
1056
1edbdee6 1057=head2 Configure HTML.pm For The Wrapper
1390ef0e 1058
a8f4e284 1059In order to create a wrapper, you must first edit your TT view and tell
1060it where to find your wrapper file.
1390ef0e 1061
f4e9de4a 1062Edit your TT view in F<lib/MyApp/View/HTML.pm> and change it to match
a8f4e284 1063the following:
1390ef0e 1064
1065 __PACKAGE__->config(
1066 # Change default TT extension
1067 TEMPLATE_EXTENSION => '.tt2',
1068 # Set the location for TT files
1069 INCLUDE_PATH => [
c2dfb562 1070 MyApp->path_to( 'root', 'src' ),
1390ef0e 1071 ],
1072 # Set to 1 for detailed timer stats in your HTML as comments
1073 TIMER => 0,
1074 # This is your wrapper template located in the 'root/src'
1075 WRAPPER => 'wrapper.tt2',
1076 );
1077
1078
1079=head2 Create the Wrapper Template File and Stylesheet
1080
1081Next you need to set up your wrapper template. Basically, you'll want
a8f4e284 1082to take the overall layout of your site and put it into this file. For
f4e9de4a 1083the tutorial, open F<root/src/wrapper.tt2> and input the following:
1390ef0e 1084
1085 <?xml version="1.0" encoding="UTF-8"?>
c988c8b0 1086 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" [%#
1087 %]"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
1390ef0e 1088 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
1089 <head>
1090 <title>[% template.title or "My Catalyst App!" %]</title>
1091 <link rel="stylesheet" href="[% c.uri_for('/static/css/main.css') %]" />
1092 </head>
7ce05098 1093
1390ef0e 1094 <body>
1095 <div id="outer">
1096 <div id="header">
1097 [%# Your logo could go here -%]
1098 <img src="[% c.uri_for('/static/images/btn_88x31_powered.png') %]" />
1099 [%# Insert the page title -%]
1100 <h1>[% template.title or site.title %]</h1>
1101 </div>
7ce05098 1102
1390ef0e 1103 <div id="bodyblock">
1104 <div id="menu">
1105 Navigation:
1106 <ul>
1107 <li><a href="[% c.uri_for('/books/list') %]">Home</a></li>
c988c8b0 1108 <li><a href="[% c.uri_for('/')
1109 %]" title="Catalyst Welcome Page">Welcome</a></li>
1390ef0e 1110 </ul>
1111 </div><!-- end menu -->
7ce05098 1112
1390ef0e 1113 <div id="content">
1114 [%# Status and error messages %]
1115 <span class="message">[% status_msg %]</span>
1116 <span class="error">[% error_msg %]</span>
1117 [%# This is where TT will stick all of your template's contents. -%]
1118 [% content %]
1119 </div><!-- end content -->
1120 </div><!-- end bodyblock -->
7ce05098 1121
1390ef0e 1122 <div id="footer">Copyright (c) your name goes here</div>
c2dfb562 1123 </div><!-- end outer -->
7ce05098 1124
1390ef0e 1125 </body>
1126 </html>
1127
1128Notice the status and error message sections in the code above:
1129
1130 <span class="status">[% status_msg %]</span>
1131 <span class="error">[% error_msg %]</span>
1132
1133If we set either message in the Catalyst stash (e.g.,
429d1caf 1134C<< $c->stash->{status_msg} = 'Request was successful!' >>) it will
a8f4e284 1135be displayed whenever any view used by that request is rendered. The
1136C<message> and C<error> CSS styles can be customized to suit your needs
f4e9de4a 1137in the F<root/static/css/main.css> file we create below.
1390ef0e 1138
a8f4e284 1139B<Notes:>
1390ef0e 1140
1141=over 4
1142
1143=item *
1144
a8f4e284 1145The Catalyst stash only lasts for a single HTTP request. If you need to
1146retain information across requests you can use
c988c8b0 1147L<Catalyst::Plugin::Session> (we will use Catalyst sessions in the
1148Authentication chapter of the tutorial).
1390ef0e 1149
1150=item *
1151
a8f4e284 1152Although it is beyond the scope of this tutorial, you may wish to use a
080bb620 1153JavaScript or AJAX tool such as jQuery (L<https://www.jquery.com>) or
56a12748 1154Dojo (L<https://dojotoolkit.org/>).
1390ef0e 1155
1156=back
1157
1158
1159=head3 Create A Basic Stylesheet
1160
1161First create a central location for stylesheets under the static
1162directory:
1163
1164 $ mkdir root/static/css
1165
f4e9de4a 1166Then open the file F<root/static/css/main.css> (the file referenced in
1390ef0e 1167the stylesheet href link of our wrapper above) and add the following
1168content:
1169
1170 #header {
1171 text-align: center;
1172 }
1173 #header h1 {
1174 margin: 0;
1175 }
1176 #header img {
1177 float: right;
1178 }
1179 #footer {
1180 text-align: center;
1181 font-style: italic;
1182 padding-top: 20px;
1183 }
1184 #menu {
1185 font-weight: bold;
1186 background-color: #ddd;
1187 }
1188 #menu ul {
1189 list-style: none;
1190 float: left;
1191 margin: 0;
1192 padding: 0 0 50% 5px;
1193 font-weight: normal;
1194 background-color: #ddd;
1195 width: 100px;
1196 }
1197 #content {
1198 margin-left: 120px;
1199 }
1200 .message {
1201 color: #390;
1202 }
1203 .error {
1204 color: #f00;
1205 }
1206
1207You may wish to check out a "CSS Framework" like Emastic
a8f4e284 1208(L<http://code.google.com/p/emastic/>) as a way to quickly provide lots
1209of high-quality CSS functionality.
1390ef0e 1210
1211
1212=head2 Test Run The Application
1213
a8f4e284 1214Hit "Reload" in your web browser and you should now see a formatted
1215version of our basic book list. (Again, the development server should
1216have automatically restarted when you made changes to
f4e9de4a 1217F<lib/MyApp/View/HTML.pm>. If you are not using the "-r" option, you
a8f4e284 1218will need to hit C<Ctrl-C> and manually restart it. Also note that the
1219development server does I<NOT> need to restart for changes to the TT and
1220static files we created and edited in the C<root> directory -- those
1221updates are handled on a per-request basis.)
f058768a 1222
a8f4e284 1223Although our wrapper and stylesheet are obviously very simple, you
1224should see how it allows us to control the overall look of an entire
1225website from two central files. To add new pages to the site, just
1226provide a template that fills in the C<content> section of our wrapper
1227template -- the wrapper will provide the overall feel of the page.
1390ef0e 1228
1229
a46b474e 1230=head2 Updating the Generated DBIx::Class Result Class Files
3533daff 1231
a8f4e284 1232If you take a look at the Schema files automatically generated by
1233L<DBIx::Class::Schema::Loader>, you will see that it has already defined
1234C<has_many> and C<belongs_to> relationships on each side of our foreign
f4e9de4a 1235keys. For example, take a look at F<lib/MyApp/Schema/Result/Book.pm> and
a8f4e284 1236notice the following code:
f058768a 1237
1238 =head1 RELATIONS
7ce05098 1239
f058768a 1240 =head2 book_authors
7ce05098 1241
f058768a 1242 Type: has_many
7ce05098 1243
f058768a 1244 Related object: L<MyApp::Schema::Result::BookAuthor>
7ce05098 1245
f058768a 1246 =cut
7ce05098 1247
f058768a 1248 __PACKAGE__->has_many(
1249 "book_authors",
1250 "MyApp::Schema::Result::BookAuthor",
1251 { "foreign.book_id" => "self.id" },
c988c8b0 1252 { cascade_copy => 0, cascade_delete => 0 },
f058768a 1253 );
1254
a8f4e284 1255Each C<Book> "has_many" C<book_authors>, where C<BookAuthor> is the
1256many-to-many table that allows each Book to have multiple Authors, and
c988c8b0 1257each Author to have multiple books. The arguments to C<has_many> are:
f058768a 1258
1259=over 4
1260
1261=item *
1262
a8f4e284 1263C<book_authors> - The name for this relationship. DBIC will create an
1264accessor on the C<Books> DBIC Row object with this name.
f058768a 1265
1266=item *
1267
a8f4e284 1268C<MyApp::Schema::Result::BookAuthor> - The name of the DBIC model class
1269referenced by this C<has_many> relationship.
f058768a 1270
1271=item *
1272
a8f4e284 1273C<foreign.book_id> - C<book_id> is the name of the foreign key column in
1274the I<foreign> table that points back to this table.
f058768a 1275
1276=item *
1277
a8f4e284 1278C<self.id> - C<id> is the name of the column in I<this> table that is
1279referenced by the foreign key.
f058768a 1280
1281=back
1282
a8f4e284 1283See L<DBIx::Class::Relationship/has_many> for additional information.
1284Note that you might see a "hand coded" version of the C<has_many>
1285relationship above expressed as:
f058768a 1286
1287 __PACKAGE__->has_many(
1288 "book_authors",
1289 "MyApp::Schema::Result::BookAuthor",
1290 "book_id",
1291 );
1292
a8f4e284 1293Where the third argument is simply the name of the column in the foreign
1294table. However, the hashref syntax used by
1295L<DBIx::Class::Schema::Loader> is more flexible (for example, it can
c988c8b0 1296handle "multi-column foreign keys").
f058768a 1297
a8f4e284 1298B<Note:> If you are using older versions of SQLite and related DBIC
1299tools, you will need to manually define your C<has_many> and
1300C<belongs_to> relationships. We recommend upgrading to the versions
1301specified above. :-)
f058768a 1302
f4e9de4a 1303Have a look at F<lib/MyApp/Schema/Result/BookAuthor.pm> and notice that
a8f4e284 1304there is a C<belongs_to> relationship defined that acts as the "mirror
1305image" to the C<has_many> relationship we just looked at above:
f058768a 1306
1307 =head1 RELATIONS
7ce05098 1308
f058768a 1309 =head2 book
7ce05098 1310
f058768a 1311 Type: belongs_to
7ce05098 1312
f058768a 1313 Related object: L<MyApp::Schema::Result::Book>
7ce05098 1314
f058768a 1315 =cut
7ce05098 1316
f058768a 1317 __PACKAGE__->belongs_to(
1318 "book",
1319 "MyApp::Schema::Result::Book",
1320 { id => "book_id" },
c988c8b0 1321 { join_type => "LEFT", on_delete => "CASCADE", on_update => "CASCADE" },
f058768a 1322 );
1323
a8f4e284 1324The arguments are similar, but see
f058768a 1325L<DBIx::Class::Relationship/belongs_to> for the details.
f33d1dd7 1326
a8f4e284 1327Although recent versions of SQLite and L<DBIx::Class::Schema::Loader>
1328automatically handle the C<has_many> and C<belongs_to> relationships,
7040a6cd 1329C<many_to_many> relationship bridges (not technically a relationship)
a8f4e284 1330currently need to be manually inserted. To add a C<many_to_many>
f4e9de4a 1331relationship bridge, first edit F<lib/MyApp/Schema/Result/Book.pm> and
a8f4e284 1332add the following text below the C<# You can replace this text...>
1333comment:
3533daff 1334
3533daff 1335 # many_to_many():
1336 # args:
7040a6cd 1337 # 1) Name of relationship bridge, DBIC will create accessor with this name
1390ef0e 1338 # 2) Name of has_many() relationship this many_to_many() is shortcut for
1339 # 3) Name of belongs_to() relationship in model class of has_many() above
3533daff 1340 # You must already have the has_many() defined to use a many_to_many().
fce83e5f 1341 __PACKAGE__->many_to_many(authors => 'book_authors', 'author');
3533daff 1342
a8f4e284 1343B<Note:> Be careful to put this code I<above> the C<1;> at the end of
1344the file. As with any Perl package, we need to end the last line with a
1345statement that evaluates to C<true>. This is customarily done with
3533daff 1346C<1;> on a line by itself.
1347
7040a6cd 1348The C<many_to_many> relationship bridge is optional, but it makes it
a8f4e284 1349easier to map a book to its collection of authors. Without it, we would
1350have to "walk" through the C<book_author> table as in
429d1caf 1351C<< $book->book_author->first->author->last_name >> (we will
a8f4e284 1352see examples on how to use DBIx::Class objects in your code soon, but
429d1caf 1353note that because C<< $book->book_author >> can return multiple authors,
a8f4e284 1354we have to use C<first> to display a single author). C<many_to_many>
1355allows us to use the shorter
429d1caf 1356C<< $book->author->first->last_name >>. Note that you cannot
a8f4e284 1357define a C<many_to_many> relationship bridge without also having the
5a82cb36 1358C<has_many> relationship in place.
3533daff 1359
f4e9de4a 1360Then edit F<lib/MyApp/Schema/Result/Author.pm> and add the reverse
a8f4e284 1361C<many_to_many> relationship bridge for C<Author> as follows (again, be
1362careful to put in above the C<1;> but below the C<# DO NOT MODIFY THIS
1363OR ANYTHING ABOVE!> comment):
3533daff 1364
3533daff 1365 # many_to_many():
1366 # args:
7040a6cd 1367 # 1) Name of relationship bridge, DBIC will create accessor with this name
3533daff 1368 # 2) Name of has_many() relationship this many_to_many() is shortcut for
1390ef0e 1369 # 3) Name of belongs_to() relationship in model class of has_many() above
3533daff 1370 # You must already have the has_many() defined to use a many_to_many().
fce83e5f 1371 __PACKAGE__->many_to_many(books => 'book_authors', 'book');
3533daff 1372
f058768a 1373
1390ef0e 1374=head2 Run The Application
3533daff 1375
4d63a0d5 1376Run the Catalyst development server script with the C<DBIC_TRACE> option
1377(it might still be enabled from earlier in the tutorial, but here is an
f33d1dd7 1378alternate way to specify the trace option just in case):
3533daff 1379
f058768a 1380 $ DBIC_TRACE=1 script/myapp_server.pl -r
3533daff 1381
1390ef0e 1382Make sure that the application loads correctly and that you see the
a1de5b65 1383three dynamically created model classes (one for each of the Result
a8f4e284 1384Classes we created).
3533daff 1385
a8f4e284 1386Then hit the URL L<http://localhost:3000/books/list> with your browser
f33d1dd7 1387and be sure that the book list still displays correctly.
3533daff 1388
c988c8b0 1389B<Note:> You will not see the authors yet because the view isn't taking
1390advantage of these relationships. Read on to the next section where we
1391update the template to do that.
3533daff 1392
1393
1394=head1 UPDATING THE VIEW
1395
a8f4e284 1396Let's add a new column to our book list page that takes advantage of the
1397relationship information we manually added to our schema files in the
f4e9de4a 1398previous section. Edit F<root/src/books/list.tt2> and replace the
080bb620 1399"empty" table cell "C<< <td></td> >>" with the following:
3533daff 1400
acbd7bdd 1401 ...
3533daff 1402 <td>
fce83e5f 1403 [% # NOTE: See Chapter 4 for a better way to do this! -%]
3533daff 1404 [% # First initialize a TT variable to hold a list. Then use a TT FOREACH -%]
1405 [% # loop in 'side effect notation' to load just the last names of the -%]
6d97b973 1406 [% # authors into the list. Note that the 'push' TT vmethod doesn't return -%]
3533daff 1407 [% # a value, so nothing will be printed here. But, if you have something -%]
6d97b973 1408 [% # in TT that does return a value and you don't want it printed, you -%]
1409 [% # 1) assign it to a bogus value, or -%]
1410 [% # 2) use the CALL keyword to call it and discard the return value. -%]
3533daff 1411 [% tt_authors = [ ];
1412 tt_authors.push(author.last_name) FOREACH author = book.authors %]
1413 [% # Now use a TT 'virtual method' to display the author count in parens -%]
1414 [% # Note the use of the TT filter "| html" to escape dangerous characters -%]
1415 ([% tt_authors.size | html %])
1416 [% # Use another TT vmethod to join & print the names & comma separators -%]
1417 [% tt_authors.join(', ') | html %]
1418 </td>
acbd7bdd 1419 ...
3533daff 1420
a8f4e284 1421B<IMPORTANT NOTE:> Again, you should keep as much "logic code" as
1422possible out of your views. This kind of logic belongs in your model
1423(the same goes for controllers -- keep them as "thin" as possible and
1424push all of the "complicated code" out to your model objects). Avoid
1425code like you see in the previous example -- we are only using it here
1426to show some extra features in TT until we get to the more advanced
1427model features we will see in Chapter 4 (see
fce83e5f 1428L<Catalyst::Manual::Tutorial::04_BasicCRUD/EXPLORING THE POWER OF DBIC>).
1429
a8f4e284 1430Then hit "Reload" in your browser (note that you don't need to reload
1431the development server or use the C<-r> option when updating TT
1432templates) and you should now see the number of authors each book has
1433along with a comma-separated list of the authors' last names. (If you
1434didn't leave the development server running from the previous step, you
1435will obviously need to start it before you can refresh your browser
1436window.)
1390ef0e 1437
1438If you are still running the development server with C<DBIC_TRACE>
1439enabled, you should also now see five more C<SELECT> statements in the
1440debug output (one for each book as the authors are being retrieved by
a46b474e 1441DBIx::Class):
3533daff 1442
fce83e5f 1443 SELECT me.id, me.title, me.rating FROM book me:
7ce05098 1444 SELECT author.id, author.first_name, author.last_name FROM book_author me
fce83e5f 1445 JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '1'
7ce05098 1446 SELECT author.id, author.first_name, author.last_name FROM book_author me
fce83e5f 1447 JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '2'
7ce05098 1448 SELECT author.id, author.first_name, author.last_name FROM book_author me
fce83e5f 1449 JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '3'
7ce05098 1450 SELECT author.id, author.first_name, author.last_name FROM book_author me
fce83e5f 1451 JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '4'
7ce05098 1452 SELECT author.id, author.first_name, author.last_name FROM book_author me
fce83e5f 1453 JOIN author author ON author.id = me.author_id WHERE ( me.book_id = ? ): '5'
c2dfb562 1454
f4e9de4a 1455Also note in F<root/src/books/list.tt2> that we are using "| html", a
429d1caf 1456type of TT filter, to escape characters such as < and > to &lt;
a8f4e284 1457and &gt; and avoid various types of dangerous hacks against your
1458application. In a real application, you would probably want to put "|
1459html" at the end of every field where a user has control over the
1460information that can appear in that field (and can therefore inject
1461markup or code if you don't "neutralize" those fields). In addition to
1462"| html", Template Toolkit has a variety of other useful filters that
a1de5b65 1463can be found in the documentation for L<Template::Filters>. (While we
1464are on the topic of security and escaping of dangerous values, one of
1465the advantages of using tools like DBIC for database access or
c988c8b0 1466L<HTML::FormFu> for form management [see
a1de5b65 1467L<Chapter 9|Catalyst::Manual::Tutorial::09_AdvancedCRUD::09_FormFu>]
c988c8b0 1468is that they automatically handle most escaping for you and therefore
1469dramatically increase the security of your app.)
3533daff 1470
1471
1390ef0e 1472=head1 RUNNING THE APPLICATION FROM THE COMMAND LINE
1473
a8f4e284 1474In some situations, it can be useful to run your application and display
1475a page without using a browser. Catalyst lets you do this using the
f4e9de4a 1476F<script/myapp_test.pl> script. Just supply the URL you wish to
a8f4e284 1477display and it will run that request through the normal controller
1478dispatch logic and use the appropriate view to render the output
1479(obviously, complex pages may dump a lot of text to your terminal
01df1cc9 1480window). For example, if C<Ctrl+C> out of the development server
1481and then type:
1390ef0e 1482
1483 $ script/myapp_test.pl "/books/list"
1484
1485You should get the same text as if you visited
1486L<http://localhost:3000/books/list> with the normal development server
c988c8b0 1487and asked your browser to view the page source. You can even pipe this
1488HTML text output to a text-based browser using a command like:
1489
1490 $ script/myapp_test.pl "/books/list" | lynx -stdin
1491
1492And you should see a fully rendered text-based view of your page. (If
1493you are following along in Debian 6, type
1494C<sudo aptitude -y install lynx> to install lynx.) If you do start
1495lynx, you can use the "Q" key to quit.
3533daff 1496
1390ef0e 1497
1498=head1 OPTIONAL INFORMATION
1499
4b4d3884 1500B<NOTE: The rest of this chapter of the tutorial is optional. You can
3ab6187c 1501skip to Chapter 4, L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>,
3533daff 1502if you wish.>
1503
acbd7bdd 1504
8a472b34 1505=head2 Using 'RenderView' for the Default View
1390ef0e 1506
1507Once your controller logic has processed the request from a user, it
1508forwards processing to your view in order to generate the appropriate
3533daff 1509response output. Catalyst uses
2217b252 1510L<Catalyst::Action::RenderView> by default
a8f4e284 1511to automatically perform this operation. If you look in
f4e9de4a 1512F<lib/MyApp/Controller/Root.pm>, you should see the empty definition for
a8f4e284 1513the C<sub end> method:
3533daff 1514
1515 sub end : ActionClass('RenderView') {}
1516
1390ef0e 1517The following bullet points provide a quick overview of the
3533daff 1518C<RenderView> process:
1519
1520=over 4
1521
1522=item *
1523
f4e9de4a 1524F<Root.pm> is designed to hold application-wide logic.
3533daff 1525
1526=item *
1527
1390ef0e 1528At the end of a given user request, Catalyst will call the most specific
1529C<end> method that's appropriate. For example, if the controller for a
1530request has an C<end> method defined, it will be called. However, if
1531the controller does not define a controller-specific C<end> method, the
f4e9de4a 1532"global" C<end> method in F<Root.pm> will be called.
3533daff 1533
1534=item *
1535
1536Because the definition includes an C<ActionClass> attribute, the
c988c8b0 1537L<Catalyst::Action::RenderView> logic will be executed B<after> any code
1538inside the definition of C<sub end> is run. See
1539L<Catalyst::Manual::Actions> for more information on C<ActionClass>.
3533daff 1540
1541=item *
1542
1390ef0e 1543Because C<sub end> is empty, this effectively just runs the default
1544logic in C<RenderView>. However, you can easily extend the
1545C<RenderView> logic by adding your own code inside the empty method body
1546(C<{}>) created by the Catalyst Helpers when we first ran the
f4e9de4a 1547F<catalyst.pl> to initialize our application. See
2217b252 1548L<Catalyst::Action::RenderView> for more
4d63a0d5 1549detailed information on how to extend C<RenderView> in C<sub end>.
3533daff 1550
1551=back
1552
1553
fce83e5f 1554=head2 RenderView's "dump_info" Feature
1555
a8f4e284 1556One of the nice features of C<RenderView> is that it automatically
1557allows you to add C<dump_info=1> to the end of any URL for your
1558application and it will force the display of the "exception dump" screen
1559to the client browser. You can try this out by pointing your browser to
1560this URL:
fce83e5f 1561
1562 http://localhost:3000/books/list?dump_info=1
1563
1564You should get a page with the following message at the top:
1565
7ce05098 1566 Caught exception in MyApp::Controller::Root->end "Forced debug -
fce83e5f 1567 Scrubbed output at /usr/share/perl5/Catalyst/Action/RenderView.pm line 46."
1568
a8f4e284 1569Along with a summary of your application's state at the end of the
1570processing for that request. The "Stash" section should show a
1571summarized version of the DBIC book model objects. If desired, you can
1572adjust the summarization logic (called "scrubbing" logic) -- see
2217b252 1573L<Catalyst::Action::RenderView> for
fce83e5f 1574details.
1575
a8f4e284 1576Note that you shouldn't need to worry about "normal clients" using this
1577technique to "reverse engineer" your application -- C<RenderView> only
1578supports the C<dump_info=1> feature when your application is running in
1579C<-Debug> mode (something you won't do once you have your application
1580deployed in production).
fce83e5f 1581
1582
3533daff 1583=head2 Using The Default Template Name
1584
1390ef0e 1585By default, C<Catalyst::View::TT> will look for a template that uses the
1586same name as your controller action, allowing you to save the step of
1587manually specifying the template name in each action. For example, this
c988c8b0 1588would allow us to remove the
429d1caf 1589C<< $c->stash->{template} = 'books/list.tt2'; >>
c988c8b0 1590line of our C<list> action in the Books controller.
a8f4e284 1591Open C<lib/MyApp/Controller/Books.pm> in your editor and comment out
1592this line to match the following (only the
429d1caf 1593C<< $c->stash->{template} >> line has changed):
3533daff 1594
1595 =head2 list
7ce05098 1596
3533daff 1597 Fetch all book objects and pass to books/list.tt2 in stash to be displayed
7ce05098 1598
3533daff 1599 =cut
7ce05098 1600
ddfbd850 1601 sub list :Local {
3533daff 1602 # Retrieve the usual Perl OO '$self' for this object. $c is the Catalyst
1603 # 'Context' that's used to 'glue together' the various components
1604 # that make up the application
1605 my ($self, $c) = @_;
7ce05098 1606
3533daff 1607 # Retrieve all of the book records as book model objects and store in the
1608 # stash where they can be accessed by the TT template
0ed3df53 1609 $c->stash(books => [$c->model('DB::Book')->all]);
7ce05098 1610
3533daff 1611 # Set the TT template to use. You will almost always want to do this
1612 # in your action methods (actions methods respond to user input in
1613 # your controllers).
61cb69fd 1614 #$c->stash(template => 'books/list.tt2');
3533daff 1615 }
1616
3533daff 1617
6961c906 1618You should now be able to access the L<http://localhost:3000/books/list>
1619URL as before.
3533daff 1620
a1de5b65 1621B<NOTE:> If you use the default template technique, you
429d1caf 1622will B<not> be able to use either the C<< $c->forward >> or the
1623C<< $c->detach >> mechanisms (these are discussed in Chapter 2 and
4b4d3884 1624Chapter 9 of the Tutorial).
3533daff 1625
a1de5b65 1626B<IMPORTANT:> Make sure that you do B<not> skip the following section
3b1fa91b 1627before continuing to the next chapter 4 Basic CRUD.
3533daff 1628
fce83e5f 1629
4d63a0d5 1630=head2 Return To A Manually Specified Template
3533daff 1631
429d1caf 1632In order to be able to use C<< $c->forward >> and C<< $c->detach >>
a8f4e284 1633later in the tutorial, you should remove the comment from the statement
f4e9de4a 1634in C<sub list> in F<lib/MyApp/Controller/Books.pm>:
3533daff 1635
0ed3df53 1636 $c->stash(template => 'books/list.tt2');
3533daff 1637
f4e9de4a 1638Then delete the C<TEMPLATE_EXTENSION> line in F<lib/MyApp/View/HTML.pm>.
3533daff 1639
a8f4e284 1640Check the L<http://localhost:3000/books/list> URL in your browser. It
1641should look the same manner as with earlier sections.
3533daff 1642
1643
24acc5d7 1644You can jump to the next chapter of the tutorial here:
1645L<Basic CRUD|Catalyst::Manual::Tutorial::04_BasicCRUD>
1646
1647
3533daff 1648=head1 AUTHOR
1649
1650Kennedy Clark, C<hkclark@gmail.com>
1651
53243324 1652Feel free to contact the author for any errors or suggestions, but the
1653best way to report issues is via the CPAN RT Bug system at
bb0999d3 1654L<https://rt.cpan.org/Public/Dist/Display.html?Name=Catalyst-Manual>.
53243324 1655
bb0999d3 1656Copyright 2006-2011, Kennedy Clark, under the
ec3ef4ad 1657Creative Commons Attribution Share-Alike License Version 3.0
56a12748 1658(L<https://creativecommons.org/licenses/by-sa/3.0/us/>).