File Coverage

blib/lib/Template/Context/Cacheable.pm
Criterion Covered Total %
statement 21 82 25.6
branch 0 44 0.0
condition 0 21 0.0
subroutine 7 9 77.7
pod 2 2 100.0
total 30 158 18.9


line stmt bran cond sub pod time code
1             package Template::Context::Cacheable;
2              
3 1     1   24780 use warnings;
  1         3  
  1         39  
4 1     1   6 use strict;
  1         4  
  1         70  
5              
6             =head1 NAME
7              
8             Template::Context::Cacheable - profiling/caching-aware version of Template::Context
9              
10             =cut
11              
12             our $VERSION = '0.03';
13              
14             =head1 SYNOPSIS
15             use My::Favourite::Cache::Engine;
16             use Template::Context::Cacheable;
17              
18             Template::Context::Cacheable::configure_caching(
19             \&My::Favourite::Cache::Engine::get,
20             \&My::Favourite::Cache::Engine::put,
21             );
22              
23             =head1 DESCRIPTION
24              
25             Enables profiling and caching of Template-Toolkit subtemplates, that can improve
26             template processing speed many times.
27              
28             =head2 Using in templates
29              
30             Inside any template you can use cached subtemplates. See example:
31              
32             [% PROCESS subtemplate.tt
33             param_name_1 = 'value_1'
34             param_name_2 = 'value_2'
35             __cache_time = 60
36             %]
37              
38             Here __cache_time parameter enables caching and sets caching time in seconds.
39             If __cache_time value is negative, subtemplated will be cached forever
40             (actually it will be cached for 12 hours ;)
41              
42             param_name_X is examples of parameters, which combination will be used as a hash key.
43              
44             =cut
45              
46 1     1   8 use base qw(Template::Context);
  1         8  
  1         3849  
47 1     1   27066 use Digest::MD5;
  1         3  
  1         63  
48 1     1   10961 use Time::HiRes qw/time/;
  1         2386  
  1         7  
49              
50 1     1   1357 use Data::Dumper;
  1         9341  
  1         98  
51              
52 1     1   976 use lib '/www/srs/lib';
  1         778  
  1         6  
