use Template3; use Template::TT3::Services; # Create a services factory object my $services = Template::TT3::Services->new; # Create some service components my $input = $services->service('input'); my $header = $services->service( header => 'site/header.tt3' ); my $footer = $services->service( footer => 'site/footer.tt3' ); my $wrapper = $services->service( wrapper => 'site/wrapper.tt3' ); my $output = $services->service('output'); # Now construct a service pipeline starting with an input... my $pipeline = $input->connect; # ...followed by each of the service components... $pipeline = $header->connect($pipeline); $pipeline = $footer->connect($pipeline); $pipeline = $wrapper->connect($pipeline); # ...and ending with an output $pipeline = $output->connect($pipeline); # or do it the all-in-one way my $pipeline = $services->connect( input => '', header => 'site/header.tt3', footer => 'site/footer.tt3', wrapper => 'site/wrapper.tt3', output => '' ); # We need a runtime context with some (random) data parameters my $context = Template3->context->with( x => 10, y => 20, ); # Then we can run the service and it all Just Works[tm] print $pipeline->( context => $context, input => 'example.tt3', ); # Change the environment to affect components in the pipeline $pipeline->( context => $context, input => 'another.tt3', header => 'my/header.tt3', footer => 'your/footer.tt3', wrapper => 'another/wrapper.tt3', output => 'another.html', };
This module is a subclass of Template::TT3::Factory for locating, loading and instantiating template service modules.
Service modules are small pipeline components that perform simple tasks to modify or augment the output generated by processing a template. The most common application of services is for automatically adding headers, footers and page wrappers. However, they can also be used to inject various other processing actions into a service pipeline. For example, a service could be used to catch and handle processing errors, or to time how long a template takes to process.
Furthermore, services may modify the runtime environment that affects how other services perform. So you can write a service that automagically changes which header, footer, wrapper or layout template is used by the relevant services that follow it.
All of this is usually handled for you by the Template::TT3::Engine::TT3 module that sits behind the Template3 module. Consider the following example:
my $tt3 = Template3->new( header => 'site/header.tt3', footer => 'site/footer.tt3', );
Behind the scenes, a service pipeline is constructed that processes whatever
template you specify and then automatically adds the site/header.tt3
and
site/footer.tt3
header and footer templates respectively.
If this kind of thing is all you ever need to do then you can stop reading now. If, however, your needs are more demanding and you find yourself wanting to add several different headers, change the layout templates dynamically, or perhaps add some debugging, timing, or logging code to your template processing service then read on. This documentation explains how service components are created and connected into service pipelines, and demonstrates how you can create your own custom template processing services.
The Template::TT3::Services
module provides the
service()
method for
loading and instantiating service object. It looks for service modules in the
following places:
Template::TT3::Service Template::Service TemplateX::TT3::Service TemplateX::Service
For example, requesting a header
service returns a
Template::TT3::Service::Header
object.
my $service = Template::TT3::Services->service( header => 'site/header.tt3' );
You can call it as a class method, as shown in the example above, or as an object method.
my $services = Template::TT3::Services->new; my $service = $services->service( header => 'site/header.tt3' );
Services can be connected together in a pipeline. In the usual case a pipeline
will start with an
input
service. This uses
the input
parameter defined in the environment to find, fetch and fill the
main page template. So we create an input service:
my $input = $services->service('input');
Then we call the connect() method to turn a service into a pipeline function.
my $pipeline = $input->connect;
We can now call the pipeline function. We must pass it an environment as a set
of named parameters. The should include a
context
object in which our variable data is defined, and an input
parameter
indicating the template that we want to be processed.
use Template::TT3::Context; my $context = Template::TT3::Context->new( data => { name => 'World', } ); print $pipeline->( input => 'example.tt3', context => $context, );
The pipeline function invokes the input service which fetches the input
template (example.tt3
) from the context and processes it. The output
generated by the template is returned.
If we want to automatically add a header to each template then we can create a header service and connect it to our existing pipeline. This returns a new pipeline function which includes both the input and header components.
$header = $services->service( header => 'site/header.tt3' ); $pipeline = $header->connect($pipeline);
Now when we run the pipeline we get the main page content plus the header
print $pipeline->( input => 'example.tt3', context => $context, );
Want a footer too? No problem. We can squish the service creation and connection into a single expression as shown below. It looks slightly different but it's functionally equivalent to the previous example.
$pipeline = $services ->service( footer => 'site/footer.tt3' ) ->connect( $pipeline );
The Template::TT3::Services
module also defines the
connect()
method
which combines both actions into one method call. It creates a service
component and connects it to the current pipeline.
$pipeline = $services->connect( $pipeline, footer => 'site/footer.tt3', );
In fact, you can use
connect()
to create a number of services and have them
all connected together in order. The only condition is that each service
component is specified as either a pair of ($name
, $config
) or a
reference of some kind (e.g. an existing service object). That requires us to
define a dummy configuration parameter for the input
service which doesn't
usually expect any configuration.
$pipeline = $services->connect( input => '', header => 'site/header.tt3', footer => 'site/footer.tt3', );
The module inherits all of the generic configuration options provided by the Template::TT3::Factory and Badger::Factory base classes. The following options are specific to this service factory.
This option allows you to add elements to the search path used to locate service modules. A single item can be specified as a string. Multiple items can be specified by reference to a list.
my $services = Template::TT3::Services->new( service_path => ['My::Service', 'Your::Service'], );
This option allows you to specify additional service components by name. This is typically used to define services that exists outside of the usual service_path path, or perhaps have unusual capitalisations that the default name translation process will fail to resolve.
my $services = Template::TT3::Services->new( services => { load_yaml => 'My::Service::LoadYAML', # vs LoadYaml } );
This module inherits all methods from the Template::TT3::Factory , Template::TT3::Base , Badger::Factory and Badger::Base base classes. The following methods are also defined or are automatically provided by the Badger::Factory base class.
Locates, loads and instantiates a service module. This is created as an alias to the item() method in Badger::Factory .
my $service = $services->service( header => 'site/header.tt3' );
The first argument should be a name identifying the service component.
This will automatically be
camel cased
and
appended to each of the package names in the
service_path
until a
matching module can be found and loaded. For example a type of header
is mapped to the
Template:TT3::Service::Header
module.
Method for inspecting or modifying the services that the factory module manages. This is created as an alias to the items() method in Badger::Factory .
This method replaces the default
type_args()
method inherited from the
Badger::Factory
base class. The first argument is
expected to be a service type that the factory can map to a module name,
e.g. header
which is mapped to
Template::TT3::Service::Header
. If a
single non-hash reference argument follows then it is assume to be a template
name or some other reference from which a template can be constructed.
The end result is that you can write this:
$service = $services->service( header => 'example.tt3' );
as a convenient shorthand for:
$service = $services->service( header => { template => 'example.tt3' }, );
This module defines the following package variables. These are declarations that are used by the Badger::Factory base class.
This is the name of the item that the factory module returns, and implicitly
the name of the method by which . In this case it is defined as service
.
Andy Wardley http://wardley.org/
Copyright (C) 1996-2009 Andy Wardley. All Rights Reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
This module inherits methods from the Template::TT3::Factory , Template::TT3::Base , Badger::Factory , and Badger::Base base classes.
It loads modules and instantiates object that are subclasses of Template::TT3::Service . See Template::TT3::Service::Header , Template::TT3::Service::Footer and the various other examples of specific service modules.