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