16ed854041095e9cb22d8f78679b9455bf3f2446
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / i486-linux-gnu-thread-multi / Template / Service.pm
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   <abw@wardley.org>
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 use strict;
24 use warnings;
25 use base 'Template::Base';
26 use Template::Config;
27 use Template::Exception;
28 use Template::Constants;
29 use Scalar::Util 'blessed';
30
31 use constant EXCEPTION => 'Template::Exception';
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     my ($self, $template, $params) = @_;
55     my $context = $self->{ CONTEXT };
56     my ($name, $output, $procout, $error);
57     $output = '';
58
59     $self->debug("process($template, ", 
60                  defined $params ? $params : '<no params>',
61                  ')') if $self->{ DEBUG };
62
63     $context->reset()
64         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     eval { $template = $context->template($template) };
69     return $self->error($@)
70         if $@;
71
72     # localise the variable stash with any parameters passed
73     # and set the 'template' variable
74     $params ||= { };
75     # TODO: change this to C<||=> so we can use a template parameter
76     $params->{ template } = $template 
77         unless ref $template eq 'CODE';
78     $context->localise($params);
79
80     SERVICE: {
81         # PRE_PROCESS
82         eval {
83             foreach $name (@{ $self->{ PRE_PROCESS } }) {
84                 $self->debug("PRE_PROCESS: $name") if $self->{ DEBUG };
85                 $output .= $context->process($name);
86             }
87         };
88         last SERVICE if ($error = $@);
89
90         # PROCESS
91         eval {
92             foreach $name (@{ $self->{ PROCESS } || [ $template ] }) {
93                 $self->debug("PROCESS: $name") if $self->{ DEBUG };
94                 $procout .= $context->process($name);
95             }
96         };
97         if ($error = $@) {
98             last SERVICE
99                 unless defined ($procout = $self->_recover(\$error));
100         }
101         
102         if (defined $procout) {
103             # WRAPPER
104             eval {
105                 foreach $name (reverse @{ $self->{ WRAPPER } }) {
106                     $self->debug("WRAPPER: $name") if $self->{ DEBUG };
107                     $procout = $context->process($name, { content => $procout });
108                 }
109             };
110             last SERVICE if ($error = $@);
111             $output .= $procout;
112         }
113         
114         # POST_PROCESS
115         eval {
116             foreach $name (@{ $self->{ POST_PROCESS } }) {
117                 $self->debug("POST_PROCESS: $name") if $self->{ DEBUG };
118                 $output .= $context->process($name);
119             }
120         };
121         last SERVICE if ($error = $@);
122     }
123
124     $context->delocalise();
125     delete $params->{ template };
126
127     if ($error) {
128     #   $error = $error->as_string if ref $error;
129         return $self->error($error);
130     }
131
132     return $output;
133 }
134
135
136 #------------------------------------------------------------------------
137 # context()
138
139 # Returns the internal CONTEXT reference.
140 #------------------------------------------------------------------------
141
142 sub context {
143     return $_[0]->{ CONTEXT };
144 }
145
146
147 #========================================================================
148 #                     -- PRIVATE METHODS --
149 #========================================================================
150
151 sub _init {
152     my ($self, $config) = @_;
153     my ($item, $data, $context, $block, $blocks);
154     my $delim = $config->{ DELIMITER };
155     $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     foreach $item (qw( PRE_PROCESS PROCESS POST_PROCESS WRAPPER )) {
160         $data = $config->{ $item };
161         $self->{ $item } = [ ], next unless (defined $data);
162         $data = [ split($delim, $data || '') ]
163             unless ref $data eq 'ARRAY';
164         $self->{ $item } = $data;
165     }
166     # unset PROCESS option unless explicitly specified in config
167     $self->{ PROCESS } = undef
168         unless defined $config->{ PROCESS };
169     
170     $self->{ ERROR      } = $config->{ ERROR } || $config->{ ERRORS };
171     $self->{ AUTO_RESET } = defined $config->{ AUTO_RESET }
172                             ? $config->{ AUTO_RESET } : 1;
173     $self->{ DEBUG      } = ( $config->{ DEBUG } || 0 )
174                             & Template::Constants::DEBUG_SERVICE;
175     
176     $context = $self->{ CONTEXT } = $config->{ CONTEXT }
177         || Template::Config->context($config)
178         || return $self->error(Template::Config->error);
179     
180     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     my ($self, $error) = @_;
197     my $context = $self->{ CONTEXT };
198     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         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     return $$error->text()
209         if $$error->type() eq 'stop';
210
211     my $handlers = $self->{ ERROR }
212         || return undef;                    ## RETURN
213
214     if (ref $handlers eq 'HASH') {
215         if ($hkey = $$error->select_handler(keys %$handlers)) {
216             $handler = $handlers->{ $hkey };
217             $self->debug("using error handler for $hkey") if $self->{ DEBUG };
218         }
219         elsif ($handler = $handlers->{ default }) {
220             # use default handler
221             $self->debug("using default error handler") if $self->{ DEBUG };
222         }
223         else {
224             return undef;                   ## RETURN
225         }
226     }
227     else {
228         $handler = $handlers;
229         $self->debug("using default error handler") if $self->{ DEBUG };
230     }
231     
232     eval { $handler = $context->template($handler) };
233     if ($@) {
234         $$error = $@;
235         return undef;                       ## RETURN
236     };
237     
238     $context->stash->set('error', $$error);
239     eval {
240         $output .= $context->process($handler);
241     };
242     if ($@) {
243         $$error = $@;
244         return undef;                       ## RETURN
245     }
246
247     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     my $self = shift;
261     my $context = $self->{ CONTEXT }->_dump();
262     $context =~ s/\n/\n    /gm;
263
264     my $error = $self->{ ERROR };
265     $error = join('', 
266           "{\n",
267           (map { "    $_ => $error->{ $_ }\n" }
268            keys %$error),
269           "}\n")
270     if ref $error;
271     
272     local $" = ', ';
273     return <<EOF;
274 $self
275 PRE_PROCESS  => [ @{ $self->{ PRE_PROCESS } } ]
276 POST_PROCESS => [ @{ $self->{ POST_PROCESS } } ]
277 ERROR        => $error
278 CONTEXT      => $context
279 EOF
280 }
281
282
283 1;
284
285 __END__
286
287 =head1 NAME
288
289 Template::Service - General purpose template processing service
290
291 =head1 SYNOPSIS
292
293     use Template::Service;
294     
295     my $service = Template::Service->new({
296         PRE_PROCESS  => [ 'config', 'header' ],
297         POST_PROCESS => 'footer',
298         ERROR        => {
299             user     => 'user/index.html', 
300             dbi      => 'error/database',
301             default  => 'error/default',
302         },
303     });
304     
305     my $output = $service->process($template_name, \%replace)
306         || die $service->error(), "\n";
307
308 =head1 DESCRIPTION
309
310 The C<Template::Service> module implements an object class for providing
311 a consistent template processing service. 
312
313 Standard header (L<PRE_PROCESS|PRE_PROCESS_POST_PROCESS>) and footer
314 (L<POST_PROCESS|PRE_PROCESS_POST_PROCESS>) templates may be specified which
315 are prepended and appended to all templates processed by the service (but not
316 any other templates or blocks C<INCLUDE>d or C<PROCESS>ed from within). An
317 L<ERROR> hash may be specified which redirects the service to an alternate
318 template file in the case of uncaught exceptions being thrown. This allows
319 errors to be automatically handled by the service and a guaranteed valid
320 response to be generated regardless of any processing problems encountered.
321
322 A default C<Template::Service> object is created by the L<Template> module.
323 Any C<Template::Service> options may be passed to the L<Template>
324 L<new()|Template#new()> constructor method and will be forwarded to the
325 L<Template::Service> constructor.
326
327     use Template;
328     
329     my $template = Template->new({
330         PRE_PROCESS  => 'header',
331         POST_PROCESS => 'footer',
332     });
333
334 Similarly, the C<Template::Service> constructor will forward all configuration
335 parameters onto other default objects (e.g. L<Template::Context>) that it may
336 need to instantiate.
337
338 A C<Template::Service> object (or subclass) can be explicitly instantiated and
339 passed to the L<Template> L<new()|Template#new()> constructor method as the
340 L<SERVICE> item.
341
342     use Template;
343     use Template::Service;
344     
345     my $service = Template::Service->new({
346         PRE_PROCESS  => 'header',
347         POST_PROCESS => 'footer',
348     });
349     
350     my $template = Template->new({
351         SERVICE => $service,
352     });
353
354 The C<Template::Service> module can be sub-classed to create custom service
355 handlers.
356
357     use Template;
358     use MyOrg::Template::Service;
359     
360     my $service = MyOrg::Template::Service->new({
361         PRE_PROCESS  => 'header',
362         POST_PROCESS => 'footer',
363         COOL_OPTION  => 'enabled in spades',
364     });
365     
366     my $template = Template->new({
367         SERVICE => $service,
368     });
369
370 The L<Template> module uses the L<Template::Config>
371 L<service()|Template::Config#service()> factory method to create a default
372 service object when required. The C<$Template::Config::SERVICE> package
373 variable may be set to specify an alternate service module. This will be
374 loaded automatically and its L<new()> constructor method called by the
375 L<service()|Template::Config#service()> factory method when a default service
376 object is required. Thus the previous example could be written as:
377
378     use Template;
379     
380     $Template::Config::SERVICE = 'MyOrg::Template::Service';
381     
382     my $template = Template->new({
383         PRE_PROCESS  => 'header',
384         POST_PROCESS => 'footer',
385         COOL_OPTION  => 'enabled in spades',
386     });
387
388 =head1 METHODS
389
390 =head2 new(\%config)
391
392 The C<new()> constructor method is called to instantiate a C<Template::Service>
393 object.  Configuration parameters may be specified as a HASH reference or
394 as a list of C<name =E<gt> value> pairs.
395
396     my $service1 = Template::Service->new({
397         PRE_PROCESS  => 'header',
398         POST_PROCESS => 'footer',
399     });
400     
401     my $service2 = Template::Service->new( ERROR => 'error.html' );
402
403 The C<new()> method returns a C<Template::Service> object or C<undef> on
404 error. In the latter case, a relevant error message can be retrieved by the
405 L<error()|Template::Base#error()> class method or directly from the
406 C<$Template::Service::ERROR> package variable.
407
408     my $service = Template::Service->new(\%config)
409         || die Template::Service->error();
410         
411     my $service = Template::Service->new(\%config)
412         || die $Template::Service::ERROR;
413
414 =head2 process($input, \%replace)
415
416 The C<process()> method is called to process a template specified as the first
417 parameter, C<$input>. This may be a file name, file handle (e.g. C<GLOB> or
418 C<IO::Handle>) or a reference to a text string containing the template text. An
419 additional hash reference may be passed containing template variable
420 definitions.
421
422 The method processes the template, adding any
423 L<PRE_PROCESS|PRE_PROCESS_POST_PROCESS> or
424 L<POST_PROCESS|PRE_PROCESS_POST_PROCESS> templates defined, and returns the
425 output text. An uncaught exception thrown by the template will be handled by a
426 relevant L<ERROR> handler if defined. Errors that occur in the
427 L<PRE_PROCESS|PRE_PROCESS_POST_PROCESS> or
428 L<POST_PROCESS|PRE_PROCESS_POST_PROCESS> templates, or those that occur in the
429 main input template and aren't handled, cause the method to return C<undef> to
430 indicate failure. The appropriate error message can be retrieved via the
431 L<error()|Template::Base#error()> method.
432
433     $service->process('myfile.html', { title => 'My Test File' })
434         || die $service->error();
435
436 =head2 context()
437
438 Returns a reference to the internal context object which is, by default, an
439 instance of the L<Template::Context> class.
440
441 =head1 CONFIGURATION OPTIONS
442
443 The following list summarises the configuration options that can be provided
444 to the C<Template::Service> L<new()> constructor. Please consult
445 L<Template::Manual::Config> for further details and examples of each
446 configuration option in use.
447
448 =head2 PRE_PROCESS, POST_PROCESS
449
450 The L<PRE_PROCESS|Template::Manual::Config#PRE_PROCESS_POST_PROCESS> and
451 L<POST_PROCESS|Template::Manual::Config#PRE_PROCESS_POST_PROCESS> options may
452 be set to contain the name(s) of template files which should be processed
453 immediately before and/or after each template. These do not get added to
454 templates processed into a document via directives such as C<INCLUDE>
455 C<PROCESS>, C<WRAPPER>, etc.
456
457     my $service = Template::Service->new({
458         PRE_PROCESS  => 'header',
459         POST_PROCESS => 'footer',
460     };
461
462 Multiple templates may be specified as a reference to a list.  Each is 
463 processed in the order defined.
464
465     my $service = Template::Service->new({
466         PRE_PROCESS  => [ 'config', 'header' ],
467         POST_PROCESS => 'footer',
468     };
469
470 =head2 PROCESS
471
472 The L<PROCESS|Template::Manual::Config#PROCESS> option may be set to contain
473 the name(s) of template files which should be processed instead of the main
474 template passed to the C<Template::Service> L<process()> method. This can be used to
475 apply consistent wrappers around all templates, similar to the use of
476 L<PRE_PROCESS|PRE_PROCESS_POST_PROCESS> and 
477 L<POST_PROCESS|PRE_PROCESS_POST_PROCESS> templates.
478
479     my $service = Template::Service->new({
480         PROCESS  => 'content',
481     };
482     
483     # processes 'content' instead of 'foo.html'
484     $service->process('foo.html');
485
486 A reference to the original template is available in the C<template>
487 variable.  Metadata items can be inspected and the template can be
488 processed by specifying it as a variable reference (i.e. prefixed by
489 'C<$>') to an C<INCLUDE>, C<PROCESS> or C<WRAPPER> directive.
490
491 Example C<PROCESS> template:
492
493     <html>
494       <head>
495         <title>[% template.title %]</title>
496       </head>
497       <body>
498       [% PROCESS $template %]
499       </body>
500     </html>
501
502 =head2 ERROR
503
504 The L<ERROR|Template::Manual::Config#ERROR> (or C<ERRORS> if you prefer)
505 configuration item can be used to name a single template or specify a hash
506 array mapping exception types to templates which should be used for error
507 handling. If an uncaught exception is raised from within a template then the
508 appropriate error template will instead be processed.
509
510 If specified as a single value then that template will be processed 
511 for all uncaught exceptions. 
512
513     my $service = Template::Service->new({
514         ERROR => 'error.html'
515     });
516
517 If the L<ERROR/ERRORS|Template::Manual::Config#ERROR> item is a hash reference
518 the keys are assumed to be exception types and the relevant template for a
519 given exception will be selected. A C<default> template may be provided for
520 the general case.
521
522     my $service = Template::Service->new({
523         ERRORS => {
524             user     => 'user/index.html',
525             dbi      => 'error/database',
526             default  => 'error/default',
527         },
528     });
529
530 =head2 AUTO_RESET
531
532 The L<AUTO_RESET|Template::Manual::Config#AUTO_RESET> option is set by default
533 and causes the local C<BLOCKS> cache for the L<Template::Context> object to be
534 reset on each call to the L<Template> L<process()|Template#process()> method.
535 This ensures that any C<BLOCK>s defined within a template will only persist until
536 that template is finished processing. 
537
538 =head2 DEBUG
539
540 The L<DEBUG|Template::Manual::Config#DEBUG> option can be used to enable
541 debugging messages from the C<Template::Service> module by setting it to include
542 the C<DEBUG_SERVICE> value.
543
544     use Template::Constants qw( :debug );
545     
546     my $template = Template->new({
547         DEBUG => DEBUG_SERVICE,
548     });
549
550 =head1 AUTHOR
551
552 Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/>
553
554 =head1 COPYRIGHT
555
556 Copyright (C) 1996-2007 Andy Wardley.  All Rights Reserved.
557
558 This module is free software; you can redistribute it and/or
559 modify it under the same terms as Perl itself.
560
561 =head1 SEE ALSO
562
563 L<Template>, L<Template::Context>
564
565 =cut
566
567 # Local Variables:
568 # mode: perl
569 # perl-indent-level: 4
570 # indent-tabs-mode: nil
571 # End:
572 #
573 # vim: expandtab shiftwidth=4: