Maypole5
From Books
Contents |
[edit] Template Toolkit
Once we have the data we want, the next stage is to display it, and this is the job of the view class. Again, Maypole is not necessarily tied down to one particular view class, and classses have been written to allow the use of systems like HTML::Mason for templating Maypole applications. You can certainly go that way if you want to, but as with Class::DBI, Maypole has been most successfully used with the Template Toolkit. In this section, therefore, we'll present an introduction to how the Template Toolkit is used in general, and also specifically within Maypole.
[edit] Basic Templating
XXX
The most basic uses of Template Toolkit use it just like other templating systems: to fill scalars into a form. Variable names are enclosed in [% ... %] pairs, like so:
[% today %] [% title %] [% forename %] [% surname %] [% address %] Dear [% title %] [% surname %], Thank you for your letter dated [% their_date %]. This is to confirm that we have received it and will respond with a more detailed response as soon as possible. In the mean time, we enclose more details of ...
Notice, however, that our variables inside the Toolkit [% and %] delimiters aren't Perl variables with the usual type sign in front of them; instead, they're now Template Toolkit variables. Template Toolkit variables can be more than just simple scalars, though; complex data structures and even Perl objects are available to Template Toolkit through a simple, consistent syntax. For instance, we could say:
[% today %]
[% name.title %] [% name.forename %] [% name.surname %]
The dot operator is equivalent to Perl's -> - it dereferences array and hash reference elements, and can also be used to call methods on objects, so here name could be a hash, or it could be an object, but so long as it has those accessors which give appropriate answers, we don't need to care. If we know they are objects, then of course we can give parameters to the method calls:
[% name.salutation("Dear %s,") %]
If our variables are arrays underneath, we can use FOREACH to loop over their elements. Here's an example from a newsletter I produce with TT:
[edit] In brief
-
[% FOREACH point = brief %]
- [% point %]
[% END %]
As you can see, the syntax is inspired by Perl - we can foreach over a list and use a local variable point to represent each element of the iterator.
Similarly, there's also the IF/ELSIF/ELSE block:
[% IF delinquent %] Our records indicate that this is the second issuing of this invoice. Please pay IMMEDIATELY. [% ELSE %] Payment terms: <30 days. [% END %]
[edit] Includes, Macros, Plugins, Filters
If that were all that Template Toolkit would do, it would be on a par with other templating systems. But there's far more.
[edit] Includes
Includes allow us to split out the template into more managable components, placed in individual files; for instance, Maypole's factory templates use static header and footer files. Here's the header:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>[% config.application_name || "A poorly configured Maypole application" %]</title> <meta http-equiv="Content-Language" content="en" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link title="Maypole Default" href="/maypole.css" type="text/css" rel="stylesheet" /> </head> <body>
This is placed inside a file called header, and so the factory templates begin with:
[% INCLUDE header %]
So if you want to supply your own look and feel to the default CRUD site, you could do so by creating custom/header, which will override the default factory header. As you can see, included files receive the template variables as well, such as config in our example.
[edit] Macros
Additionally, you can define macros to simplify repeated pieces of coding. For instance, we've seen that Maypole URLs are dissected into table, action, and arguments; the factory macros include some code to construct a link by putting these back together again:
[% MACRO link(table, command, additional, label) BLOCK; '<A HREF="' _ base _ "/" _ table _ "/" _ command _ "/" _ additional _ '">'; label; "</A>"; END; %]
Notice here the use of Perl 6 style concatenation operators. XXX
[edit] Plugins
Of slightly less common use, but astonishing versatility, is the Template Toolkit plugin system. This provides the ability for templates to call out to Perl code. For instance, the amazingly helpful (but somewhat dangerous) Template::Plugin::Class allows you to call class methods from within TT:
[% USE tagcloud_c = Class("HTML::TagCloud");
SET tagcloud = tagcloud_c.new;
FOREACH tag = tags;
tagcloud.add(...);
END
tagcloud.html;
%]
XXX
[edit] Filters
Template Toolkit filters are a little like Unix filters - they're little routines which take an input, transform it, and spit it back out again. And just like Unix filters, they're connected to our template output with a pipe symbol. (|)
For instance, the oddly named format filter performs printf-like formatting on its input:
[% job.description | format("%60s") %] : [% job.cost %]
We can also filter whole blocks of template content. For example, if we wanted to format the output as HTML, we could apply the html_entity filter to replace entities with their HTML encoding:
[% FILTER html_entity %] Payment terms: < 30 days. [% END %]
This turns into:
Payment terms: < 30 days.
Other interesting filters include the upper, lower, ucfirst and lcfirst filters to change the casing of the text; uri to URI-escape any special characters; eval to treat the text to another level of Template processing, and perl_eval to treat the output as Perl, eval that, and then add the output to the template. For a fuller list of filters with examples, see the Template::Manual::Filters documentation.
[edit] TT Within Maypole
As with any view class, TT receives certain template variables from Maypole:
Table 4.1. Template variables request The Maypole request object objects The objects to be displayed base The base URL config The Maypole::Config object classmetadata The class metadata as described in Table 1.1, “The classmetadata hash” Anything else The contents of $r->template_args is added to the set of template variables at this point.
Additionally, Maypole makes an alias for the objects it passes in; for instance, in /supporters/list/ the objects can be referred to as supporters as well as objects. If there's only one item in the objects array, it's given a singular name such as supporter. This makes the templates much easier to read.
The factory templates are written to use these template variables, and particularly the classmetadata, to provide a generic CRUD interface. When you are writing your own templates, you can use as many or as few elements of the factory templates as you like, but you will find that writing your
own templates is actually considerably simpler.