NAME
Template::Plugin::TwoStage - two stage processing of template blocks with first stage caching
VERSION
Version 0.02
SYNOPSIS
This is a plugin for the Template Toolkit that facilitates a two stage processing of BLOCKs with first stage caching. Processing results of the first (precompilation) stage are cached away for subsequent repeated processing in the second (runtime) stage. Precompilation and runtime tags are seperated by using different tag styles.
Basic usage in the a TT2-template:
[% USE TwoStage = TwoStage( namespace => application.name ); # make an application specific namespace (optional)
TwoStage.process( 'template' => 'cached_page', keys => { 'bar' => bar }, ttl => 60 * 60 );
BLOCK cached_page;
# use precompile tags or runtime tags here
%]
[* foo # runtime stage evaluation *]
[% IF bar; # precompilation stage evaluation
# ...
ELSE;
# ...
END;
%]
[% END %]
More features
subclassable
Make your own application specific subclass of this module and avoid repeated application wide configuration of the plugin on each use in different templates.
parameterized precompilation of a single block
Pass keys as additional identifiers of a BLOCK, based upon which the BLOCK produces a different precompiled output/version of the BLOCK.
expiration
Give the precompiled BLOCKs a 'time to live' before they expire.
namespaces
Distinguish different e.g. applications in one process by the use of namespaces.
development mode
Edit your templates with caching turned off. The development mode also gives you convenient access to the precompiled versions produced for validation of your separation of precompilation and runtime directives.
flexible customization
Set your basic configuration in a subclass, and override any configuration option on plugin instantiation or even on specific plugin method calls in the templates.
MOTIVATIONS FOR USE
You might benefit from this module if ...
... you have static external content e.g. from databases or .po-files that you want to pull into your templates only once while still being able to insert dynamic data into the same template
... you are following the DRY principle by having a central BLOCK library that you use to style your GUI HTML components
... you do not want to use ttree because you prefer "lazy" precompilation (only on demand), and you want to see your changes to the template without running an external program first
SUBCLASSING
This plugin is subclassable. Though it is possible to use this module without subclassing it, subclassing has many benefits and is the recommended way of use. Subclassing allows you to customize your plugin behaviour at a single place, and extend the template signature by some default keys. Still it lets you override the configuration on plugin instantiation or even on the call of the include() or precompile()-methods at your will with only local scope.
Sample code
package Your::Application::Template::Plugin::TwoStage;
use base qw( Template::Plugin::TwoStage Your::Application );
__PACKAGE__->caching_dir( __PACKAGE__->Application->config->tmp_dir() );
__PACKAGE__->dev_mode( 1 );
__PACKAGE__->ttl( 60 * 60 ); # 1 h
__PACKAGE__->dir_keys( 1 );
__PACKAGE__->runtime_tag_style( 'html' );
sub extend_keys {
my ( $self, $keys ) = @_;
my $context = $self->{CONTEXT};
my $stash = $context->stash();
# hook method for adding standard keys - return the keys => value -hash by reference!
{ domain => __PACKAGE__->Application->request->uri->authority,
language => __PACKAGE__->Application->request->language,
logged_in => __PACKAGE__->Application->request->session->logged_in,
gui_style => __PACKAGE__->Application->request->session->preferences->gui_style
};
}
Don't forget to add your sublcass to the plugin base of your TT2-configuration:
PLUGIN_BASE => [ 'Your::Application::Template::Plugin' ]
or declare it via the PLUGINS TT2-configuration option
PLUGINS => { TwoStage => 'Your::Application::Template::Plugin::TwoStage', ... }
Configuration Options
Configuration options may be set with different scopes. When subclassing this module a subclass wide configuration can be achieved by using the inheritable class data accessors provided via Class::Data::Inheritable. See also the sample code above.
The following configuration options may be set
... as class data for this module or a derived class:
caching_dir
dev_mode
ttl
namespace
dir_keys
runtime_tag_style
__PACKAGE__->caching_dir( $some_path );
... on plugin instantiation for the scope of the plugin object
... and on the call of the include() or precompile()-methods valid for the present call:
dev_mode
ttl
namespace
dir_keys
runtime_tag_style
[% TwoStage = USE TwoStage( ttl => 3600 );
...
TwoStage.process( template => 'some_template', ttl => 1800 );
%]
caching_dir
The directory 'TT_P_TwoStage' in your platform specific tmp-directory determined with the help of File::Spec->tmpdir() is the default setting here. Pass a path in order to change it to some other directory - it will also be extended by a subdirectory 'TT_P_TwoStage'. In contrast to all the other configuration options this option can only be set as class data.
dev_mode
Set this configuration option to a TRUE value in order to disable the use of cached files and see your changes to cached BLOCKs immediately while still having access to the precompiled versions on disc for their validation.
See also the configuration option 'dir_keys' as another interesting feature for development.
ttl
Specify the "time to live" for the precompiled versions of the BLOCKs in seconds - 0 is 'no expiration' and the default setting.
dir_keys
Usually the keys connected to a precompiled version are included among other things into the file name of a BLOCK in order to identify a precompiled cached BLOCK on disc. This is accomplished by using the SHA1 hash function.
To make the retrieval of a certain caching file easier for humans, the configuration parameter 'dir_keys' lets you include the keys into the file path of the precompiled cached BLOCK. This behaviour might be handy in cases where one wants to inspect the precompiled versions produced.
Set 'dir_keys' either to an array reference holding a selection of keys or a scalar holding a TRUE value for all keys. This feature is available in development mode only! See also configuration option 'dev_mode'.
See also the section PLUGIN OBJECT METHODS for more on the 'keys' parameter.
namespace
By default we incorporate the BLOCK name together with the TT2 meta variables 'component.callers' and 'component.name' - which in turn is the call stack of BLOCKs and templates to the BLOCK from the outermost file the BLOCK was included in - into the caching signature in order to achieve the used BLOCK name is having only file scope.
Furthermore we avoid interference of template signatures of different subclasses of this module by file system paths.
If you choose not to subclass this module for an application you can ensure the segmentation of applications by setting the 'namespace' configuration option accordingly. This approach has the drawback that you need to set this configuration option in each template on plugin instantiation:
USE TwoStage( namespace => application_name );
runtime_tag_style
Set this option to one of the predefined tag styles TT is offering like 'php', 'mason', 'html', ..., and that are accepted by TT as a value to its 'TAG_STYLE' configuration option or 'TAGS' directive. Default is: star ([* *]).
Excursus: precompilation tag style
The precompilation tag style is always the tag style set in the TT configuration or 'default'. A tag style defined local to the file the plugin is being called in ( by means of the 'TAGS'-directive at the beginning of the file) will be handled correctly - this file scoped tag style will also be used in the BLOCK to be precompiled as precompilation tag style.
Changing the tag style only for a certain BLOCK that is to be precompiled is not possible, as the 'TAGS' directive can be set only on per template file basis. A centralized configuration of the precompilation tag style to be used is not available to date.
Object hook methods
extend_keys
With this callback method it is possible to merge some default keys into the template signature. The values of the keys introduced this way will be dominated by the values of identical keys passed to process() or include(). Return a hash reference mapping standard signature keys to its values! Have a look at the sample code above.
Exports
None.
PLUGIN OBJECT METHODS
Once the plugin object has been pulled into the template by means of the 'USE' directive, calling the plugin object methods include() or process() against it will insert the BLOCK content with all the precompilation and caching magic delivered by this plugin into the template.
Named parameters of process/include:
template
Specify the name of the BLOCK to be processed/included into the template here. Its name does not have to be template spanning unique. The plugin takes care that the name is local to the template it is defined in.
keys (optional)
Use this parameter in situations where you want to evaluate a certain stash variable in the precompilation stage, and that variable can take on only a limited set of discrete values but has considerable influence on the precompiled versions. Examples for such variables might be: template language, user preferences, user privileges, ...
Each combination of the values of the variables passed as 'keys' parameter will produce a distinct precompiled version of the BLOCK in question. Take care not to choose to many keys with to many values in order to produce only a reasonable number of precompiled versions.
If you find some keys are supposed to be added to each and every call to process() or include() consider subclassing this plugin and using the extend_keys() hook method (see also above).
all of the available configuration options (optional)
For more on those options see section "Configuration Options" in this documentation.
include() is exposing an identical behaviour as process() with the exception that it does stash localisation in the runtime stage.
CACHING
Having precompiled a BLOCK the TwoStage plugin assigns a unique identity (signature) to it, and writes it to the disk using a SHA1 fingerprint of the signature as the filename. Now all processes sharing the same caching directory and namespace will always retrieve this precompiled version of the BLOCK.
The precompiled version is retrieved using the standard loading mechanism of the Template Toolkit as any other template. Please note that the STAT_TTL configuration of TT however will not work for those cached precompiled versions as you make modifications to the "source" BLOCKS of those cached templates.
In order to set back caching remove the cached templates from your caching directory. Maybe a script to assist you in this task will be shipped together with a future version of this plugin.
purge
Using purge() you remove all files from the caching directory of the class - use this to set back caching from within templates. This method is used mainly in the self tests of this module. Maybe there are even more useful applications for it - so it became a public class method.
[% TwoStage = USE TwoStage;
TwoStage.purge;
%]
HEURISTICS
In order to avoid common pitfalls when using this module you find some tips and reminders below:
Templates used as "intras" with runtime directives ought to be controlled by the TwoStage plugin themselves! This ensures that such templates can be included into another template either at runtime or at precompilation stage.
Upstream keys from included templates ( "intras" ) must be incorporated into the 'keys' option of the including template! Explanation: They have to be known ex ante meaning prior to a test for a cached version of a template and can therefor not easily be collected from upstream templates automatically!
Situation: A template A includes another template B while both are using the TwoStage plugin. In addition you pass parameters on invocation of INCLUDE, PROCESS to template B. Add those parameters to the 'keys' option when calling the TwoStage plugin in template B and use them at precompilation stage. This way you can include template B at runtime and at precompilation at your will.
Ensure there are no BLOCK definitions inside the BLOCK to be TwoStage processed! This is nothing specific to the TwoStage plugin really, but is a common mistake. Simply put those BLOCKs outside the BLOCK to be TwoStage processed. They will be visible to it anyway.
When altering option 'dev_mode' on plugin object instantiation or on calls to the methods process()/include() one has to be cautious in situations where calls to the TwoStage plugins methods process()/include() are nested: Remember to alter the option in the outermost call!
CAVEATS
INCLUDE_PATH
Setting the INCLUDE_PATH option in the TT configuration is a must as of this version. But even setting it to a reference to an empty array is sufficient here.
CACHE_SIZE
As one can produce a lot of versions of a single BLOCK using the 'keys' feature of process()/include(), it might be advisable in some situations to set the CACHE_SIZE TT configuration option to a positive value in order to curb memory consumption when having a TT singleton object around in a persistent environment like e.g. mod_perl.
AUTHOR
Alexander Kühne, <alexk at cpan.org>
BUGS
Please report any bugs or feature requests to bug-template-plugin-twostage at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Template-Plugin-TwoStage. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Template::Plugin::TwoStage
You can also look for information at:
RT: CPAN's request tracker
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Template-Plugin-TwoStage
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
ACKNOWLEDGEMENTS
This module was inspired to some extent by Perrin Harkins http://search.cpan.org/dist/Template-Plugin-Cache and not least by my CO2 footprint.
COPYRIGHT & LICENSE
Copyright 2008 Alexander Kühne, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
SEE ALSO
Template::Plugin, http://search.cpan.org/dist/Template-Plugin-Cache
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 722:
Non-ASCII character seen before =encoding in 'Kühne,'. Assuming CP1252