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