File Coverage

lib/Template/Service.pm
Criterion Covered Total %
statement 106 121 87.6
branch 45 66 68.1
condition 12 16 75.0
subroutine 12 13 92.3
pod 2 2 100.0
total 177 218 81.1


line stmt bran cond sub pod time code
1             #============================================================= -*-Perl-*-
2             #
3             # Template::Service
4             #
5             # DESCRIPTION
6             # Module implementing a template processing service which wraps a
7             # template within PRE_PROCESS and POST_PROCESS templates and offers
8             # ERROR recovery.
9             #
10             # AUTHOR
11             # Andy Wardley
12             #
13             # COPYRIGHT
14             # Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved.
15             #
16             # This module is free software; you can redistribute it and/or
17             # modify it under the same terms as Perl itself.
18             #
19             #============================================================================
20              
21             package Template::Service;
22              
23 86     86   507 use strict;
  86         192  
  86         3464  
24 86     86   476 use warnings;
  86         176  
  86         2958  
25 86     86   494 use base 'Template::Base';
  86         177  
  86         8683  
26 86     86   508 use Template::Config;
  86         218  
  86         2130  
27 86     86   41845 use Template::Exception;
  86         329  
  86         3076  
28 86     86   649 use Template::Constants;
  86         185  
  86         4967  
29 86     86   606 use Scalar::Util 'blessed';
  86         168  
  86         11803  
30              
31 86     86   516 use constant EXCEPTION => 'Template::Exception';
  86         209  
  86         155412  
