1Template::Manual::ViewsU(s3e)r Contributed Perl DocumentaTteimopnlate::Manual::Views(3)
2
3
4

NAME

6       Template::Manual::Views - Template Toolkit views (experimental)
7

Overview

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

Views as Template Collectors/Providers

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

Local BLOCK Definitions

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

Preserving Variable State within Views

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)
Impressum