File Coverage

blib/lib/PlackX/Framework/Template.pm
Criterion Covered Total %
statement 42 87 48.2
branch 5 28 17.8
condition 5 24 20.8
subroutine 8 16 50.0
pod 8 14 57.1
total 68 169 40.2


line stmt bran cond sub pod time code
1 2     2   1145 use v5.36;
  2         9  
2             package PlackX::Framework::Template {
3             my %engine_objects = ();
4              
5             sub engine_class {
6             # Use Template Toolkit (Template.pm) by default
7             # If defining your own engine it should implement the role from
8             # PlackX::Framework::Role::TemplateEngine
9 0     0 0 0 'Template';
10             }
11              
12             sub engine_default_options {
13             # Specify options for the template engine if none are defined
14 0     0 0 0 { INCLUDE_PATH => ['template', 'templates'] };
15             }
16              
17 0     0   0 sub import ($class, $options = undef) {
  0         0  
  0         0  
  0         0  
18 0 0       0 die "Import from your app's subclass of PlackX::Framework::Template, not directly"
19             if $class eq __PACKAGE__;
20              
21             # Do nothing if engine is already set up or if :manual tag is passed
22 0 0       0 return if $class->get_engine;
23 0 0 0     0 return if $options and not ref $options and ($options eq ':manual' or $options eq ':no-auto');
      0        
      0        
24              
25             # Setup Template Toolkit if available
26             # Options can be passed in import statement or in config file
27 0 0       0 eval 'require ' . $class->engine_class
28             or die "Cannot load module " . $class->engine_class . ", $@";
29              
30 0 0       0 unless ($options) {
31 0         0 $options = eval {
32 0         0 my $config = $class->app_namespace->config();
33 0 0       0 return $config->{pxf}{template} if $config->{pxf}{template};
34 0 0       0 return $config->{pxf_template} if $config->{pxf_template};
35 0         0 return $class->engine_default_options;
36 0         0 return undef;
37             };
38             }
39              
40             # Create and remember the Template-Toolkit object to be used
41 0         0 my $template_engine_object = $class->engine_class->new($options);
42 0         0 $class->set_engine($template_engine_object);
43             }
44              
45 1     1 1 20689 sub new ($class, $response, $engine = undef) {
  1         3  
  1         2  
  1         3  
  1         1  
46 1 50 33     9 die 'Usage: ->new($response_object)' unless $response and ref $response;
47              
48 1 50       3 $engine = $class->get_engine() unless $engine;
49 1 50 33     10 die 'No valid template engine object' unless $engine and ref $engine;
50              
51 1         6 my $self = bless { engine => $engine, params => {}, response => $response }, $class;
52 1         7 $self->set_defaults;
53 1         4 return $self;
54             }
55              
56 1     1 1 2 sub output ($self, $file = undef, $params = undef, $output_to = undef) {
  1         2  
  1         2  
  1         2  
  1         2  
  1         1  
57 1         7 $self->before_output;
58 1   33     7 $output_to //= $self->{response};
59 1   33     3 $file //= $self->{filename};
60 1 50 33     6 $self->set_params(%$params) if $params and ref $params eq 'HASH';
61             $self->{engine}->process($file, $self->{params}, $output_to)
62             or die 'Template engine process() method failed.' . (
63 1 0       8 $self->{engine}->can('error') ? ' '.$self->{engine}->error : ''
    50          
64             );
65             }
66              
67 0     0 0 0 sub output_as_string ($self, $file, $params) {
  0         0  
  0         0  
  0         0  
  0         0  
68 0         0 my $str = '';
69 0         0 $self->output($file, $params, \$str);
70 0         0 return $str;
71             }
72              
73       1 0   sub set_defaults { } # hook for user extension
74       1 0   sub before_output { } # hook for user extension
75 0 0   0 0 0 sub self_to_class ($self) { ref $self ? ref $self : $self }
  0         0  
  0         0  
  0         0  
76 0     0 1 0 sub get_engine ($self) { $engine_objects{self_to_class $self} }
  0         0  
  0         0  
  0         0  
77 0     0 1 0 sub set_engine ($self, $new) { $engine_objects{self_to_class $self} = $new }
  0         0  
  0         0  
  0         0  
  0         0  
78 3     3 1 10 sub get_param ($self, $name) { $self->{params}{$name} }
  3         5  
  3         5  
  3         3  
  3         13  
79 2     2 1 568 sub set_params ($self, %params) { @{$self->{params}}{keys %params} = values %params; $self }
  2         3  
  2         7  
  2         3  
  2         5  
  2         6  
  2         5  
80 0     0 1 0 sub set_filename ($self, $fname) { $self->{filename} = $fname }
  0         0  
  0         0  
  0         0  
  0         0  
81 1     1 1 2 sub render ($self, @args) { $self->output(@args); $self->{response} }
  1         2  
  1         2  
  1         1  
  1         8  
  1         15  
82             *set = \&set_params;
83             *use = \&set_filename;
84             }
85              
86             1;
87              
88             =pod
89              
90             =head1 NAME
91              
92             PlackX::Framework::Template - Use templates in a PlackX::Framework app.
93              
94              
95             =head1 SYNOPSIS
96              
97             This module allows a convenient way to select template files, add parameters,
98             and process and output the templates. By default, the Template Toolkit module
99             ('Template') is used as the engine, but you can use your own.
100              
101             If using Template Toolkit, you can pass options to Template->new by including
102             a hashref in your use statement:
103              
104             # Your app
105             package MyApp {
106             use PlackX::Framework; # (automatically generates MyApp::Template...)
107             use MyApp::Template { OPTION => 'value', ... };
108             }
109              
110             Your PlackX::Framework app will automatically create a new instance of this
111             class and make it available to your $response object.
112              
113             # In your controller
114             my $template = $response->template;
115             $template->set_filename('foobar.tmpl'); # or ->use('foobar.tmpl');
116             $template->add_params(food => 'pizza', drink => 'beer'); # or ->set(...)
117             return $template->render;
118              
119              
120             =head1 CUSTOM TEMPLATE ENGINE
121              
122             To use your own, subclass this module and override get_engine() method to
123             return an instance of your templating engine object. If your engine does not
124             have a Template Toolkit-like process() method, you will have to override the
125             output() method of this module as well.
126              
127             This example assumes you reuse the same template object for each request:
128              
129             package MyApp::Template {
130             my $templater = Some::Template::Engine->new;
131             sub get_engine { $templater; }
132             sub output ($self, $file) {
133             $self->get_engine->render($file, $self->{'params'}->%*);
134             }
135             }
136              
137             However you can also create a new one for each request:
138              
139             package MyApp::Template {
140             sub get_engine { Some::Template::Engine->new() }
141             sub output ($self, $file) {
142             $self->get_engine->render($file, $self->{'params'}->%*);
143             }
144             }
145              
146             As an example, consider an extremely simple template engine that simply
147             replaces {{variable}} with the value of key 'variable' in the params:
148              
149             package MyTemplateEngine {
150             sub new { bless {}, shift }
151             sub process ($self, $file, $params, $response) {
152             my $content = readfile($file); # readfile() implementation not shown
153             foreach my ($key, $val) (%$params) {
154             $content =~ s`\{\{$key\}\}`$val`g;
155             }
156             $response->print($content);
157             }
158             }
159              
160             Which we can use our new engine in our PlackX::Framework app like this:
161              
162             package MyApp::Template {
163             use parent 'PlackX::Framework::Template';
164             sub get_engine { MyTemplateEngine->new() }
165             }
166              
167             In this case, there is no need to override output() as our engine's process()
168             method is TT-like.
169              
170              
171             =head1 CLASS METHODS
172              
173             =head2 new($response)
174             =head2 new($response, $engine)
175              
176             Create a new instance of this class, optionally specifying the
177             template engine. If not specified, get_engine() will be called.
178              
179             The first argument, a PlackX::Framework response object, is required.
180              
181              
182             =head2 get_engine
183              
184             Get the Template engine object (e.g., the Template Toolkit instance).
185              
186             =head2 set_engine($obj)
187              
188             Set the Template engine object (e.g., the Template Toolkit instance).
189              
190              
191             =head1 OBJECT METHODS
192              
193             =head2 get_param($key)
194              
195             Get the value of a template parameter.
196              
197             =head2 set_params($k => $v, $k2 => $v2...)
198             =head2 set(...)
199              
200             Set the value of template parameters. Aliased as set() for short.
201              
202             =head2 set_filename($filename)
203             =head2 use(...)
204              
205             Set the template filename to be automatically passed to output().
206             Aliased as use() for short.
207              
208             =head2 output
209             =head2 output($filename)
210              
211             Process the template file, to optionally include the filename which will
212             override any previous calls to set_filename() or use().
213              
214             =head2 render(...)
215              
216             Call the output(...) method, passing the same arguments, and return the
217             Plack response object.