.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man 5.0102 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Template::Manual::Internals 3" .TH Template::Manual::Internals 3 2024-09-01 "perl v5.40.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Template::Manual::Internals \- Template Toolkit internals .SH Introduction .IX Header "Introduction" This section of the documentation is aimed at developers wishing to know more about how the Template Toolkit works on the inside in order to extend or adapt it to their own needs. .PP If that doesn't sound like you then you probably don't need to read this. There is no test afterwards. .SH "Outside Looking In" .IX Header "Outside Looking In" The Template module is simply a front end module which creates and uses a Template::Service and pipes the output wherever you want it to go (\f(CW\*(C`STDOUT\*(C'\fR by default, or maybe a file, scalar, etc). The \&\f(CW\*(C`Apache::Template\*(C'\fR module (available separately from CPAN) is another front end. That creates a \f(CW\*(C`Template::Service::Apache\*(C'\fR object, calls on it as required and sends the output back to the relevant \&\f(CW\*(C`Apache::Request\*(C'\fR object. .PP These front-end modules are really only there to handle any specifics of the environment in which they're being used. The \f(CW\*(C`Apache::Template\*(C'\fR front end, for example, handles \f(CW\*(C`Apache::Request\*(C'\fR specifics and configuration via the \fIhttpd.conf\fR. The regular Template front-end deals with \f(CW\*(C`STDOUT\*(C'\fR, variable refs, etc. Otherwise it is Template::Service (or subclass) which does all the work. .PP The Template::Service module provides a high-quality template delivery service, with bells, whistles, signed up service level agreement and a 30\-day no quibble money back guarantee. "Have a good time, all the time", that's our motto. .PP Within the lower levels of the Template Toolkit, there are lots of messy details that we generally don't want to have to worry about most of the time. Things like templates not being found, or failing to parse correctly, uncaught exceptions being thrown, missing plugin modules or dependencies, and so on. Template::Service hides that all away and makes everything look simple to the outsider. It provides extra features, like \f(CW\*(C`PRE_PROCESS\*(C'\fR, \f(CW\*(C`PROCESS\*(C'\fR and \&\f(CW\*(C`POST_PROCESS\*(C'\fR, and also provides the error recovery mechanism via \f(CW\*(C`ERROR\*(C'\fR. You ask it to process a template and it takes care of everything for you. The \&\f(CW\*(C`Template::Service::Apache\*(C'\fR module goes a little bit further, adding some extra headers to the Apache::Request, setting a few extra template variables, and so on. .PP For the most part, the job of a service is really just one of scheduling and dispatching. It receives a request in the form of a call to its \&\fBprocess()\fR method and schedules the named template specified as an argument, and possibly several other templates (\f(CW\*(C`PRE_PROCESS\*(C'\fR, etc) to be processed in order. It doesn't actually process the templates itself, but instead makes a \&\fBprocess()\fR call against a Template::Context object. .PP Template::Context is the runtime engine for the Template Toolkit \- the module that hangs everything together in the lower levels of the Template Toolkit and that one that does most of the real work, albeit by crafty delegation to various other friendly helper modules. .PP Given a template name (or perhaps a reference to a scalar or file handle) the context \fBprocess()\fR method must load and compile, or fetch a cached copy of a previously compiled template, corresponding to that name. It does this by calling on a list of one or more Template::Provider objects (the \f(CW\*(C`LOAD_TEMPLATES\*(C'\fR posse) who themselves might get involved with a Template::Parser to help turn source templates into executable Perl code (but more on that later). .PP Thankfully, all of this complexity is hidden away behind a simple \&\fBtemplate()\fR method. You call it passing a template name as an argument, and it returns a compiled template in the form of a Template::Document object, or otherwise raises an exception. .PP A Template::Document is a thin object wrapper around a compiled template subroutine. The object implements a \fBprocess()\fR method which performs a little bit of housekeeping and then calls the template subroutine. The object also defines template metadata (defined in \f(CW\*(C`[% META \&... %]\*(C'\fR directives) and has a \fBblock()\fR method which returns a hash of any additional \f(CW\*(C`[% BLOCK xxxx %]\*(C'\fR definitions found in the template source. .PP So the context fetches a compiled document via its own \&\fBtemplate()\fR method and then gets ready to process it. It first updates the stash (the place where template variables get defined \- more on that shortly) to set any template variable definitions specified as the second argument by reference to hash array. Then, it calls the document \fBprocess()\fR method, passing a reference to itself, the context object, as an argument. In doing this, it provides itself as an object against which template code can make callbacks to access runtime resources and Template Toolkit functionality. .PP What we're trying to say here is this: not only does the Template::Context object receive calls from the \fIoutside\fR, i.e. those originating in user code calling the \fBprocess()\fR method on a Template object, but it also receives calls from the \fIinside\fR, i.e. those originating in template directives of the form \f(CW\*(C`[% PROCESS template %]\*(C'\fR. .PP Before we move on to that, here's a simple structure diagram showing the outer layers of the Template Toolkit heading inwards, with pseudo code annotations showing a typical invocation sequence. .PP .Vb 10 \& ,\-\-\-\-\-\-\-\-. \& | Caller | use Template; \& \`\-\-\-\-\-\-\-\-\*(Aq my $tt = Template\->new( ... ); \& | $tt\->process($template, \e%vars); \& | Outside \& \- \- \- | \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- \- T T \& | package Template; Inside \& V \& +\-\-\-\-\-\-\-\-\-\-+ sub process($template, \e%vars) { \& | Template | $out = $self\->SERVICE\->process($template, $vars); \& +\-\-\-\-\-\-\-\-\-\-+ print $out or send it to $self\->OUTPUT; \& | } \& | \& | package Template::Service; \& | \& | sub process($template, \e%vars) { \& | try { \& +\-\-\-\-\-\-\-\-\-\-+ foreach $p in @self\->PRE_PROCESS \& | Service | $self\->CONTEXT\->process($p, $vars); \& +\-\-\-\-\-\-\-\-\-\-+ \& | $self\->CONTEXT\->process($template, $vars); \& | \& | foreach $p @self\->POST_PROCESS \& | $self\->CONTEXT\->process($p, $vars); \& | } \& | catch { \& | $self\->CONTEXT\->process($self\->ERROR); \& | } \& | } \& | \& V package Template::Context; \& +\-\-\-\-\-\-\-\-\-\-+ \& | Context | sub process($template, \e%vars) { \& +\-\-\-\-\-\-\-\-\-\-+ # fetch compiled template \& | $template = $self\->template($template) \& | # update stash \& | $self\->STASH\->update($vars); \& | # process template \& | $template\->process($self) \& | } \& V \& +\-\-\-\-\-\-\-\-\-\-+ package Template::Document; \& | Document | \& +\-\-\-\-\-\-\-\-\-\-+ sub process($context) { \& $output = &{ $self\->BLOCK }($context); \& } .Ve .SH "Inside Looking Out" .IX Header "Inside Looking Out" To understand more about what's going on in these lower levels, we need to look at what a compiled template looks like. In fact, a compiled template is just a regular Perl sub-routine. Here's a very simple one. .PP .Vb 3 \& sub my_compiled_template { \& return "This is a compiled template.\en"; \& } .Ve .PP You're unlikely to see a compiled template this simple unless you wrote it yourself but it is entirely valid. All a template subroutine is obliged to do is return some output (which may be an empty of course). If it can't for some reason, then it should raise an error via \f(CWdie()\fR. .PP .Vb 3 \& sub my_todo_template { \& die "This template not yet implemented\en"; \& } .Ve .PP If it wants to get fancy, it can raise an error as a Template::Exception object. An exception object is really just a convenient wrapper for the '\f(CW\*(C`type\*(C'\fR' and '\f(CW\*(C`info\*(C'\fR' fields. .PP .Vb 3 \& sub my_solilique_template { \& die (Template::Exception\->new(\*(Aqyorrick\*(Aq, \*(AqFellow of infinite jest\*(Aq)); \& } .Ve .PP Templates generally need to do a lot more than just generate static output or raise errors. They may want to inspect variable values, process another template, load a plugin, run a filter, and so on. Whenever a template subroutine is called, it gets passed a reference to a Template::Context object. It is through this context object that template code can access the features of the Template Toolkit. .PP We described earlier how the Template::Service object calls on Template::Context to handle a \fBprocess()\fR request from the \fIoutside\fR. We can make a similar request on a context to process a template, but from within the code of another template. This is a call from the \fIinside\fR. .PP .Vb 6 \& sub my_process_template { \& my $context = shift; \& my $output = $context\->process(\*(Aqheader\*(Aq, { title => \*(AqHello World\*(Aq }) \& . "\ensome content\en" \& . $context\->process(\*(Aqfooter\*(Aq); \& } .Ve .PP This is then roughly equivalent to a source template something like this: .PP .Vb 5 \& [% PROCESS header \& title = \*(AqHello World\*(Aq \& %] \& some content \& [% PROCESS footer %] .Ve .PP Template variables are stored in, and managed by a Template::Stash object. This is a blessed hash array in which template variables are defined. The object wrapper provides \fBget()\fR and \&\fBset()\fR method which implement all the \&\fImagical.variable.features\fR of the Template Toolkit. .PP Each context object has its own stash, a reference to which can be returned by the appropriately named \fBstash()\fR method. So to print the value of some template variable, or for example, to represent the following source template: .PP .Vb 1 \&