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 85     85   503 use strict;
  85         173  
  85         15965  
24 85     85   488 use warnings;
  85         179  
  85         2951  
25 85     85   474 use base 'Template::Base';
  85         168  
  85         14822  
26 85     85   495 use Template::Config;
  85         216  
  85         2117  
27 85     85   39102 use Template::Exception;
  85         253  
  85         2790  
28 85     85   1000 use Template::Constants;
  85         209  
  85         5023  
29 85     85   529 use Scalar::Util 'blessed';
  85         183  
  85         11560  
30              
31 85     85   524 use constant EXCEPTION => 'Template::Exception';
  85         184  
  85         155336  
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 1210     1210 1 2375 my ($self, $template, $params) = @_;
55 1210         2663 my $context = $self->{ CONTEXT };
56 1210         1758 my ($name, $output, $procout, $error);
57 1210         2125 $output = '';
58              
59             $self->debug("process($template, ",
60             defined $params ? $params : '',
61 1210 0       3939 ')') if $self->{ DEBUG };
    50          
62              
63             $context->reset()
64 1210 100       7460 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 1210         2441 eval { $template = $context->template($template) };
  1210         4091  
69 1210 100       7587 return $self->error($@)
70             if $@;
71              
72             # localise the variable stash with any parameters passed
73             # and set the 'template' variable
74 1209   100     3765 $params ||= { };
75             # TODO: change this to C<||=> so we can use a template parameter
76 1209 50       5965 $params->{ template } = $template
77             unless ref $template eq 'CODE';
78 1209         5990 $context->localise($params);
79              
80             SERVICE: {
81             # PRE_PROCESS
82 1209         2757 eval {
  1209         1880  
83 1209         1926 foreach $name (@{ $self->{ PRE_PROCESS } }) {
  1209         4714  
84 30 50       96 $self->debug("PRE_PROCESS: $name") if $self->{ DEBUG };
85 30         110 $output .= $context->process($name);
86             }
87             };
88 1209 50       3915 last SERVICE if ($error = $@);
89              
90             # PROCESS
91 1209         1708 eval {
92 1209 100       1803 foreach $name (@{ $self->{ PROCESS } || [ $template ] }) {
  1209         7796  
93 1209 50       3619 $self->debug("PROCESS: $name") if $self->{ DEBUG };
94 1209         9585 $procout .= $context->process($name);
95             }
96             };
97 1209 100       4124 if ($error = $@) {
98             last SERVICE
99 15 100       76 unless defined ($procout = $self->_recover(\$error));
100             }
101            
102 1207 100       3241 if (defined $procout) {
103             # WRAPPER
104 1206         3357 eval {
105 1206         1892 foreach $name (reverse @{ $self->{ WRAPPER } }) {
  1206         3960  
106 3 50       17 $self->debug("WRAPPER: $name") if $self->{ DEBUG };
107 3         18 $procout = $context->process($name, { content => $procout });
108             }
109             };
110 1206 50       3234 last SERVICE if ($error = $@);
111 1206         2620 $output .= $procout;
112             }
113            
114             # POST_PROCESS
115 1207         1930 eval {
116 1207         1835 foreach $name (@{ $self->{ POST_PROCESS } }) {
  1207         3340  
117 17 50       58 $self->debug("POST_PROCESS: $name") if $self->{ DEBUG };
118 17         52 $output .= $context->process($name);
119             }
120             };
121 1207 50       3301 last SERVICE if ($error = $@);
122             }
123              
124 1209         4464 $context->delocalise();
125 1209         6011 delete $params->{ template };
126              
127 1209 100       3475 if ($error) {
128             # $error = $error->as_string if ref $error;
129 2         389 return $self->error($error);
130             }
131              
132 1207         38128 return $output;
133             }
134              
135              
136             #------------------------------------------------------------------------
137             # context()
138             #
139             # Returns the internal CONTEXT reference.
140             #------------------------------------------------------------------------
141              
142             sub context {
143 2     2 1 8 return $_[0]->{ CONTEXT };
144             }
145              
146              
147             #========================================================================
148             # -- PRIVATE METHODS --
149             #========================================================================
150              
151             sub _init {
152 145     145   386 my ($self, $config) = @_;
153 145         283 my ($item, $data, $context, $block, $blocks);
154 145         481 my $delim = $config->{ DELIMITER };
155 145 50       688 $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         459 foreach $item (qw( PRE_PROCESS PROCESS POST_PROCESS WRAPPER )) {
160 580         1060 $data = $config->{ $item };
161 580 100       2638 $self->{ $item } = [ ], next unless (defined $data);
162 23 100 100     181 $data = [ split($delim, $data || '') ]
163             unless ref $data eq 'ARRAY';
164 23         68 $self->{ $item } = $data;
165             }
166             # unset PROCESS option unless explicitly specified in config
167             $self->{ PROCESS } = undef
168 145 100       823 unless defined $config->{ PROCESS };
169            
170 145   66     1000 $self->{ ERROR } = $config->{ ERROR } || $config->{ ERRORS };
171             $self->{ AUTO_RESET } = defined $config->{ AUTO_RESET }
172 145 100       917 ? $config->{ AUTO_RESET } : 1;
173 145   100     987 $self->{ DEBUG } = ( $config->{ DEBUG } || 0 )
174             & Template::Constants::DEBUG_SERVICE;
175            
176             $context = $self->{ CONTEXT } = $config->{ CONTEXT }
177 145   50     1316 || Template::Config->context($config)
178             || return $self->error(Template::Config->error);
179            
180 145         2941 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   37 my ($self, $error) = @_;
197 15         32 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     158 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       60 return $$error->text()
209             if $$error->type() eq 'stop';
210              
211             my $handlers = $self->{ ERROR }
212 6   100     42 || return undef; ## RETURN
213              
214 4 100       263 if (ref $handlers eq 'HASH') {
215 3 100       18 if ($hkey = $$error->select_handler(keys %$handlers)) {
    50          
216 1         3 $handler = $handlers->{ $hkey };
217 1 50       5 $self->debug("using error handler for $hkey") if $self->{ DEBUG };
218             }
219             elsif ($handler = $handlers->{ default }) {
220             # use default handler
221 2 50       9 $self->debug("using default error handler") if $self->{ DEBUG };
222             }
223             else {
224 0         0 return undef; ## RETURN
225             }
226             }
227             else {
228 1         3 $handler = $handlers;
229 1 50       6 $self->debug("using default error handler") if $self->{ DEBUG };
230             }
231            
232 4         10 eval { $handler = $context->template($handler) };
  4         16  
233 4 50       18 if ($@) {
234 0         0 $$error = $@;
235 0         0 return undef; ## RETURN
236             };
237            
238 4         18 $context->stash->set('error', $$error);
239 4         7 eval {
240 4         17 $output .= $context->process($handler);
241             };
242 4 50       15 if ($@) {
243 0         0 $$error = $@;
244 0         0 return undef; ## RETURN
245             }
246              
247 4         21 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__