1Template::Manual::ViewsU(s3e)r Contributed Perl DocumentaTteimopnlate::Manual::Views(3)
2
3
4
6 Template::Manual::Views - Template Toolkit views (experimental)
7
9 A view is effectively a collection of templates and/or variable
10 definitions which can be passed around as a self-contained unit. This
11 then represents a particular interface or presentation style for other
12 objects or items of data.
13
14 You can use views to implement custom "skins" for an application or
15 content set. You can use them to help simplify the presentation of
16 common objects or data types. You can even use then to automate the
17 presentation of complex data structures such as that generated in an
18 "XML::DOM" tree or similar. You let an iterator do the walking, and
19 the view does the talking (or in this case, the presenting). Voila -
20 you have view independent, structure shy traversal using templates.
21
22 In general, views can be used in a number of different ways to achieve
23 several different things. They elegantly solve some problems which
24 were otherwise difficult or complicated, and make easy some things that
25 were previously hard.
26
27 At the moment, they're still very experimental. The directive syntax
28 and underlying API are likely to change quite considerably over the
29 next version or two. Please be very wary about building your multi-
30 million dollar e-commerce solutions based around this feature.
31
33 The "VIEW" directive starts a view definition and includes a name by
34 which the view can be referenced. The view definition continues up to
35 the matching "END" directive.
36
37 [% VIEW myview %]
38 ...
39 [% END %]
40
41 The first role of a view is to act as a collector and provider of
42 templates. The "include()" method can be called on a view to
43 effectively do the same thing as the "INCLUDE" directive. The template
44 name is passed as the first argument, followed by any local variable
45 definitions for the template.
46
47 [% myview.include('header', title='The Title') %]
48
49 # equivalent to
50 [% INCLUDE header title='The Title' %]
51
52 Views accept a number of configuration options which can be used to
53 control different aspects of their behaviour. The '"prefix"' and
54 '"suffix"' options can be specified to add a fixed prefix and/or suffix
55 to the name of each template.
56
57 [% VIEW myview
58 prefix = 'my/'
59 suffix = '.tt2' ;
60 END
61 %]
62
63 Now the call
64
65 [% myview.include('header', title='The Title') %]
66
67 is equivalent to
68
69 [% INCLUDE my/header.tt2 title='The Title' %]
70
71 Views provide an "AUTOLOAD" method which maps method names to the
72 "include()" method. Thus, the following are all equivalent:
73
74 [% myview.include('header', title='Hello World') %]
75 [% myview.include_header(title='Hello World') %]
76 [% myview.header(title='Hello World') %]
77
79 A "VIEW" definition can include "BLOCK" definitions which remain local
80 to the view. A request for a particular template will return a
81 "BLOCK", if defined, in preference to any other template of the same
82 name.
83
84 [% BLOCK foo %]
85 public foo block
86 [% END %]
87
88 [% VIEW plain %]
89 [% BLOCK foo %]
90 plain foo block
91 [% END %]
92 [% END %]
93
94 [% VIEW fancy %]
95 [% BLOCK foo %]
96 fancy foo block
97 [% END %]
98 [% END %]
99
100 [% INCLUDE foo %] # public foo block
101 [% plain.foo %] # plain foo block
102 [% fancy.foo %] # fancy foo block
103
104 In addition to "BLOCK" definitions, a "VIEW" can contain any other
105 template directives. The entire "VIEW" definition block is processed
106 to initialise the view but no output is generated (this may change RSN
107 - and get stored as '"output"' item, subsequently accessible as "[%
108 view.output %]"). However, directives that have side-effects, such as
109 those that update a variable, will have noticeable consequences.
110
112 Views can also be used to save the values of any existing variables, or
113 to create new ones at the point at which the view is defined. Unlike
114 simple template metadata ("META") which can only contain static string
115 values, the view initialisation block can contain any template
116 directives and generate any kind of dynamic output and/or data items.
117
118 [% VIEW my_web_site %]
119 [% view.title = title or 'My Cool Web Site' %]
120 [% view.author = "$abw.name, $abw.email" %]
121 [% view.sidebar = INCLUDE my/sidebar.tt2 %]
122 [% END %]
123
124 Note that additional data items can be specified as arguments to the
125 "VIEW" directive. Anything that doesn't look like a configuration
126 parameter is assumed to be a data item. This can be a little
127 hazardous, of course, because you never know when a new configuration
128 item might get added which interferes with your data.
129
130 [% VIEW my_web_site
131 # config options
132 prefix = 'my/'
133 # misc data
134 title = title or 'My Cool Web Site'
135 author = "$abw.name, $abw.email"
136 sidebar = INCLUDE my/sidebar.tt2
137 %]
138 ...
139 [% END %]
140
141 Outside of the view definition you can access the view variables as,
142 for example:
143
144 [% my_web_site.title %]
145
146 One important feature is the equivalence of simple variables and
147 templates. You can implement the view item '"title"' as a simple
148 variable, a template defined in an external file, possibly with a
149 prefix/suffix automatically appended, or as a local "BLOCK" definition
150 within the "[% VIEW %] ... [% END %]" definition. If you use the
151 syntax above then the view will Do The Right Thing to return the
152 appropriate output.
153
154 At the "END" of the "VIEW" definition the view is "sealed" to prevent
155 you from accidentally updating any variable values. If you attempt to
156 change the value of a variable after the "END" of the "VIEW" definition
157 block then a "view" error will be thrown.
158
159 [% TRY;
160 my_web_site.title = 'New Title';
161 CATCH;
162 error;
163 END
164 %]
165
166 The error above will be reported as:
167
168 view error - cannot update item in sealed view: title
169
170 The same is true if you pass a parameter to a view variable. This is
171 interpreted as an attempt to update the variable and will raise the
172 same warning.
173
174 [% my_web_site.title('New Title') %] # view error!
175
176 You can set the "silent" parameter to have the view ignore these
177 parameters and simply return the variable value.
178
179 [% VIEW my_web_site
180 silent = 1
181 title = title or 'My Cool Web Site'
182 # ... ;
183 END
184 %]
185
186 [% my_web_site.title('Blah Blah') %] # My Cool Web Site
187
188 Alternately, you can specify that a view is unsealed allowing existing
189 variables to be updated and new variables defined.
190
191 [% VIEW my_web_site
192 sealed = 0
193 title = title or 'My Cool Web Site'
194 # ... ;
195 END
196 %]
197
198 [% my_web_site.title('Blah Blah') %] # Blah Blah
199 [% my_web_site.title %] # Blah Blah
200
201 Inheritance, Delegation and Reuse
202 Views can be inherited from previously defined views by use of the
203 "base" parameter. This example shows how a base class view is defined
204 which applies a "view/default/" prefix to all template names.
205
206 [% VIEW my.view.default
207 prefix = 'view/default/';
208 END
209 %]
210
211 Thus the directive:
212
213 [% my.view.default.header(title='Hello World') %]
214
215 is now equivalent to:
216
217 [% INCLUDE view/default/header title='Hello World' %]
218
219 A second view can be defined which specifies the default view as a
220 base.
221
222 [% VIEW my.view.fancy
223 base = my.view.default
224 prefix = 'view/fancy/';
225 END
226 %]
227
228 Now the directive:
229
230 [% my.view.fancy.header(title='Hello World') %]
231
232 will resolve to:
233
234 [% INCLUDE view/fancy/header title='Hello World' %]
235
236 or if that doesn't exist, it will be handled by the base view as:
237
238 [% INCLUDE view/default/header title='Hello World' %]
239
240 When a parent view is specified via the "base" parameter, the
241 delegation of a view to its parent for fetching templates and accessing
242 user defined variables is automatic. You can also implement your own
243 inheritance, delegation or other reuse patterns by explicitly
244 delegating to other views.
245
246 [% BLOCK foo %]
247 public foo block
248 [% END %]
249
250 [% VIEW plain %]
251 [% BLOCK foo %]
252 <plain>[% PROCESS foo %]</plain>
253 [% END %]
254 [% END %]
255
256 [% VIEW fancy %]
257 [% BLOCK foo %]
258 [% plain.foo | replace('plain', 'fancy') %]
259 [% END %]
260 [% END %]
261
262 [% plain.foo %] # <plain>public foo block</plain>
263 [% fancy.foo %] # <fancy>public foo block</fancy>
264
265 Note that the regular "INCLUDE/PROCESS/WRAPPER" directives work
266 entirely independently of views and will always get the original,
267 unaltered template name rather than any local per-view definition.
268
269 Self-Reference
270 A reference to the view object under definition is available with the
271 "VIEW ... END" block by its specified name and also by the special name
272 '"view"' (similar to the "my $self = shift;" in a Perl method or the
273 '"this"' pointer in C++, etc). The view is initially unsealed allowing
274 any data items to be defined and updated within the "VIEW ... END"
275 block. The view is automatically sealed at the end of the definition
276 block, preventing any view data from being subsequently changed.
277
278 (NOTE: sealing should be optional. As well as sealing a view to
279 prevent updates ("SEALED"), it should be possible to set an option in
280 the view to allow external contexts to update existing variables
281 ("UPDATE") or even create totally new view variables ("CREATE")).
282
283 [% VIEW fancy %]
284 [% fancy.title = 'My Fancy Title' %]
285 [% fancy.author = 'Frank Open' %]
286 [% fancy.col = { bg => '#ffffff', bar => '#a0a0ff' } %]
287 [% END %]
288
289 or
290
291 [% VIEW fancy %]
292 [% view.title = 'My Fancy Title' %]
293 [% view.author = 'Frank Open' %]
294 [% view.col = { bg => '#ffffff', bar => '#a0a0ff' } %]
295 [% END %]
296
297 It makes no real difference in this case if you refer to the view by
298 its name, '"fancy"', or by the general name, '"view"'. Outside of the
299 view block, however, you should always use the given name, '"fancy"':
300
301 [% fancy.title %]
302 [% fancy.author %]
303 [% fancy.col.bg %]
304
305 The choice of given name or '"view"' is much more important when it
306 comes to "BLOCK" definitions within a "VIEW". It is generally
307 recommended that you use '"view"' inside a "VIEW" definition because
308 this is guaranteed to be correctly defined at any point in the future
309 when the block gets called. The original name of the view might have
310 long since been changed or reused but the self-reference via '"view"'
311 should always be intact and valid.
312
313 Take the following VIEW as an example:
314
315 [% VIEW foo %]
316 [% view.title = 'Hello World' %]
317 [% BLOCK header %]
318 Title: [% view.title %]
319 [% END %]
320 [% END %]
321
322 Even if we rename the view, or create a new "foo" variable, the header
323 block still correctly accesses the "title" attribute of the view to
324 which it belongs. Whenever a view "BLOCK" is processed, the "view"
325 variable is always updated to contain the correct reference to the view
326 object to which it belongs.
327
328 [% bar = foo %]
329 [% foo = { title => "New Foo" } %] # no problem
330 [% bar.header %] # => Title: Hello World
331
332 Saving References to External Views
333 When it comes to view inheritance, it's always a good idea to take a
334 local copy of a parent or delegate view and store it as an attribute
335 within the view for later use. This ensures that the correct view
336 reference is always available, even if the external name of a view has
337 been changed.
338
339 [% VIEW plain %]
340 ...
341 [% END %]
342
343 [% VIEW fancy %]
344 [% view.plain = plain %]
345 [% BLOCK foo %]
346 [% view.plain.foo | replace('plain', 'fancy') %]
347 [% END %]
348 [% END %]
349
350 [% plain.foo %] # => <plain>public foo block</plain>
351 [% plain = 'blah' %] # no problem
352 [% fancy.foo %] # => <fancy>public foo block</fancy>
353
354 Views as Data Presenters
355 Another key role of a view is to act as a dispatcher to automatically
356 apply the correct template to present a particular object or data item.
357 This is handled via the "print()" method.
358
359 Here's an example:
360
361 [% VIEW foo %]
362
363 [% BLOCK text %]
364 Some text: [% item %]
365 [% END %]
366
367 [% BLOCK hash %]
368 a hash:
369 [% FOREACH key = item.keys.sort -%]
370 [% key %] => [% item.$key %]
371 [% END -%]
372 [% END %]
373
374 [% BLOCK list %]
375 a list: [% item.sort.join(', ') %]
376 [% END %]
377
378 [% END %]
379
380 We can now use the view to print text, hashes or lists. The "print()"
381 method includes the right template depending on the typing of the
382 argument (or arguments) passed.
383
384 [% some_text = 'I read the news today, oh boy.' %]
385 [% a_hash = { house => 'Lords', hall => 'Albert' } %]
386 [% a_list = [ 'sure', 'Nobody', 'really' ] %]
387
388 [% view.print(some_text) %]
389 # Some text: I read the news today, oh boy.
390
391 [% view.print(a_hash) %]
392 # a hash:
393 hall => Albert
394 house => Lords
395 [% view.print(a_list) %]
396 # a list: Nobody, really, sure
397
398 You can also provide templates to print objects of any other class.
399 The class name is mapped to a template name with all non-word character
400 sequences such as '"::"' converted to a single '"_"'.
401
402 [% VIEW foo %]
403 [% BLOCK Foo_Bar %]
404 a Foo::Bar object:
405 thingies: [% view.print(item.thingies) %]
406 doodahs: [% view.print(item.doodahs) %]
407 [% END %]
408 [% END %]
409
410 [% USE fubar = Foo::Bar(...) %]
411
412 [% foo.print(fubar) %]
413
414 Note how we use the view object to display various items within the
415 objects ('"thingies"' and '"doodahs"'). We don't need to worry what
416 kind of data these represent (text, list, hash, etc) because we can let
417 the view worry about it, automatically mapping the data type to the
418 correct template.
419
420 Views may define their own type => template map.
421
422 [% VIEW foo
423 map = { TEXT => 'plain_text',
424 ARRAY => 'show_list',
425 HASH => 'show_hash',
426 My::Module => 'template_name'
427 default => 'any_old_data'
428 }
429 %]
430 [% BLOCK plain_text %]
431 ...
432 [% END %]
433
434 ...
435 [% END %]
436
437 They can also provide a "default" map entry, specified as part of the
438 "map" hash or as a parameter by itself.
439
440 [% VIEW foo
441 map = { ... },
442 default = 'whatever'
443 %]
444 ...
445 [% END %]
446
447 or
448
449 [% VIEW foo %]
450 [% view.map = { ... }
451 view.default = 'whatever'
452 %]
453 ...
454 [% END %]
455
456 The "print()" method provides one more piece of magic. If you pass it a
457 reference to an object which provides a "present()" method, then the
458 method will be called passing the view as an argument. This then gives
459 any object a chance to determine how it should be presented via the
460 view.
461
462 package Foo::Bar;
463 ...
464 sub present {
465 my ($self, $view) = @_;
466 return "a Foo::Bar object:\n"
467 . "thingies: " . $view->print($self->{ _THINGIES }) . "\n"
468 . "doodahs: " . $view->print($self->{ _DOODAHS }) . "\n";
469 }
470
471 The object is free to delve deeply into its innards and mess around
472 with its own private data, before presenting the relevant data via the
473 view. In a more complex example, a "present()" method might walk part
474 of a tree making calls back against the view to present different nodes
475 within the tree. We may not want to expose the internal structure of
476 the tree (because that would break encapsulation and make our
477 presentation code dependant on it) but we want to have some way of
478 walking the tree and presenting items found in a particular manner.
479
480 This is known as Structure Shy Traversal. Our view object doesn't
481 require prior knowledge about the internal structure of any data set to
482 be able to traverse it and present the data contained therein. The
483 data items themselves, via the "present()" method, can implement the
484 internal iterators to guide the view along the right path to
485 presentation happiness.
486
487 The upshot is that you can use views to greatly simplify the display of
488 data structures like "XML::DOM" trees. The documentation for the
489 "Template::Plugin::XML::DOM" module contains an example of this. In
490 essence, it looks something like this:
491
492 XML source:
493
494 <user name="Andy Wardley">
495 <project id="iCan" title="iCan, but theyCan't"/>
496 <project id="p45" title="iDid, but theyDidn't"/>
497 </user>
498
499 TT View:
500
501 [% VIEW fancy %]
502 [% BLOCK user %]
503 User: [% item.name %]
504 [% item.content(myview) %]
505 [% END %]
506
507 [% BLOCK project %]
508 Project: [% project.id %] - [% project.name %]
509 [% END %]
510 [% END %]
511
512 Generate view:
513
514 [% USE dom = XML.DOM %]
515 [% fancy.print(dom.parse(xml_source)) %]
516
517 Output:
518
519 User: Andy Wardley
520 Project: iCan - iCan, but theyCan't
521 Project: p45 - iDid, but theyDidn't
522
523 The same approach can be applied to many other areas. Here's an
524 example from the "File"/"Directory" plugins.
525
526 [% VIEW myview %]
527 [% BLOCK file %]
528 - [% item.name %]
529 [% END %]
530
531 [% BLOCK directory %]
532 * [% item.name %]
533 [% item.content(myview) FILTER indent %]
534 [% END %]
535 [% END %]
536
537 [% USE dir = Directory(dirpath) %]
538 [% myview.print(dir) %]
539
540 And here's the same approach use to convert POD documentation to any
541 other format via template.
542
543 [% # load Pod plugin and parse source file into Pod Object Model
544 USE Pod;
545 pom = Pod.parse_file(my_pod_file);
546
547 # define view to map all Pod elements to "pod/html/xxx" templates
548 VIEW pod2html
549 prefix='pod/html';
550 END;
551
552 # now print document via view (i.e. as HTML)
553 pod2html.print(pom)
554 %]
555
556 Here we simply define a template prefix for the view which causes the
557 view to look for "pod/html/head1", "pod/html/head2", "pod/html/over" as
558 templates to present the different sections of the parsed Pod document.
559
560 There are some examples in the Template Toolkit test suite: t/pod.t and
561 t/view.t which may shed some more light on this. See the distribution
562 sub-directory examples/pod/html for examples of Pod -> HTML templates.
563
564
565
566perl v5.34.0 2022-01-21 Template::Manual::Views(3)