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 92     92   321 use strict;
  92         106  
  92         2229  
24 92     92   284 use warnings;
  92         88  
  92         2073  
25 92     92   280 use base 'Template::Base';
  92         88  
  92         5646  
26 92     92   355 use Template::Config;
  92         86  
  92         1481  
27 92     92   23104 use Template::Exception;
  92         141  
  92         2222  
28 92     92   441 use Template::Constants;
  92         97  
  92         3233  
29 92     92   319 use Scalar::Util 'blessed';
  92         106  
  92         5857  
30              
31 92     92   330 use constant EXCEPTION => 'Template::Exception';
  92         95  
  92         83049  
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 1227     1227 1 1247 my ($self, $template, $params) = @_;
55 1227         1229 my $context = $self->{ CONTEXT };
56 1227         993 my ($name, $output, $procout, $error);
57 1227         1170 $output = '';
58              
59             $self->debug("process($template, ",
60             defined $params ? $params : '',
61 1227 0       1928 ')') if $self->{ DEBUG };
    50          
62              
63             $context->reset()
64 1227 100       3667 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 1227         1590 eval { $template = $context->template($template) };
  1227         2111  
69 1227 100       1951 return $self->error($@)
70             if $@;
71              
72             # localise the variable stash with any parameters passed
73             # and set the 'template' variable
74 1226   100     2145 $params ||= { };
75             # TODO: change this to C<||=> so we can use a template parameter
76 1226 50       3186 $params->{ template } = $template
77             unless ref $template eq 'CODE';
78 1226         2882 $context->localise($params);
79              
80             SERVICE: {
81             # PRE_PROCESS
82 1226         1082 eval {
  1226         1117  
83 1226         937 foreach $name (@{ $self->{ PRE_PROCESS } }) {
  1226         2538  
84 30 50       48 $self->debug("PRE_PROCESS: $name") if $self->{ DEBUG };
85 30         46 $output .= $context->process($name);
86             }
87             };
88 1226 50       2256 last SERVICE if ($error = $@);
89              
90             # PROCESS
91 1226         953 eval {
92 1226 100       956 foreach $name (@{ $self->{ PROCESS } || [ $template ] }) {
  1226         4803  
93 1226 50       1949 $self->debug("PROCESS: $name") if $self->{ DEBUG };
94 1226         2869 $procout .= $context->process($name);
95             }
96             };
97 1226 100       2247 if ($error = $@) {
98             last SERVICE
99 17 100       42 unless defined ($procout = $self->_recover(\$error));
100             }
101            
102 1222 100       1923 if (defined $procout) {
103             # WRAPPER
104 1221         1042 eval {
105 1221         910 foreach $name (reverse @{ $self->{ WRAPPER } }) {
  1221         1792  
106 3 50       7 $self->debug("WRAPPER: $name") if $self->{ DEBUG };
107 3         7 $procout = $context->process($name, { content => $procout });
108             }
109             };
110 1221 50       1795 last SERVICE if ($error = $@);
111 1221         1433 $output .= $procout;
112             }
113            
114             # POST_PROCESS
115 1222         1040 eval {
116 1222         862 foreach $name (@{ $self->{ POST_PROCESS } }) {
  1222         1519  
117 17 50       33 $self->debug("POST_PROCESS: $name") if $self->{ DEBUG };
118 17         25 $output .= $context->process($name);
119             }
120             };
121 1222 50       1839 last SERVICE if ($error = $@);
122             }
123              
124 1226         2063 $context->delocalise();
125 1226         2713 delete $params->{ template };
126              
127 1226 100       1906 if ($error) {
128             # $error = $error->as_string if ref $error;
129 4         27 return $self->error($error);
130             }
131              
132 1222         6303 return $output;
133             }
134              
135              
136             #------------------------------------------------------------------------
137             # context()
138             #
139             # Returns the internal CONTEXT reference.
140             #------------------------------------------------------------------------
141              
142             sub context {
143 2     2 1 3 return $_[0]->{ CONTEXT };
144             }
145              
146              
147             #========================================================================
148             # -- PRIVATE METHODS --
149             #========================================================================
150              
151             sub _init {
152 155     155   233 my ($self, $config) = @_;
153 155         198 my ($item, $data, $context, $block, $blocks);
154 155         297 my $delim = $config->{ DELIMITER };
155 155 50       436 $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 155         310 foreach $item (qw( PRE_PROCESS PROCESS POST_PROCESS WRAPPER )) {
160 620         591 $data = $config->{ $item };
161 620 100       1507 $self->{ $item } = [ ], next unless (defined $data);
162 23 100 100     185 $data = [ split($delim, $data || '') ]
163             unless ref $data eq 'ARRAY';
164 23         36 $self->{ $item } = $data;
165             }
166             # unset PROCESS option unless explicitly specified in config
167             $self->{ PROCESS } = undef
168 155 100       465 unless defined $config->{ PROCESS };
169            
170 155   66     606 $self->{ ERROR } = $config->{ ERROR } || $config->{ ERRORS };
171             $self->{ AUTO_RESET } = defined $config->{ AUTO_RESET }
172 155 100       544 ? $config->{ AUTO_RESET } : 1;
173 155   100     715 $self->{ DEBUG } = ( $config->{ DEBUG } || 0 )
174             & Template::Constants::DEBUG_SERVICE;
175            
176             $context = $self->{ CONTEXT } = $config->{ CONTEXT }
177 155   50     813 || Template::Config->context($config)
178             || return $self->error(Template::Config->error);
179            
180 155         1464 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 17     17   15 my ($self, $error) = @_;
197 17         26 my $context = $self->{ CONTEXT };
198 17         15 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 17 50 33     109 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 17 100       36 return $$error->text()
209             if $$error->type() eq 'stop';
210              
211             my $handlers = $self->{ ERROR }
212 8   100     30 || return undef; ## RETURN
213              
214 4 100       8 if (ref $handlers eq 'HASH') {
215 3 100       9 if ($hkey = $$error->select_handler(keys %$handlers)) {
    50          
216 1         2 $handler = $handlers->{ $hkey };
217 1 50       2 $self->debug("using error handler for $hkey") if $self->{ DEBUG };
218             }
219             elsif ($handler = $handlers->{ default }) {
220             # use default handler
221 2 50       5 $self->debug("using default error handler") if $self->{ DEBUG };
222             }
223             else {
224 0         0 return undef; ## RETURN
225             }
226             }
227             else {
228 1         2 $handler = $handlers;
229 1 50       3 $self->debug("using default error handler") if $self->{ DEBUG };
230             }
231            
232 4         5 eval { $handler = $context->template($handler) };
  4         7  
233 4 50       7 if ($@) {
234 0         0 $$error = $@;
235 0         0 return undef; ## RETURN
236             };
237            
238 4         9 $context->stash->set('error', $$error);
239 4         5 eval {
240 4         8 $output .= $context->process($handler);
241             };
242 4 50       7 if ($@) {
243 0         0 $$error = $@;
244 0         0 return undef; ## RETURN
245             }
246              
247 4         10 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             $error = join('',
266             "{\n",
267 0 0         (map { " $_ => $error->{ $_ }\n" }
  0            
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__