]> git.decadent.org.uk Git - maypole.git/blob - doc/View.pod
c4691002a3ff36dafb1133454139c55eedb63ab2
[maypole.git] / doc / View.pod
1 =head1 Maypole View Classes
2
3 In a large application, you will almost certainly want to customize the
4 layout and design of the output pages. This task may even be the purview
5 of a separate team of HTML designers rather than the programmers. Since
6 a typical programmer will try to avoid touching HTML as much as possible
7 and a typical designer will try to avoid touching Perl code, programmers
8 have evolved a system of templating to separate the concerns of
9 programming and designing. 
10
11 One of the core concepts in Maypole is the I<view class>, and this is
12 responsible for routing the data produced in the model class into the
13 templates produced by the designers. Of course, there are a great many
14 possible templating systems and styles, and so there can be a great many
15 possible Maypole view classes. Each view class will take the data from
16 the controller, locate a template to be processed, and hand the whole
17 lot to its preferred templating module, which will then do the hard work
18 of filling in the template and coming up with the output.
19
20 You can choose whatever Maypole view class you want, but the default
21 view class is C<Maypole::View::TT>, and it feeds its data and templates
22 to a module called the Template Toolkit.
23
24 =head2 The Template Toolkit
25
26 The Template Toolkit, written by Andy Wardley, is a very powerful and
27 generic templating system. It provides its own little formatting language
28 which supports loops, conditionals, hash and array dereferences and
29 method calls, macro processing and a plug-in system to connect it to
30 external Perl modules. There are several good introductions to the
31 Template Toolkit available: you should have one installed as
32 L<Template::Tutorial::Datafile>; there's one at
33 L<http://www.perl.com/pub/a/2003/07/15/nocode.html>, and of course
34 there's the "Badger Book" - I<The Perl Template Toolkit>, by Andy et al.
35
36 We'll present a brief introduction here by deconstructing some of the 
37 templates used by Maypole applications. For more deconstruction, see
38 L<StandardTemplates.pod>, which is an entire chapter dealing with the
39 factory supplied templates.
40
41 Here's the template which is called for the front page of the standard
42 beer database application, C<custom/frontpage>.
43
44     [% INCLUDE header %]
45
46     <h2> The beer database </h2>
47
48     <TABLE BORDER="0" ALIGN="center" WIDTH="70%">
49     [% FOR table = config.display_tables %]
50     <TR>
51     <TD>
52     <A HREF="[%table%]/list">List by [%table %]</A>
53     </TD>
54     </TR>
55     [% END %]
56     </TABLE>
57
58 The first thing to note about this is that everything outside of the
59 Template Toolkit tags (C<[%> and C<%]>) is output verbatim. That is,
60 you're guaranteed to see 
61
62     <h2> The beer database </h2>
63
64     <TABLE BORDER="0" ALIGN="center" WIDTH="70%">
65
66 in the output somewhere. Inside the tags, magic happens. The first piece
67 of magic is the C<[% INCLUDE header %]> directive. This goes away and
68 finds a file called F<header> - don't worry about how it finds that yet,
69 we'll come to that later on - and processes the file's contents as
70 though they were right there in the template. Our F<header> file happens
71 not to contain any C<[% %]> tags, but if it did, they would be processed
72 in the same way as the ones in F<frontpage>. 
73
74 The next piece of magic is this line:
75
76     [% FOR table = config.display_tables %]
77
78 We're seeing a lot of things here at once. C<config> is where we should
79 start looking. This is a template variable, which is what templates are
80 all about - templating means getting data from somewhere outside and
81 presenting it to the user in a useful way, and the C<config> hash is a
82 prime example of data that we want to use. It's actually the hash of
83 configuration parameters for this Maypole application, and one of the
84 keys in that hash is C<display_tables>, the database tables that we're
85 allowed to play with. In the application, we probably said something
86 like
87
88     BeerDB->config->{display_tables} = [qw[beer brewery pub style]];
89
90 This stores the four values - C<beer>, C<brewery>, C<pub> and C<style> -
91 in an array, which is placed in the config hash under the key
92 C<display_tables>. Now we're getting them back again.
93
94 The Template Toolkit's dot operator is a sort of do-the-right-thing
95 operator; we can say C<array.0> to get the first element of an array,
96 C<hash.key> to look up the C<key> key in a hash, and C<object.method> to
97 call C<method> on an object. So, for instance, if we said
98 C<config.display_tables.2>, we'd look up the C<display_tables> key in
99 the configuration hash and get our array back, then look up the 2nd
100 element and get C<pub>.
101
102 The C<FOR> loop will repeat the code four times, setting our new
103 variable C<table> to the appropriate array element. This code:
104
105     [% FOR table = config.display_tables %]
106         Hello [% table %]!
107     [% END %]
108
109 will produce something like
110
111     Hello beer!
112     Hello brewery!
113     Hello pub!
114     Hello style!
115
116 In our case, though, we're printing out a table element linking to each
117 database table in turn.
118
119 Here's a slightly more complicated example, adapted from F<factory/pager>.
120 This template is responsible for printing the little page menu at the
121 bottom of a listing if there are more rows in the listing than we want
122 on a single page.
123
124     [% PROCESS macros %]
125     <P ALIGN="center">Pages:
126     [%
127          FOREACH num = [pager.first_page .. pager.last_page];
128               IF num == pager.current_page;
129                 "["; num; "] ";
130               ELSE;
131                 SET args = "?page=" _ num;
132                 SET label = "[" _ num _ "]";
133                 link(classmetadata.moniker, "list", args, label);
134               END;
135          END;
136     %]
137     </P>
138
139 Maypole will be providing a whole bunch of variables to this template,
140 and we'll look at them all in a moment, but the only ones we need to care
141 about are C<pager> and C<classmetadata>. 
142
143 We start by loading in a bunch of macros. Macros are Template Toolkit's
144 functions - you can provide them some parameters and they'll run a little
145 sub-template based on them. The C<macros> file contains some handy macros
146 that I've found useful for constructing Maypole templates; again, these
147 will be covered in full detail in L<StandardTemplates.pod>.
148
149 We're going to be displaying something like this:
150
151     Pages: [1] [2] [3] [4]
152
153 with most of those numbers being a link to the appropriate page. This
154 mean we're going to have to have a list of numbers, and the C<FOREACH> loop
155 provides this: (C<FOREACH> and C<FOR> are identical, just like in Perl.)
156
157          FOREACH num = [pager.first_page .. pager.last_page];
158
159 Here we're manually constructing an array of numbers, using the range
160 operator (C<..>) to fill in all the numbers from the C<first_page> (1)
161 to the C<last_page> (4). The same dot operator is used to ask the C<pager>
162 what its C<first_page> and C<last_page> is. Remember when we said 
163 C<config.display_tables>, we were looking up the C<display_tables> key
164 in the C<config> hash? Well, this time we're not looking anything up in
165 a hash. C<pager> is an object, and C<first_page> is a method. Thing is,
166 you don't have to care. You can pretend it's a hash if you want. The
167 syntax is the same, and Template Toolkit knows the right thing to do.
168
169 Now we're going to be executing this loop four times, once each for C<num>
170 being set to 1, 2, 3, and 4. At some point, we'll come across the page
171 that we're actually on right now:
172
173       IF num == pager.current_page;
174
175 and in that case, we don't want to produce a link to it. We just want
176 to output it as text, surrounded by square brackets:
177
178                 "["; num; "] ";
179
180 We're using string literals to output the brackets. We don't have to
181 do that. We could say it this way:
182
183     [% ...
184       IF num == pager.current_page;
185     %]
186         [ [% num %] ] 
187     [% ELSE %]
188        ...
189     [% END %]
190
191 But you know, I quite like it my way.
192
193 Now if the number we're printing isn't the number of the current page,
194 we want to make a link. Here's how we do it:
195
196     SET args = "?page=" _ num;
197     SET label = "[" _ num _ "]";
198     link(classmetadata.table, "list", args, label);
199
200 C<SET> declares a new variable of our own. If there was anything called
201 C<args> before, there isn't now. It's going to be the result of our
202 statement C<"?page=" _ num>. C<_> is the concatenation operator, and
203 glues C<?page=> onto the front of our number. So if we want to link to
204 page 4, then the C<args> variable will contain C<?page=4>. Similarly,
205 the C<label> variable will be C<[4]>.
206
207 Now we call a macro, C<link> with these two variables and the value of
208 C<classmetadata.table>. This macro takes four arguments, C<table>, 
209 C<action>, C<args> and C<label>, and constructs a link of the form
210
211     <A HREF="[% config.base_url %]/[% table %]/[% action %][% args %]">
212     [% label %]
213     </A>
214
215 In our case, it'll be filled in like so:
216
217     <A HREF="[% config.base_url %]/[% classmetadata.table %]/list?page=4">
218     [ 4 ]
219     </A>
220
221 Where C<classmetadata.table> will actually be the name of the current
222 table, and C<config.base_url> will be replaced by the appropriate URL for
223 this application.
224
225 =head2 Locating Templates
226
227 Another feature of C<Maypole::View::TT> which may not be present in
228 alternate view class implementations - although they are strongly
229 encouraged to provide it - is the way that templates are located.
230 (Remember, I B<did> say I'd tell you about that later.) Template Toolkit
231 allows whatever uses it to provide a path for template files to be
232 located in. C<Maypole::View::TT> feeds it up to three possible
233 directories to look things up in, and it will try to find a template in
234 each of these in turn.
235
236 When you configure a Maypole application, you can tell it the base
237 directory of your templates like so:
238
239     BeerDB->config->{template_root} = "/var/www/beerdb/templates";
240
241 If you don't do this, most Maypole front-ends will use the current
242 directory, which is generally what you want anyway. Off this directory,
243 Maypole will look for a set of subdirectories.
244
245 For instance, I said we were in the middle of processing the front page
246 and looking up a template file called F<header>. Maypole will first look
247 for this file in the F<custom> subdirectory. (say,
248 F</var/www/beerdb/templates/custom>) If it doesn't find one, then it
249 looks in the F<factory> subdirectory. If it doesn't find one there, then
250 it gives up and dies with an error. But that's your fault, since you've
251 called for a template which doesn't exist. Don't do that. 
252
253 This behaviour means that you can provide your own site-specific
254 templates, but if you don't do so, then you get to use a generic one
255 provided by Maypole. Maypole's "factory setting" templates are written
256 in such a way as to try and do the right thing no matter what your
257 application does. They are occasionally successful at this. 
258
259 Now the front page was a pretty simple example, since Maypole only looks
260 up two directories. In most cases, it checks an additional directory,
261 and this directory depends entirely on what Maypole is doing.
262
263 If you're writing an e-commerce application, for example, you may well
264 have a table which represents the product catalogue and all the products
265 you can buy. Let's call this the C<product> table. You'll also have a
266 data source which is specific to the user which contains all the
267 products that they're buying on this particular visit to the site. In
268 time-honoured tradition, we'll call this the C<basket> table.
269
270 Now it ought to be reasonably apparent that you don't want the basket
271 to be displayed in exactly the same way as the product catalogue. The
272 templates for C<product/list> and C<basket/list> need to be different.
273 This is where the third directory comes in. The other directory, which
274 Maypole checks very first of all, is specific to the table that you're
275 viewing. So if you go to C<http://your.shop.com/basket/list>, Maypole
276 will look in the F<basket> directory first for a file called F<list>,
277 and second in the F<custom> directory for a site-wide list template,
278 and then fall-back to the F<factory> directory for a generic list
279 template. It should be obvious that you probably want to provide all
280 of F<basket/list>, F<basket/view>, F<product/list>, F<product/view>
281 and any other combination of classes and actions that you can think of.
282
283 =head2 What Maypole provides to a template
284
285 C<Maypole::View::TT> provides quite a variety of template variables to
286 the template. As these are the building blocks of your pages, it's worth
287 looking at precisely what variables are available.
288
289 The most important variable is called C<objects>, and is a list of all
290 the objects that this page is going to deal with. For instance,
291 in the template F</beer/view>, C<objects> will contain the C<BeerDB::Beer>
292 object for the 23rd item in the database, while F</brewery/list> will
293 fill C<objects> will all the breweries; or at least, all the breweries
294 on the current page.
295
296 This variable is so important that to help design templates with it,
297 C<Maypole::View::TT> provides a helpful alias to it depending on
298 context. For instance, if you're writing your own F</brewery/list>
299 template, the data in C<objects> is also available in a template
300 variable called C<breweries>. If you're working on F</brewery/view>,
301 though, it's available in C<brewery>, since there's only one brewery to
302 be displayed.
303
304 Additionally, you can get the base URL for the application from the
305 C<base> template variable; this allows you to construct links, as we
306 saw earlier:
307
308     <A HREF="[% base %]/brewery/edit/[% brewery.id %]">Edit this brewery</A>
309
310 You can also get at the rest of the configuration for the site with the
311 C<config> variable as we saw above, and the entire request object in 
312 C<request>, should you really need to poke at it. (I've only found this
313 useful when working with authentication modules which stash a current user
314 object in C<request.user>.)
315
316 To allow the construction of the "generic" templates which live in
317 F<factory>, Maypole also passes in a hash called C<classmetadata>,
318 which contains all sorts of useful information about the class under
319 examination:
320
321 =over 3
322
323 =item C<table>
324
325 This is the name of the table that is represented by the class.
326
327 =item C<class>
328
329 This is the Perl's idea of the class; you don't need this unless you're
330 doing really tricky things.
331
332 =item C<moniker>
333
334 This is a more human-readable version of the table name, that can be
335 used for display.
336
337 =item C<plural>
338
339 The same, but a correctly-formed plural. For instance, "breweries".
340
341 =item C<columns>
342
343 The list of columns for display; see the section "Customizing Generic
344 CRUD Applications" in L<StandardTemplates.pod>.
345
346 =item C<colnames>
347
348 This is a hash mapping the database's name for a column to a more
349 human-readable name. Again, see "Customizing Generic CRUD Applications>.
350
351 =item C<cgi>
352
353 This is a slightly trickier one. It is a hash mapping column names to
354 a C<HTML::Element> suitable for entering data into a new instance of
355 that class. That is, for the C<beer> table, C<classmetadata.cgi.style>
356 should be a C<HTML::Element> object containing a drop-down list of
357 beer styles. This is explained in L<StandardTemplates.pod>.
358
359 =item C<description>
360
361 This is the human-readable description provided by a class.
362
363 =item C<related_accessors>
364
365 This is a list of accessors which can be called on an object to get
366 lists of other things that this object "has". For instance, on a
367 brewery, it would return C<beers>, since calling C<brewery.beers> would
368 give you a list of beers produced by the brewery. Note that this only
369 caters for accessors defining one-to-many relationships, not the
370 ordinary one-to-one relationships, such as C<style>.
371
372 =back
373
374 =head2 Other view classes
375
376 Please note that these template variables, C<config>, C<classmetadata>,
377 C<objects> and its user-friendly alias, as well as the rest of them are
378 a function of one particular view class, the default
379 C<Maypole::View::TT> class. Other view classes may need to present an
380 entirely different set of template variables, since the default ones
381 might not make sense. The templates may look wildly different in other
382 view class implementations. But that's OK, because you couldn't
383 necessarily use the same templates with a different templating system
384 anyway.
385
386 For instance, in really dumb templating languages which can't handle
387 dereferencing hashes or arrays - no wait, that's most of them - passing
388 in a hash reference like C<classmetadata> won't help you since you can't
389 get at any of its elements. So you'll need to take a look at the
390 documentation for the appropriate view class to see what template
391 variables it provides.
392
393 So if, for some perverse reason, the Template Toolkit just isn't good
394 enough for you, then you can set your own view class while configuring
395 your application:
396
397    package BeerDB;
398    use base 'Apache::MVC';
399    ...
400    BeerDB->setup("dbi:SQLite:t/beerdb.db");
401    BeerDB->config->{uri_base} = "http://localhost/beerdb/";
402    BeerDB->config->{rows_per_page} = 10;
403    BeerDB->config->{view} = "Maypole::View::Mason"; 
404
405 Where do these alternate view classes come from? Gentle reader, they
406 come from B<you>.
407
408 =head2 Building your own view class
409
410 I<You should probably skip this section for the first few readings of this manual. It's only intended for people extending Maypole.>
411
412 Imagine you've found a brand new templating system that's B<much better>
413 than the Template Toolkit. I know I'm stretching your imagination a bit
414 here, but try. You'd like to use it with Maypole, which means writing your
415 own view class. How is it done?
416
417 We'll demonstrate by implementing a view class for C<HTML::Mason>,
418 although no value judgement is implied. C<HTML::Mason> is a templating
419 system which embeds pure Perl code inside its magic tags. The good side
420 of this is that it can get into hash references and objects, and so
421 providing C<classmetadata>, C<config> and the Maypole request object
422 will work out just fine. The down side is that C<HTML::Mason> is used to
423 running more or less standalone, and having all the template variables
424 it wants already at its disposal through CGI parameters and the like, so
425 we have to fiddle a bit to get these variables into our template.
426
427 The key to building view classes is C<Maypole::View::Base>. This is the
428 base class that you're going to inherit from and, to be honest, it does
429 pretty much everything you need. It provides a method called C<vars>
430 which returns a hash of all the template variables described above, so
431 it would be good to feed those into C<HTML::Mason>. It also provides a
432 C<paths> method which turns returns the full filesystem path of the
433 three possible template paths as shown above. Again, it would be good to
434 use this as our component paths if we can. It also has some methods we
435 can override if we want to, but they're not massively important, so you
436 can see L<Maypole::View::Base> for more about them. 
437
438 The module will do the right thing for us if we agree to provide a
439 method called C<template>. This is responsible for taking the Maypole
440 request object (of which more later) and putting the appropriate output
441 either into C<$r-E<gt>{output}> or C<$r-E<gt>{error}>, depending, of
442 course, whether things are OK or whether we got an error.
443
444 Thankfully, C<HTML::Mason> makes things really easy for us. We B<can>
445 use multiple template roots, so we can use the C<paths> method; we
446 B<can> pass in a hash full of interesting data structures, so we can use
447 the C<vars> method too. In fact, we have to do very little to make
448 C<Maypole::View::Mason> work. Which is somewhat annoying, because it
449 makes a boring example. But it means I can leave the fun ones to you!
450
451 The doing-the-templating, in Mason and in any templating system, depends on
452 three things: the paths that we're going to use to find our templates, the
453 template name that we've been asked to fill out, and the set of variables that
454 are going to be fed to the template. We'll assemble these for reference:
455
456     sub template {
457         my ($self, $r) = @_;
458         my @paths = $self->paths($r);
459         my $template = $r->template;
460         my %vars = $self->args($r);
461
462 We'll also declare somewhere to temporarily store the output:
463
464         my $output;
465
466 Now comes the part where we have to actually do something
467 templating-language specific, so we open up our copy of "Embedding Perl
468 in HTML with Mason" and find the bit where it talks about running Mason
469 standalone. We find that the first thing we need to do is create a
470 C<HTML::Mason::Interp> object which knows about the component roots.
471 There's a slight subtlety in that the component roots have to be
472 specified as an array of arrays, with each array being a two-element
473 list of label and path, like so:
474
475     comproot => [
476         [ class   => "/var/www/beerdb/templates/brewery" ],
477         [ custom  => "/var/www/beerdb/templates/custom" ],
478         [ factory => "/var/www/beerdb/templates/factory" ],
479     ]
480
481 We also find that we can set the output method here to capture Mason's
482 output into a scalar, and also that we can tell Mason to generate
483 sensible error messages itself, which saves us from having to worry
484 about catching errors. At the end of all this, we come up with a
485 constructor for our C<HTML::Mason::Interp> object which looks like this:
486
487     my $label = "path0";
488     my $mason = HTML::Mason::Interp->new(
489         comproot => [ map { [ $label++ => $_ ] } @paths ],
490         output_method => \$output,
491         error_mode => "output" 
492     );
493
494 The next thing we need to do is run the template with the appropriate
495 template variables. This turns out to be really easy:
496
497     $mason->exec($template, %vars);
498
499 Now we've got the data in C<$output>, we can put it into the request object,
500 and return a true value to indicate that we processed everything OK. (If there
501 was an error, then Mason will have produced some suitable output, so we can
502 pretend that everything's OK anyway.)
503
504     $r->{output} = $output;
505     return 1;
506
507 And that's all we need to do. Barely twenty lines of code for the finished
508 product. Wasn't that easy? Don't you feel inspired to write Maypole view
509 classes for your favourite templating language? Well, don't let me stop you!
510 Patches are always welcome!