[% TAGS [** **] -%]
=head1 USING PLUGINS TO EXTEND FUNCTIONALITY
As we've already shown, it is possible to bind Perl data and functions
to template variables when creating dynamic content via a CGI script
or Apache/mod_perl process. The Template Toolkit also supports a
plugin interface which allows you define such additional data and/or
functionality in a separate module and then load and use it as
required with the USE directive.
The main benefit to this approach is that you can load the extension into
any template document, even those that are processed "statically" by
F<tpage> or F<ttree>. You I<don't> need to write a Perl wrapper to
explicitly load the module and make it available via the stash.
Let's demonstrate this principle using the DBI plugin written by Simon
Matthews <sam@knowledgepool.com>. You can create this template in your
'src' directory and process it using F<ttree> to see the results. Of
course, this example relies on the existence of the appropriate SQL
database but you should be able to adapt it to your own resources, or
at least use it as a demonstrative example of what's possible.
[% INCLUDE header
title = 'User Info'
%]
[% USE DBI('dbi:mSQL:mydbname') %]
<table border=0 width="100%">
<tr>
<th>User ID</th>
<th>Name</th>
<th>Email</th>
</tr>
[% FOREACH user = DBI.query('SELECT * FROM user ORDER BY id') %]
<tr>
<td>[% user.id %]</td>
<td>[% user.name %]</td>
<td>[% user.email %]</td>
</tr>
[% END %]
</table>
[% INCLUDE footer %]
A plugin is simply a Perl module in a known location and conforming to
a known standard such that the Template Toolkit can find and load it
automatically. You can create your own plugin by inheriting from the
F<Template::Plugin> module.
Here's an example which defines some data items ('foo' and 'people')
and also an object method ('bar'). We'll call the plugin 'FooBar' for
want of a better name and create it in the 'MyOrg::Template::Plugin::FooBar'
package. We've added a 'MyOrg' to the regular 'Template::Plugin::*' package
to avoid any conflict with existing plugins.
You can create a module stub using the Perl utlity F<h2xs>:
h2xs -A -X -n MyOrg::Template::Plugin::FooBar
This will create a directory structure representing the package name
along with a set of files comprising your new module. You can then
edit FooBar.pm to look something like this:
package MyOrg::Template::Plugin::FooBar;
use Template::Plugin;
use vars qw( $VERSION @ISA );
@ISA = qw( Template::Plugin );
$VERSION = 1.23;
sub new {
my ($class, $context, @params) = @_;
bless {
_CONTEXT => $context,
foo => 25,
people => [ 'tom', 'dick', 'harry' ],
}, $class;
}
sub bar {
my ($self, @params) = @_;
# ...do something...
return $some_value;
}
The plugin constructor new() receives the class name as the first
parameter, as is usual in Perl, followed by a reference to something
called a Template::Context object. You don't need to worry too much
about this at the moment, other than to know that it's the main
processing object for the Template Toolkit. It provides access to the
functionality of the processor and some plugins may need to
communicate with it. We don't at this stage, but we'll save the
reference anyway in the '_CONTEXT' member. The leading underscore is
a convention which indicates that this item is private and the
Template Toolkit won't attempt to access this member. The other
members defined, 'foo' and 'people' are regular data items which will be
made available to templates using this plugin. Following the context
reference are passed any additional parameters specified with the
USE directive, such as the data source parameter, 'dbi:mSQL:mydbname',
that we used in the earlier DBI example.
If you used F<h2xs> to create the module stub then you'll already
have a Makefile.PL and you can incite the familiar incantation to
build and install it. Don't forget to add some tests to test.pl!
perl Makefile.PL
make
make test
make install
If you don't or can't install it to the regular place for your Perl
modules (perhaps because you don't have the required privileges) then
you can set the PERL5LIB environment variable to specify another location.
If you're using F<ttree> then you can add the following line to your
configuration file instead. This has the effect of add '/path/to/modules'
to the @INC array to a similar end.
$HOME/.ttreerc:
perl5lib = /path/to/modules
One further configuration item must be added to inform the toolkit of
the new package name we have adopted for our plugins:
$HOME/.ttreerc:
plugin_base = 'MyOrg::Template::Plugin'
If you're writing Perl code to control the Template modules directly,
then this value can be passed as a configuration parameter when you
create the module.
use Template;
my $template = Template->new({
PLUGIN_BASE => 'MyOrg::Template::Plugin'
});
Now we can create a template which uses this plugin:
[% INCLUDE header
title = 'FooBar Plugin Test'
%]
[% USE FooBar %]
Some values available from this plugin:
[% FooBar.foo %] [% FooBar.bar %]
The users defined in the 'people' list:
[% FOREACH uid = FooBar.people %]
* [% uid %]
[% END %]
[% INCLUDE footer %]
The 'foo', 'bar' and 'people' items of the FooBar plugin are
automatically resolved to the appropriate data items or method calls
on the underlying object.
Using this approach, it is possible to create application
functionality in a single module which can then be loaded and used on
demand in any template. The simple interface between template
directives and plugin objects allows complex, dynamic content to be
built from a few simple template documents without knowing anything
about the underlying implementation.