53              
54             our $DEBUG = 0;
55             our $CACHE_GET; # GET subroutine reference
56             our $CACHE_PUT; # PUT subroutine reference
57              
58             my @stack;
59             my %totals;
60              
61             =head1 FUNCTIONS / METHODS
62              
63             The following functions / methods are available:
64              
65             =head2 configure_caching ( cache_get_ref, cache_put_ref )
66              
67             Install cache get / put handlers.
68              
69             Here are protypes for get / put handlers which illustrates parameters which they will receive:
70              
71             sub get {
72             my ($key) = @_;
73              
74             ...
75             }
76              
77             sub set {
78             my ($code, $key, $keep_in_seconds) = @_;
79              
80             ...
81             }
82              
83             =cut
84              
85             sub configure_caching {
86 0     0 1   ($CACHE_GET, $CACHE_PUT) = @_;
87             }
88              
89             =head2 process ( self )
90              
91             Overloaded Template::Context::process method
92              
93             =cut
94              
95             sub process {
96 0     0 1   my $self = shift;
97              
98 0           my $template = $_[0];
99 0 0         if (UNIVERSAL::isa($template, "Template::Document")) {
100 0   0       $template = $template->name || $template;
101             }
102              
103 0           my @result;
104              
105 0 0         if ($DEBUG) {
106 0           push @stack, [ time, times ];
107 0 0         print STDERR Dumper( @_ ) if $DEBUG >= 2;
108             }
109              
110 0 0 0       unless ($CACHE_GET && $CACHE_PUT) {
111 0 0         @result = wantarray ?
112             $self->SUPER::process(@_) :
113             scalar $self->SUPER::process(@_);
114              
115 0           goto SKIP_CACHING;
116             }
117              
118             # subtemplates caching
119              
120 0           my $cache_key = '';
121 0           my $cache_time;
122              
123 0           my $param_ref = $_[1];
124              
125 0 0 0       if (exists $param_ref->{__cache_time} && !$param_ref->{__cache_time}) {
126 0           delete $param_ref->{__cache_time};
127             }
128 0 0 0       if ($param_ref && ref $param_ref eq 'HASH' && $param_ref->{__cache_time}) {
      0        
129 0           $cache_time = delete $param_ref->{__cache_time};
130 0 0         $cache_time = $cache_time < 0 ? 3600 * 12 : $cache_time;
131              
132 0           $cache_key = join '_', map { ($_, $param_ref->{$_}) } sort keys %$param_ref;
  0            
133              
134 0 0         print STDERR "RAW KEY: $cache_key\n" if $DEBUG >= 2;
135              
136 0           $cache_key = $template . '__' . Digest::MD5::md5_hex( $cache_key );
137              
138             # Удалим ненужные для обработки шаблона ключи
139             # (которые являются исключительно ключами кэширования)
140 0           foreach my $key (keys %{$param_ref}) {
  0            
141 0 0         delete $param_ref->{$key} if $key =~ /^__nocache_/;
142             }
143             }
144 0 0 0       print STDERR "HASHED KEY: $cache_key\n" if $DEBUG >= 2 && $cache_key;
145              
146 0           my $cached_data;
147 0 0 0       if ($cache_key && ($cached_data = $CACHE_GET->($cache_key))) {
148 0 0         print STDERR "$template: CACHED ($cache_key)\n" if $DEBUG >= 2;
149 0           @result = @{ $cached_data };
  0            
150             }
151             else {
152 0 0         print STDERR "$template: NON_CACHED ($cache_key)\n" if $DEBUG >= 2;
153 0 0         @result = wantarray ?
154             $self->SUPER::process(@_) :
155             scalar $self->SUPER::process(@_);
156 0 0         $CACHE_PUT->( $cache_key, \@result, $cache_time ) if $cache_key;
157             }
158              
159             # / subtemplates caching
160             SKIP_CACHING:
161              
162 0 0         if ($DEBUG) {
163 0           my @delta_times = @{pop @stack};
  0            
164 0           @delta_times = map { $_ - shift @delta_times } time, times;
  0            
165 0           for (0..$#delta_times) {
166 0           $totals{$template}[$_] += $delta_times[$_];
167 0           for my $parent (@stack) {
168 0 0         $parent->[$_] += $delta_times[$_] if @stack; # parent adjust
169             }
170             }
171 0           $totals{$template}[5] ++; # count of calls
172 0 0         $totals{$template}[6] = $cached_data ? 1 : 0;
173              
174 0 0         unless (@stack) {
175             ## top level again, time to display results
176 0           print STDERR "-- $template at ". localtime, ":\n";
177 0           printf STDERR "%4s %6s %6s %6s %6s %6s %s\n",
178             qw(cnt clk user sys cuser csys template);
179              
180 0           my @totals = (0) x 6;
181              
182 0           for my $template (sort keys %totals) {
183 0           my @values = @{$totals{$template}};
  0            
184 0 0         printf STDERR "%4d %6.4f %6.4f %6.4f %6.4f %6.4f %s\n",
185             $values[5],
186             @values[0..4],
187             $template .($values[6] ? ' CACHED' : '');
188              
189 0           for my $i (0..5) { $totals[$i] += $values[$i] };
  0            
190             }
191              
192 0           printf STDERR "%4d %6.4f %6.4f %6.4f %6.4f %6.4f %s\n",
193             $totals[5],
194             @totals[0..4],
195             'TOTAL';
196              
197 0           print STDERR "-- end\n";
198 0           %totals = (); # clear out results
199             }
200             }
201              
202             # return value from process:
203 0 0         wantarray ? @result : $result[0];
204             }
205              
206             $Template::Config::CONTEXT = __PACKAGE__;
207              
208             =head1 EXPORT
209              
210             No functions is exported.
211              
212             =head1 AUTHOR
213              
214             Walery Studennikov, C<< >>
215              
216             =head1 COPYRIGHT & LICENSE
217              
218             This program is free software; you can redistribute it and/or modify it
219             under the same terms as Perl itself.
220              
221             =cut
222              
223             1;