1 package Maypole::View::TT;
2 use base 'Maypole::View::Base';
3 use Maypole::Constants;
5 use File::Spec::Functions qw(catdir tmpdir);
8 { local $/; $error_template = <DATA>; }
14 my ( $self, $r ) = @_;
16 unless ($self->{tt}) {
17 my $view_options = $r->config->view_options || {};
18 $self->{provider} = Template::Provider->new($view_options);
19 $self->{tt} = Template->new({
21 LOAD_TEMPLATES => [ $self->{provider} ],
25 $self->{provider}->include_path([ $self->paths($r) ]);
27 my $template_file = $r->template;
28 my $ext = $r->config->template_extension;
29 $template_file .= $ext if defined $ext;
32 if ($self->{tt}->process($template_file, { $self->vars($r) }, \$output )) {
33 $r->{output} = $output;
37 $r->{error} = "TT error for template '$template_file'\n" . $self->{tt}->error;
44 my ($self, $r, $error, $type) = @_;
46 # Need to be very careful here.
47 my $tt = Template->new;
48 if ($tt->process(\$error_template,
49 { err_type => $type, error => $error,
50 config => { %{$r->{config}}},
51 request => $r, # We have that at least
52 eval{$self->vars($r)} }, \$output )) {
53 $r->{output} = $output;
54 if ($tt->error) { $r->{output} = "<html><body>Even the error template
55 errored - ".$tt->error."</body></html>"; }
56 $r->{content_type} ||= "text/html";
57 $r->{document_encoding} ||= "utf-8";
66 Maypole::View::TT - A Template Toolkit view class for Maypole
70 BeerDB->config->view("Maypole::View::TT"); # The default anyway
72 # Set some Template Toolkit options
73 BeerDB->config->view_options( {
75 COMPILE_DIR => '/var/tmp/mysite/templates',
90 This is the default view class for Maypole; it uses the Template Toolkit to fill
91 in templates with the objects produced by Maypole's model classes. Please see
92 the L<Maypole manual|Maypole::Manual>, and in particular, the
93 L<view|Maypole::Manual::View> chapter for the template variables available and
94 for a refresher on how template components are resolved.
96 The underlying Template toolkit object is configured through
97 C<$r-E<gt>config-E<gt>view_options>. See L<Template|Template> for available
104 Processes the template and sets the output. See L<Maypole::View::Base>
108 =head1 TEMPLATE TOOLKIT INTRODUCTION
110 The Template Toolkit uses it's own mini language described in
111 L<Template::Manual::Directives>.
113 A simple example would be :
119 Dear [% title %] [% surname %],
120 Thank you for your letter dated [% your.date %]. This is to
121 confirm that we have received it and will respond with a more
122 detailed response as soon as possible. In the mean time, we
123 enclose more details of ...
127 TT uses '[%' and '%]' (by default) to delimit directives within a template, and
128 the simple directives above just display the value of variable named within
129 those delimiters -- [% title %] will be replaced inline with the value of the
130 'title' variable passed in the 'stash' to the template when it is processed.
132 You can access nested data through the dot ('.') operator, which will
133 dereference array or hash elements, but can also be used to call methods on
134 objects, i.e. '[% name.salutation("Dear %s,") %]'. The other main operator is
135 underscore ('_'), which will concatonate strings or variables.
137 The value returned by a directive replaces the directive inline when the
138 template is processes, you can also SET a value which will not return anything,
139 or CALL a method or operation which will also not return anything.
141 You can specify expressions using the logical (and, or, not, ?:) and mathematic
142 operators (+ - * / % mod div).
146 [% template.title or default.title %]
150 [% order.nitems ? checkout(order.total) : 'no items' %]
154 TT allows you to include or re-use templates through it's INCLUDE, PROCESS and
155 INSERT directives, which are fairly self explainatory. You can also re-use parts
156 of template with the BLOCK or MACRO directives.
158 Conditional and Looping constructs are simple and powerful, and TT provides an
159 inbuilt iterator and helper functions and classes that make life sweet.
161 Conditional directives are IF, UNLESS, ELSIF, ELSE and behave as they would in
167 Hello [% name %], does your mother know you're using her AOL account?
169 Sorry, you're not old enough to enter (and too dumb to lie about your age)
174 [% UNLESS text_mode %] [% INCLUDE biglogo %] [% END %]
178 Looping directives are FOREACH, LAST and BREAK.
180 FOREACH loops through a HASH or ARRAY processing the enclosed block for each
183 Looping through an array
185 [% FOREACH i = items %]
189 Looping through a hash
191 [% FOREACH u IN users %]
192 * [% u.key %] : [% u.value %]
195 Looping through an array of hashes
197 [% FOREACH user IN userlist %]
198 * [% user.id %] [% user.name %]
201 The LAST and BREAK directive can be used to exit the loop.
203 The FOREACH directive is implemented using the Template::Iterator module. A
204 reference to the iterator object for a FOREACH directive is implicitly available
205 in the 'loop' variable. The loop iterator object provides a selection of methods
206 including size(), max(), first(), last(), count(), etc
210 [% FOREACH item IN [ 'foo', 'bar', 'baz' ] -%]
211 [%- "<ul>\n" IF loop.first %]
212 <li>[% loop.count %]/[% loop.size %]: [% item %]
213 [%- "</ul>\n" IF loop.last %]
218 See Template::Iterator for further details on looping and the Iterator.
220 You might notice the minus ('-') operator in the example above, it is used to
221 remove a newline before or after a directive so that you can layout the Template
222 logic as above but the resulting output will look exactly how you require it.
224 You will also frequently see comments and multi-line directives, # at the start
225 of a directive marks it as a comment, i.e. '[%# this is a comment %]'. A
226 multiline directive looks like :
232 You can see that lines are terminated with a semi-colon (';') unless the
233 delimter ('%]') closes the directive.
235 For full details of the Template Toolkit see Template::Manual and
236 Template::Manual::Directives, you can also check the website, mailing list or
237 the Template Toolkit book published by O Reilly.
239 =head1 TEMPLATE PLUGINS, FILTERS AND MACROS
241 The Template Toolkit has a popular and powerful selection of Plugins and
244 TT Plugins provide additional functionality within Templates, from accessing CGI
245 and databases directly, handling paging or simple integration with Class::DBI
246 (for those rare occasions where you don't actually need Maypole). See
247 L<Template::Manual::Plugins>.
249 One plugin that is indispensible when using Maypole and the Template View is
250 C<Template::Plugin::Class> -- This allows you to import and use any class
251 installed within a template. For example :
255 [% USE foo = Class('Foo') %]
260 Would do the equivilent of 'use Foo; Foo->bar;' in perl. See
261 L<Template::Plugin::Class> for details.
263 TT Filters process strings or blocks within a template, allowing you to
264 truncate, format, escape or encode trivially. A useful selection is included
265 with Template Toolkit and they can also be found on CPAN or can be written
266 easily. See L<Template::Manual::Filters>.
268 TT Macros allow you to reuse small blocks of content, directives, etc. The MACRO
269 directive allows you to define a directive or directive block which is then
270 evaluated each time the macro is called. Macros can be passed named parameters
273 Once a MACRO is defined within a template or 'include'd template it can be used
274 as if it were a native TT directive. Maypole provides a selection of powerful
275 and useful macros in the templates/ directory of the package and these are used
276 in the beerdb and default templates. See the MACRO section of the
277 L<Template::Manual::Directives> documentation.
279 =head1 MAYPOLE MACROS AND FILTERS
281 Maypole provides a collection of useful and powerful macros in the templates/factory/macros
282 and other templates. These can be used in any template with [% PROCESS templatename %].
286 This creates an <A HREF="..."> to a command in the Apache::MVC system by
287 catenating the base URL, table, command, and any arguments.
289 =head2 maybe_link_view
291 C<maybe_link_view> takes something returned from the database - either
292 some ordinary data, or an object in a related class expanded by a
293 has-a relationship. If it is an object, it constructs a link to the view
294 command for that object. Otherwise, it just displays the data.
298 This is an include template rather than a macro, and it controls the pager
299 display at the bottom (by default) of the factory list and search views/template.
300 It expects a C<pager> template argument which responds to the L<Data::Page> interface.
302 This macro is in the pager template and used as :
306 Maypole provides a pager for list and search actions, otherwise you can
307 provide a pager in the template using Template::Plugin::Pagination.
309 [% USE pager = Pagination(objects, page.current, page.rows) %]
313 The pager will use a the request action as the action in the url unless the
314 pager_action variable is set, which it will use instead if available.
327 <html><head><title>Maypole error page</title>
328 <style type="text/css">
329 body { background-color:#7d95b5; font-family: sans-serif}
330 p { background-color: #fff; padding: 5px; }
331 pre { background-color: #fff; padding: 5px; border: 1px dotted black }
334 .lhs {background-color: #ffd; }
335 .rhs {background-color: #dff; }
338 <h1> Maypole application error </h1>
340 <p> This application living at <code>[%request.config.uri_base%]</code>,
341 [%request.config.application_name || "which is unnamed" %], has
342 produced an error. The adminstrator should be able to understand
343 this error message and fix the problem.</p>
345 <h2> Some basic facts </h2>
347 <p> The error was found in the [% err_type %] stage of processing
348 the path "[% request.path %]". The error text returned was:
354 <h2> Request details </h2>
357 [% FOR thing = ["model_class", "table", "template", "path",
358 "content_type", "document_encoding", "action", "args", "objects"] %]
359 <tr> <td class="lhs"> [%thing %] </td> <td class="rhs"> [%
360 request.$thing.list.join(" , ") %] </td></tr>
364 <h2> Application configuration </h2>
366 [% FOR thing = config.keys %]
367 <tr> <td class="lhs"> [%thing %] </td> <td class="rhs"> [%
368 config.$thing.list.join(" , ") %] </td></tr>