32              
33             our $VERSION = 2.80;
34             our $DEBUG = 0 unless defined $DEBUG;
35             our $ERROR = '';
36              
37              
38             #========================================================================
39             # ----- PUBLIC METHODS -----
40             #========================================================================
41              
42             #------------------------------------------------------------------------
43             # process($template, \%params)
44             #
45             # Process a template within a service framework. A service may encompass
46             # PRE_PROCESS and POST_PROCESS templates and an ERROR hash which names
47             # templates to be substituted for the main template document in case of
48             # error. Each service invocation begins by resetting the state of the
49             # context object via a call to reset(). The AUTO_RESET option may be set
50             # to 0 (default: 1) to bypass this step.
51             #------------------------------------------------------------------------
52              
53             sub process {
54 1202     1202 1 2580 my ($self, $template, $params) = @_;
55 1202         2595 my $context = $self->{ CONTEXT };
56 1202         1682 my ($name, $output, $procout, $error);
57 1202         4210 $output = '';
58              
59             $self->debug("process($template, ",
60             defined $params ? $params : '',
61 1202 0       3613 ')') if $self->{ DEBUG };
    50          
62              
63             $context->reset()
64 1202 100       14594 if $self->{ AUTO_RESET };
65              
66             # pre-request compiled template from context so that we can alias it
67             # in the stash for pre-processed templates to reference
68 1202         2566 eval { $template = $context->template($template) };
  1202         3792  
69 1202 100       3789 return $self->error($@)
70             if $@;
71              
72             # localise the variable stash with any parameters passed
73             # and set the 'template' variable
74 1201   100     3548 $params ||= { };
75             # TODO: change this to C<||=> so we can use a template parameter
76 1201 50       7169 $params->{ template } = $template
77             unless ref $template eq 'CODE';
78 1201         5637 $context->localise($params);
79              
80             SERVICE: {
81             # PRE_PROCESS
82 1201         1872 eval {
  1201         1787  
83 1201         1728 foreach $name (@{ $self->{ PRE_PROCESS } }) {
  1201         4604  
84 30 50       83 $self->debug("PRE_PROCESS: $name") if $self->{ DEBUG };
85 30         96 $output .= $context->process($name);
86             }
87             };
88 1201 50       4160 last SERVICE if ($error = $@);
89              
90             # PROCESS
91 1201         1748 eval {
92 1201 100       1979 foreach $name (@{ $self->{ PROCESS } || [ $template ] }) {
  1201         8712  
93 1201 50       5771 $self->debug("PROCESS: $name") if $self->{ DEBUG };
94 1201         5565 $procout .= $context->process($name);
95             }
96             };
97 1201 100       4455 if ($error = $@) {
98             last SERVICE
99 15 100       71 unless defined ($procout = $self->_recover(\$error));
100             }
101            
102 1199 100       3035 if (defined $procout) {
103             # WRAPPER
104 1198         1587 eval {
105 1198         1861 foreach $name (reverse @{ $self->{ WRAPPER } }) {
  1198         4018  
106 3 50       11 $self->debug("WRAPPER: $name") if $self->{ DEBUG };
107 3         14 $procout = $context->process($name, { content => $procout });
108             }
109             };
110 1198 50       3175 last SERVICE if ($error = $@);
111 1198         2614 $output .= $procout;
112             }
113            
114             # POST_PROCESS
115 1199         1633 eval {
116 1199         1839 foreach $name (@{ $self->{ POST_PROCESS } }) {
  1199         3717  
117 17 50       44 $self->debug("POST_PROCESS: $name") if $self->{ DEBUG };
118 17         52 $output .= $context->process($name);
119             }
120             };
121 1199 50       3186 last SERVICE if ($error = $@);
122             }
123              
124 1201         4249 $context->delocalise();
125 1201         5259 delete $params->{ template };
126              
127 1201 100       4970 if ($error) {
128             # $error = $error->as_string if ref $error;
129 2         20 return $self->error($error);
130             }
131              
132 1199         40292 return $output;
133             }
134              
135              
136             #------------------------------------------------------------------------
137             # context()
138             #
139             # Returns the internal CONTEXT reference.
140             #------------------------------------------------------------------------
141              
142             sub context {
143 2     2 1 15 return $_[0]->{ CONTEXT };
144             }
145              
146              
147             #========================================================================
148             # -- PRIVATE METHODS --
149             #========================================================================
150              
151             sub _init {
152 145     145   345 my ($self, $config) = @_;
153 145         295 my ($item, $data, $context, $block, $blocks);
154 145         469 my $delim = $config->{ DELIMITER };
155 145 50       621 $delim = ':' unless defined $delim;
156              
157             # coerce PRE_PROCESS, PROCESS and POST_PROCESS to arrays if necessary,
158             # by splitting on non-word characters
159 145         385 foreach $item (qw( PRE_PROCESS PROCESS POST_PROCESS WRAPPER )) {
160 580         880 $data = $config->{ $item };
161 580 100       2725 $self->{ $item } = [ ], next unless (defined $data);
162 23 100 100     146 $data = [ split($delim, $data || '') ]
163             unless ref $data eq 'ARRAY';
164 23         57 $self->{ $item } = $data;
165             }
166             # unset PROCESS option unless explicitly specified in config
167             $self->{ PROCESS } = undef
168 145 100       747 unless defined $config->{ PROCESS };
169            
170 145   66     971 $self->{ ERROR } = $config->{ ERROR } || $config->{ ERRORS };
171             $self->{ AUTO_RESET } = defined $config->{ AUTO_RESET }
172 145 100       876 ? $config->{ AUTO_RESET } : 1;
173 145   100     1277 $self->{ DEBUG } = ( $config->{ DEBUG } || 0 )
174             & Template::Constants::DEBUG_SERVICE;
175            
176             $context = $self->{ CONTEXT } = $config->{ CONTEXT }
177 145   50     1297 || Template::Config->context($config)
178             || return $self->error(Template::Config->error);
179            
180 145         2714 return $self;
181             }
182              
183              
184             #------------------------------------------------------------------------
185             # _recover(\$exception)
186             #
187             # Examines the internal ERROR hash array to find a handler suitable
188             # for the exception object passed by reference. Selecting the handler
189             # is done by delegation to the exception's select_handler() method,
190             # passing the set of handler keys as arguments. A 'default' handler
191             # may also be provided. The handler value represents the name of a
192             # template which should be processed.
193             #------------------------------------------------------------------------
194              
195             sub _recover {
196 15     15   29 my ($self, $error) = @_;
197 15         41 my $context = $self->{ CONTEXT };
198 15         26 my ($hkey, $handler, $output);
199              
200             # there shouldn't ever be a non-exception object received at this
201             # point... unless a module like CGI::Carp messes around with the
202             # DIE handler.
203             return undef
204 15 50 33     139 unless blessed($$error) && $$error->isa(EXCEPTION);
205              
206             # a 'stop' exception is thrown by [% STOP %] - we return the output
207             # buffer stored in the exception object
208 15 100       48 return $$error->text()
209             if $$error->type() eq 'stop';
210              
211             my $handlers = $self->{ ERROR }
212 6   100     29 || return undef; ## RETURN
213              
214 4 100       13 if (ref $handlers eq 'HASH') {
215 3 100       15 if ($hkey = $$error->select_handler(keys %$handlers)) {
    50          
216 1         3 $handler = $handlers->{ $hkey };
217 1 50       3 $self->debug("using error handler for $hkey") if $self->{ DEBUG };
218             }
219             elsif ($handler = $handlers->{ default }) {
220             # use default handler
221 2 50       7 $self->debug("using default error handler") if $self->{ DEBUG };
222             }
223             else {
224 0         0 return undef; ## RETURN
225             }
226             }
227             else {
228 1         1 $handler = $handlers;
229 1 50       5 $self->debug("using default error handler") if $self->{ DEBUG };
230             }
231            
232 4         7 eval { $handler = $context->template($handler) };
  4         10  
233 4 50       15 if ($@) {
234 0         0 $$error = $@;
235 0         0 return undef; ## RETURN
236             };
237            
238 4         13 $context->stash->set('error', $$error);
239 4         6 eval {
240 4         13 $output .= $context->process($handler);
241             };
242 4 50       12 if ($@) {
243 0         0 $$error = $@;
244 0         0 return undef; ## RETURN
245             }
246              
247 4         15 return $output;
248             }
249              
250              
251              
252             #------------------------------------------------------------------------
253             # _dump()
254             #
255             # Debug method which return a string representing the internal object
256             # state.
257             #------------------------------------------------------------------------
258              
259             sub _dump {
260 0     0     my $self = shift;
261 0           my $context = $self->{ CONTEXT }->_dump();
262 0           $context =~ s/\n/\n /gm;
263              
264 0           my $error = $self->{ ERROR };
265 0           $error = join('',
266             "{\n",
267 0 0         (map { " $_ => $error->{ $_ }\n" }
268             keys %$error),
269             "}\n")
270             if ref $error;
271            
272 0           local $" = ', ';
273 0           return <
274             $self
275 0           PRE_PROCESS => [ @{ $self->{ PRE_PROCESS } } ]
276 0           POST_PROCESS => [ @{ $self->{ POST_PROCESS } } ]
277             ERROR => $error
278             CONTEXT => $context
279             EOF
280             }
281              
282              
283             1;
284              
285             __END__