1#============================================================= -*-Perl-*- 2# 3# Template::Provider 4# 5# DESCRIPTION 6# This module implements a class which handles the loading, compiling 7# and caching of templates. Multiple Template::Provider objects can 8# be stacked and queried in turn to effect a Chain-of-Command between 9# them. A provider will attempt to return the requested template, 10# an error (STATUS_ERROR) or decline to provide the template 11# (STATUS_DECLINE), allowing subsequent providers to attempt to 12# deliver it. See 'Design Patterns' for further details. 13# 14# AUTHORS 15# Andy Wardley <abw@wardley.org> 16# 17# Refactored by Bill Moseley for v2.19 to add negative caching (i.e. 18# tracking templates that are NOTFOUND so that we can decline quickly) 19# and to provide better support for subclassing the provider. 20# 21# COPYRIGHT 22# Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved. 23# 24# This module is free software; you can redistribute it and/or 25# modify it under the same terms as Perl itself. 26# 27# WARNING: 28# This code is ugly and contorted and is being totally re-written for TT3. 29# In particular, we'll be throwing errors rather than messing around 30# returning (value, status) pairs. With the benefit of hindsight, that 31# was a really bad design decision on my part. I deserve to be knocked 32# to the ground and kicked around a bit by hoards of angry TT developers 33# for that one. Bill's refactoring has made the module easier to subclass, 34# (so you can ease off the kicking now), but it really needs to be totally 35# redesigned and rebuilt from the ground up along with the bits of TT that 36# use it. -- abw 2007/04/27 37#============================================================================ 38 39package Template::Provider; 40 41use strict; 42use warnings; 43use base 'Template::Base'; 44use Template::Config; 45use Template::Constants; 46use Template::Document; 47use File::Basename; 48use File::Spec; 49 50use constant PREV => 0; 51use constant NAME => 1; # template name -- indexed by this name in LOOKUP 52use constant DATA => 2; # Compiled template 53use constant LOAD => 3; # mtime of template 54use constant NEXT => 4; # link to next item in cache linked list 55use constant STAT => 5; # Time last stat()ed 56use constant MSWin32 => $^O eq 'MSWin32'; 57 58our $VERSION = '3.010'; 59our $DEBUG = 0 unless defined $DEBUG; 60our $ERROR = ''; 61 62# name of document class 63our $DOCUMENT = 'Template::Document' unless defined $DOCUMENT; 64 65# maximum time between performing stat() on file to check staleness 66our $STAT_TTL = 1 unless defined $STAT_TTL; 67 68# maximum number of directories in an INCLUDE_PATH, to prevent runaways 69our $MAX_DIRS = 64 unless defined $MAX_DIRS; 70 71# UNICODE is supported in versions of Perl from 5.007 onwards 72our $UNICODE = $] > 5.007 ? 1 : 0; 73 74my $boms = [ 75 'UTF-8' => "\x{ef}\x{bb}\x{bf}", 76 'UTF-32BE' => "\x{0}\x{0}\x{fe}\x{ff}", 77 'UTF-32LE' => "\x{ff}\x{fe}\x{0}\x{0}", 78 'UTF-16BE' => "\x{fe}\x{ff}", 79 'UTF-16LE' => "\x{ff}\x{fe}", 80]; 81 82# regex to match relative paths 83our $RELATIVE_PATH = qr[(?:^|/)\.+/]; 84 85#======================================================================== 86# -- PUBLIC METHODS -- 87#======================================================================== 88 89#------------------------------------------------------------------------ 90# fetch($name) 91# 92# Returns a compiled template for the name specified by parameter. 93# The template is returned from the internal cache if it exists, or 94# loaded and then subsequently cached. The ABSOLUTE and RELATIVE 95# configuration flags determine if absolute (e.g. '/something...') 96# and/or relative (e.g. './something') paths should be honoured. The 97# INCLUDE_PATH is otherwise used to find the named file. $name may 98# also be a reference to a text string containing the template text, 99# or a file handle from which the content is read. The compiled 100# template is not cached in these latter cases given that there is no 101# filename to cache under. A subsequent call to store($name, 102# $compiled) can be made to cache the compiled template for future 103# fetch() calls, if necessary. 104# 105# Returns a compiled template or (undef, STATUS_DECLINED) if the 106# template could not be found. On error (e.g. the file was found 107# but couldn't be read or parsed), the pair ($error, STATUS_ERROR) 108# is returned. The TOLERANT configuration option can be set to 109# downgrade any errors to STATUS_DECLINE. 110#------------------------------------------------------------------------ 111 112sub fetch { 113 my ($self, $name) = @_; 114 my ($data, $error); 115 116 117 if (ref $name) { 118 # $name can be a reference to a scalar, GLOB or file handle 119 ($data, $error) = $self->_load($name); 120 ($data, $error) = $self->_compile($data) 121 unless $error; 122 $data = $data->{ data } 123 unless $error; 124 } 125 elsif (File::Spec->file_name_is_absolute($name)) { 126 # absolute paths (starting '/') allowed if ABSOLUTE set 127 ($data, $error) = $self->{ ABSOLUTE } 128 ? $self->_fetch($name) 129 : $self->{ TOLERANT } 130 ? (undef, Template::Constants::STATUS_DECLINED) 131 : ("$name: absolute paths are not allowed (set ABSOLUTE option)", 132 Template::Constants::STATUS_ERROR); 133 } 134 elsif ($name =~ m/$RELATIVE_PATH/o) { 135 # anything starting "./" is relative to cwd, allowed if RELATIVE set 136 ($data, $error) = $self->{ RELATIVE } 137 ? $self->_fetch($name) 138 : $self->{ TOLERANT } 139 ? (undef, Template::Constants::STATUS_DECLINED) 140 : ("$name: relative paths are not allowed (set RELATIVE option)", 141 Template::Constants::STATUS_ERROR); 142 } 143 else { 144 # otherwise, it's a file name relative to INCLUDE_PATH 145 ($data, $error) = $self->{ INCLUDE_PATH } 146 ? $self->_fetch_path($name) 147 : (undef, Template::Constants::STATUS_DECLINED); 148 } 149 150 return ($data, $error); 151} 152 153 154#------------------------------------------------------------------------ 155# store($name, $data) 156# 157# Store a compiled template ($data) in the cached as $name. 158# Returns compiled template 159#------------------------------------------------------------------------ 160 161sub store { 162 my ($self, $name, $data, $mtime) = @_; 163 $self->_store($name, { 164 data => $data, 165 load => 0, 166 mtime => $mtime 167 }); 168} 169 170 171#------------------------------------------------------------------------ 172# load($name) 173# 174# Load a template without parsing/compiling it, suitable for use with 175# the INSERT directive. There's some duplication with fetch() and at 176# some point this could be reworked to integrate them a little closer. 177#------------------------------------------------------------------------ 178 179sub load { 180 my ($self, $name) = @_; 181 my ($data, $error); 182 my $path = $name; 183 184 if (File::Spec->file_name_is_absolute($name)) { 185 # absolute paths (starting '/') allowed if ABSOLUTE set 186 $error = "$name: absolute paths are not allowed (set ABSOLUTE option)" 187 unless $self->{ ABSOLUTE }; 188 } 189 elsif ($name =~ m[$RELATIVE_PATH]o) { 190 # anything starting "./" is relative to cwd, allowed if RELATIVE set 191 $error = "$name: relative paths are not allowed (set RELATIVE option)" 192 unless $self->{ RELATIVE }; 193 } 194 else { 195 INCPATH: { 196 # otherwise, it's a file name relative to INCLUDE_PATH 197 my $paths = $self->paths() 198 || return ($self->error(), Template::Constants::STATUS_ERROR); 199 200 foreach my $dir (@$paths) { 201 $path = File::Spec->catfile($dir, $name); 202 last INCPATH 203 if defined $self->_template_modified($path); 204 } 205 undef $path; # not found 206 } 207 } 208 209 # Now fetch the content 210 ($data, $error) = $self->_template_content($path) 211 if defined $path && !$error; 212 213 if ($error) { 214 return $self->{ TOLERANT } 215 ? (undef, Template::Constants::STATUS_DECLINED) 216 : ($error, Template::Constants::STATUS_ERROR); 217 } 218 elsif (! defined $path) { 219 return (undef, Template::Constants::STATUS_DECLINED); 220 } 221 else { 222 return ($data, Template::Constants::STATUS_OK); 223 } 224} 225 226 227 228#------------------------------------------------------------------------ 229# include_path(\@newpath) 230# 231# Accessor method for the INCLUDE_PATH setting. If called with an 232# argument, this method will replace the existing INCLUDE_PATH with 233# the new value. 234#------------------------------------------------------------------------ 235 236sub include_path { 237 my ($self, $path) = @_; 238 $self->{ INCLUDE_PATH } = $path if $path; 239 return $self->{ INCLUDE_PATH }; 240} 241 242 243#------------------------------------------------------------------------ 244# paths() 245# 246# Evaluates the INCLUDE_PATH list, ignoring any blank entries, and 247# calling and subroutine or object references to return dynamically 248# generated path lists. Returns a reference to a new list of paths 249# or undef on error. 250#------------------------------------------------------------------------ 251 252sub paths { 253 my $self = shift; 254 my @ipaths = @{ $self->{ INCLUDE_PATH } }; 255 my (@opaths, $dpaths, $dir); 256 my $count = $MAX_DIRS; 257 258 while (@ipaths && --$count) { 259 $dir = shift @ipaths || next; 260 261 # $dir can be a sub or object ref which returns a reference 262 # to a dynamically generated list of search paths. 263 264 if (ref $dir eq 'CODE') { 265 eval { $dpaths = &$dir() }; 266 if ($@) { 267 chomp $@; 268 return $self->error($@); 269 } 270 unshift(@ipaths, @$dpaths); 271 next; 272 } 273 elsif (ref($dir) && UNIVERSAL::can($dir, 'paths')) { 274 $dpaths = $dir->paths() 275 || return $self->error($dir->error()); 276 unshift(@ipaths, @$dpaths); 277 next; 278 } 279 else { 280 push(@opaths, $dir); 281 } 282 } 283 return $self->error("INCLUDE_PATH exceeds $MAX_DIRS directories") 284 if @ipaths; 285 286 return \@opaths; 287} 288 289 290#------------------------------------------------------------------------ 291# DESTROY 292# 293# The provider cache is implemented as a doubly linked list which Perl 294# cannot free by itself due to the circular references between NEXT <=> 295# PREV items. This cleanup method walks the list deleting all the NEXT/PREV 296# references, allowing the proper cleanup to occur and memory to be 297# repooled. 298#------------------------------------------------------------------------ 299 300sub DESTROY { 301 my $self = shift; 302 my ($slot, $next); 303 304 $slot = $self->{ HEAD }; 305 while ($slot) { 306 $next = $slot->[ NEXT ]; 307 undef $slot->[ PREV ]; 308 undef $slot->[ NEXT ]; 309 $slot = $next; 310 } 311 undef $self->{ HEAD }; 312 undef $self->{ TAIL }; 313} 314 315 316 317 318#======================================================================== 319# -- PRIVATE METHODS -- 320#======================================================================== 321 322#------------------------------------------------------------------------ 323# _init() 324# 325# Initialise the cache. 326#------------------------------------------------------------------------ 327 328sub _init { 329 my ($self, $params) = @_; 330 my $size = $params->{ CACHE_SIZE }; 331 my $path = $params->{ INCLUDE_PATH } || '.'; 332 my $cdir = $params->{ COMPILE_DIR } || ''; 333 my $dlim = $params->{ DELIMITER }; 334 my $debug; 335 336 # tweak delim to ignore C:/ 337 unless (defined $dlim) { 338 $dlim = MSWin32 ? ':(?!\\/)' : ':'; 339 } 340 341 # coerce INCLUDE_PATH to an array ref, if not already so 342 $path = [ split(/$dlim/, $path) ] 343 unless ref $path eq 'ARRAY'; 344 345 # don't allow a CACHE_SIZE 1 because it breaks things and the 346 # additional checking isn't worth it 347 $size = 2 348 if defined $size && ($size == 1 || $size < 0); 349 350 if (defined ($debug = $params->{ DEBUG })) { 351 $self->{ DEBUG } = $debug & ( Template::Constants::DEBUG_PROVIDER 352 | Template::Constants::DEBUG_FLAGS ); 353 } 354 else { 355 $self->{ DEBUG } = $DEBUG; 356 } 357 358 if ($self->{ DEBUG }) { 359 local $" = ', '; 360 $self->debug("creating cache of ", 361 defined $size ? $size : 'unlimited', 362 " slots for [ @$path ]"); 363 } 364 365 # create COMPILE_DIR and sub-directories representing each INCLUDE_PATH 366 # element in which to store compiled files 367 if ($cdir) { 368 require File::Path; 369 foreach my $dir (@$path) { 370 next if ref $dir; 371 my $wdir = $dir; 372 $wdir =~ tr[:][]d if MSWin32; 373 { 374 no warnings 'syntax'; 375 $wdir = each %{ { $wdir => undef } } if ${^TAINT}; #untaint 376 } 377 $wdir = File::Spec->catfile($cdir, $wdir); 378 File::Path::mkpath($wdir) unless -d $wdir; 379 } 380 } 381 382 $self->{ LOOKUP } = { }; 383 $self->{ NOTFOUND } = { }; # Tracks templates *not* found. 384 $self->{ SLOTS } = 0; 385 $self->{ SIZE } = $size; 386 $self->{ INCLUDE_PATH } = $path; 387 $self->{ DELIMITER } = $dlim; 388 $self->{ COMPILE_DIR } = $cdir; 389 $self->{ COMPILE_EXT } = $params->{ COMPILE_EXT } || ''; 390 $self->{ ABSOLUTE } = $params->{ ABSOLUTE } || 0; 391 $self->{ RELATIVE } = $params->{ RELATIVE } || 0; 392 $self->{ TOLERANT } = $params->{ TOLERANT } || 0; 393 $self->{ DOCUMENT } = $params->{ DOCUMENT } || $DOCUMENT; 394 $self->{ PARSER } = $params->{ PARSER }; 395 $self->{ DEFAULT } = $params->{ DEFAULT }; 396 $self->{ ENCODING } = $params->{ ENCODING }; 397# $self->{ PREFIX } = $params->{ PREFIX }; 398 $self->{ STAT_TTL } = $params->{ STAT_TTL } || $STAT_TTL; 399 $self->{ PARAMS } = $params; 400 401 # look for user-provided UNICODE parameter or use default from package var 402 $self->{ UNICODE } = defined $params->{ UNICODE } 403 ? $params->{ UNICODE } : $UNICODE; 404 405 return $self; 406} 407 408 409#------------------------------------------------------------------------ 410# _fetch($name, $t_name) 411# 412# Fetch a file from cache or disk by specification of an absolute or 413# relative filename. No search of the INCLUDE_PATH is made. If the 414# file is found and loaded, it is compiled and cached. 415# Call with: 416# $name = path to search (possible prefixed by INCLUDE_PATH) 417# $t_name = template name 418#------------------------------------------------------------------------ 419 420sub _fetch { 421 my ($self, $name, $t_name) = @_; 422 my $stat_ttl = $self->{ STAT_TTL }; 423 424 $self->debug("_fetch($name)") if $self->{ DEBUG }; 425 426 # First see if the named template is in the memory cache 427 if ((my $slot = $self->{ LOOKUP }->{ $name })) { 428 # Test if cache is fresh, and reload/compile if not. 429 my ($data, $error) = $self->_refresh($slot); 430 431 return $error 432 ? ( $data, $error ) # $data may contain error text 433 : $slot->[ DATA ]; # returned document object 434 } 435 436 # Otherwise, see if we already know the template is not found 437 if (my $last_stat_time = $self->{ NOTFOUND }->{ $name }) { 438 my $expires_in = $last_stat_time + $stat_ttl - time; 439 if ($expires_in > 0) { 440 $self->debug(" file [$name] in negative cache. Expires in $expires_in seconds") 441 if $self->{ DEBUG }; 442 return (undef, Template::Constants::STATUS_DECLINED); 443 } 444 else { 445 delete $self->{ NOTFOUND }->{ $name }; 446 } 447 } 448 449 my($template,$error); 450 my $uncompiled_template_mtime = $self->_template_modified( $name ); # does template exist? 451 452 # some templates like Provider::FromDATA does not provide mtime information 453 $uncompiled_template_mtime = 0 unless defined $uncompiled_template_mtime; 454 455 # Is there an up-to-date compiled version on disk? 456 if (my $template_mtime = $self->_compiled_is_current($name, $uncompiled_template_mtime)) { 457 # require() the compiled template. 458 my $compiled_template = $self->_load_compiled( $self->_compiled_filename($name) ); 459 460 # Store and return the compiled template 461 return $self->store( $name, $compiled_template, $template_mtime ) if $compiled_template; 462 463 # Problem loading compiled template: 464 # warn and continue to fetch source template 465 warn($self->error(), "\n"); 466 } 467 468 # load template from source 469 ($template, $error) = $self->_load($name, $t_name); 470 471 if ($error) { 472 # Template could not be fetched. Add to the negative/notfound cache. 473 $self->{ NOTFOUND }->{ $name } = time; 474 return ( $template, $error ); 475 } 476 477 # compile template source 478 ($template, $error) = $self->_compile($template, $self->_compiled_filename($name) ); 479 480 if ($error) { 481 # return any compile time error 482 return ($template, $error); 483 } 484 else { 485 # Store compiled template and return it 486 return $self->store($name, $template->{data}) ; 487 } 488} 489 490 491#------------------------------------------------------------------------ 492# _fetch_path($name) 493# 494# Fetch a file from cache or disk by specification of an absolute cache 495# name (e.g. 'header') or filename relative to one of the INCLUDE_PATH 496# directories. If the file isn't already cached and can be found and 497# loaded, it is compiled and cached under the full filename. 498#------------------------------------------------------------------------ 499 500sub _fetch_path { 501 my ($self, $name) = @_; 502 503 $self->debug("_fetch_path($name)") if $self->{ DEBUG }; 504 505 # the template may have been stored using a non-filename name 506 # so look for the plain name in the cache first 507 if ((my $slot = $self->{ LOOKUP }->{ $name })) { 508 # cached entry exists, so refresh slot and extract data 509 my ($data, $error) = $self->_refresh($slot); 510 511 return $error 512 ? ($data, $error) 513 : ($slot->[ DATA ], $error ); 514 } 515 516 my $paths = $self->paths 517 || return ( $self->error, Template::Constants::STATUS_ERROR ); 518 519 # search the INCLUDE_PATH for the file, in cache or on disk 520 foreach my $dir (@$paths) { 521 my $path = File::Spec->catfile($dir, $name); 522 523 $self->debug("searching path: $path\n") if $self->{ DEBUG }; 524 525 my ($data, $error) = $self->_fetch( $path, $name ); 526 527 # Return if no error or if a serious error. 528 return ( $data, $error ) 529 if !$error || $error == Template::Constants::STATUS_ERROR; 530 531 } 532 533 # not found in INCLUDE_PATH, now try DEFAULT 534 return $self->_fetch_path( $self->{DEFAULT} ) 535 if defined $self->{DEFAULT} && $name ne $self->{DEFAULT}; 536 537 # We could not handle this template name 538 return (undef, Template::Constants::STATUS_DECLINED); 539} 540 541sub _compiled_filename { 542 my ($self, $file) = @_; 543 544 return $self->{ COMPILEDPATH }{$file} if $self->{ COMPILEDPATH }{$file}; 545 546 my ($compext, $compdir) = @$self{ qw( COMPILE_EXT COMPILE_DIR ) }; 547 my ($path, $compiled); 548 549 return undef 550 unless $compext || $compdir; 551 552 $path = $file; 553 $path or die "invalid filename: $path"; 554 $path =~ tr[:][]d if MSWin32; 555 556 557 $compiled = "$path$compext"; 558 $self->{ COMPILEDPATH }{$file} = $compiled = File::Spec->catfile($compdir, $compiled) if length $compdir; 559 560 return $compiled; 561} 562 563sub _load_compiled { 564 my ($self, $file) = @_; 565 566 # Implicitly Relative paths are not supported 567 # by "require" and invoke @INC traversal, where relative 568 # paths only traditionally worked prior to Perl 5.26 569 # due to the presence of '.' in @INC 570 # 571 # Given load_compiled never wants to traverse @INC, forcing 572 # an absolute path for the loaded file and the INC key is 573 # sensible. 574 # 575 # NB: %INC Keys are always identical to their respective 576 # "require" invocations regardless of OS, and the only time 577 # one needs to care about slash direction is when dealing 578 # with Module::Name -> Module/Name.pm translation. 579 my $fpath = File::Spec->rel2abs( $file ); 580 581 return $self->error("compiled template missing path") unless defined $fpath; 582 583 ($fpath) = $fpath =~ /^(.*)$/s; 584 585 my $compiled; 586 587 # load compiled template via require(); we zap any 588 # %INC entry to ensure it is reloaded (we don't 589 # want 1 returned by require() to say it's in memory) 590 delete $INC{ $fpath }; 591 eval { $compiled = require $fpath; }; 592 return $@ 593 ? $self->error("compiled template $compiled: $@") 594 : $compiled; 595} 596 597#------------------------------------------------------------------------ 598# _load($name, $alias) 599# 600# Load template text from a string ($name = scalar ref), GLOB or file 601# handle ($name = ref), or from an absolute filename ($name = scalar). 602# Returns a hash array containing the following items: 603# name filename or $alias, if provided, or 'input text', etc. 604# text template text 605# time modification time of file, or current time for handles/strings 606# load time file was loaded (now!) 607# 608# On error, returns ($error, STATUS_ERROR), or (undef, STATUS_DECLINED) 609# if TOLERANT is set. 610#------------------------------------------------------------------------ 611 612sub _load { 613 my ($self, $name, $alias) = @_; 614 my ($data, $error); 615 my $tolerant = $self->{ TOLERANT }; 616 my $now = time; 617 618 $alias = $name unless defined $alias or ref $name; 619 620 $self->debug("_load($name, ", defined $alias ? $alias : '<no alias>', 621 ')') if $self->{ DEBUG }; 622 623 # SCALAR ref is the template text 624 if (ref $name eq 'SCALAR') { 625 # $name can be a SCALAR reference to the input text... 626 return { 627 name => defined $alias ? $alias : 'input text', 628 path => defined $alias ? $alias : 'input text', 629 text => $$name, 630 time => $now, 631 load => 0, 632 }; 633 } 634 635 # Otherwise, assume GLOB as a file handle 636 if (ref $name) { 637 local $/; 638 my $text = <$name>; 639 $text = $self->_decode_unicode($text) if $self->{ UNICODE }; 640 return { 641 name => defined $alias ? $alias : 'input file handle', 642 path => defined $alias ? $alias : 'input file handle', 643 text => $text, 644 time => $now, 645 load => 0, 646 }; 647 } 648 649 # Otherwise, it's the name of the template 650 if ( defined $self->_template_modified( $name ) ) { # does template exist? 651 my ($text, $error, $mtime ) = $self->_template_content( $name ); 652 unless ( $error ) { 653 $text = $self->_decode_unicode($text) if $self->{ UNICODE }; 654 return { 655 name => $alias, 656 path => $name, 657 text => $text, 658 time => $mtime, 659 load => $now, 660 }; 661 } 662 663 return ( $error, Template::Constants::STATUS_ERROR ) 664 unless $tolerant; 665 } 666 667 # Unable to process template, pass onto the next Provider. 668 return (undef, Template::Constants::STATUS_DECLINED); 669} 670 671 672#------------------------------------------------------------------------ 673# _refresh(\@slot) 674# 675# Private method called to mark a cache slot as most recently used. 676# A reference to the slot array should be passed by parameter. The 677# slot is relocated to the head of the linked list. If the file from 678# which the data was loaded has been updated since it was compiled, then 679# it is re-loaded from disk and re-compiled. 680#------------------------------------------------------------------------ 681 682sub _refresh { 683 my ($self, $slot) = @_; 684 my $stat_ttl = $self->{ STAT_TTL }; 685 my ($head, $file, $data, $error); 686 687 $self->debug("_refresh([ ", 688 join(', ', map { defined $_ ? $_ : '<undef>' } @$slot), 689 '])') if $self->{ DEBUG }; 690 691 # if it's more than $STAT_TTL seconds since we last performed a 692 # stat() on the file then we need to do it again and see if the file 693 # time has changed 694 my $now = time; 695 my $expires_in_sec = $slot->[ STAT ] + $stat_ttl - $now; 696 697 if ( $expires_in_sec <= 0 ) { # Time to check! 698 $slot->[ STAT ] = $now; 699 700 # Grab mtime of template. 701 # Seems like this should be abstracted to compare to 702 # just ask for a newer compiled template (if it's newer) 703 # and let that check for a newer template source. 704 my $template_mtime = $self->_template_modified( $slot->[ NAME ] ); 705 if ( ! defined $template_mtime || ( $template_mtime != $slot->[ LOAD ] )) { 706 $self->debug("refreshing cache file ", $slot->[ NAME ]) 707 if $self->{ DEBUG }; 708 709 ($data, $error) = $self->_load($slot->[ NAME ], $slot->[ DATA ]->{ name }); 710 ($data, $error) = $self->_compile($data) 711 unless $error; 712 713 if ($error) { 714 # if the template failed to load/compile then we wipe out the 715 # STAT entry. This forces the provider to try and reload it 716 # each time instead of using the previously cached version 717 # until $STAT_TTL is next up 718 $slot->[ STAT ] = 0; 719 } 720 else { 721 $slot->[ DATA ] = $data->{ data }; 722 $slot->[ LOAD ] = $data->{ time }; 723 } 724 } 725 726 } elsif ( $self->{ DEBUG } ) { 727 $self->debug( sprintf('STAT_TTL not met for file [%s]. Expires in %d seconds', 728 $slot->[ NAME ], $expires_in_sec ) ); 729 } 730 731 # Move this slot to the head of the list 732 unless( $self->{ HEAD } == $slot ) { 733 # remove existing slot from usage chain... 734 if ($slot->[ PREV ]) { 735 $slot->[ PREV ]->[ NEXT ] = $slot->[ NEXT ]; 736 } 737 else { 738 $self->{ HEAD } = $slot->[ NEXT ]; 739 } 740 if ($slot->[ NEXT ]) { 741 $slot->[ NEXT ]->[ PREV ] = $slot->[ PREV ]; 742 } 743 else { 744 $self->{ TAIL } = $slot->[ PREV ]; 745 } 746 747 # ..and add to start of list 748 $head = $self->{ HEAD }; 749 $head->[ PREV ] = $slot if $head; 750 $slot->[ PREV ] = undef; 751 $slot->[ NEXT ] = $head; 752 $self->{ HEAD } = $slot; 753 } 754 755 return ($data, $error); 756} 757 758 759 760#------------------------------------------------------------------------ 761# _store($name, $data) 762# 763# Private method called to add a data item to the cache. If the cache 764# size limit has been reached then the oldest entry at the tail of the 765# list is removed and its slot relocated to the head of the list and 766# reused for the new data item. If the cache is under the size limit, 767# or if no size limit is defined, then the item is added to the head 768# of the list. 769# Returns compiled template 770#------------------------------------------------------------------------ 771 772sub _store { 773 my ($self, $name, $data, $compfile) = @_; 774 my $size = $self->{ SIZE }; 775 my ($slot, $head); 776 777 # Return if memory cache disabled. (overriding code should also check) 778 # $$$ What's the expected behaviour of store()? Can't tell from the 779 # docs if you can call store() when SIZE = 0. 780 return $data->{data} if defined $size and !$size; 781 782 # check the modification time -- extra stat here 783 my $load = $data->{ mtime } || $self->_modified($name); 784 785 # extract the compiled template from the data hash 786 $data = $data->{ data }; 787 $self->debug("_store($name, $data)") if $self->{ DEBUG }; 788 789 if (defined $size && $self->{ SLOTS } >= $size) { 790 # cache has reached size limit, so reuse oldest entry 791 $self->debug("reusing oldest cache entry (size limit reached: $size)\nslots: $self->{ SLOTS }") if $self->{ DEBUG }; 792 793 # remove entry from tail of list 794 $slot = $self->{ TAIL }; 795 $slot->[ PREV ]->[ NEXT ] = undef; 796 $self->{ TAIL } = $slot->[ PREV ]; 797 798 # remove name lookup for old node 799 delete $self->{ LOOKUP }->{ $slot->[ NAME ] }; 800 801 # add modified node to head of list 802 $head = $self->{ HEAD }; 803 $head->[ PREV ] = $slot if $head; 804 @$slot = ( undef, $name, $data, $load, $head, time ); 805 $self->{ HEAD } = $slot; 806 807 # add name lookup for new node 808 $self->{ LOOKUP }->{ $name } = $slot; 809 } 810 else { 811 # cache is under size limit, or none is defined 812 813 $self->debug("adding new cache entry") if $self->{ DEBUG }; 814 815 # add new node to head of list 816 $head = $self->{ HEAD }; 817 $slot = [ undef, $name, $data, $load, $head, time ]; 818 $head->[ PREV ] = $slot if $head; 819 $self->{ HEAD } = $slot; 820 $self->{ TAIL } = $slot unless $self->{ TAIL }; 821 822 # add lookup from name to slot and increment nslots 823 $self->{ LOOKUP }->{ $name } = $slot; 824 $self->{ SLOTS }++; 825 } 826 827 return $data; 828} 829 830 831#------------------------------------------------------------------------ 832# _compile($data) 833# 834# Private method called to parse the template text and compile it into 835# a runtime form. Creates and delegates a Template::Parser object to 836# handle the compilation, or uses a reference passed in PARSER. On 837# success, the compiled template is stored in the 'data' item of the 838# $data hash and returned. On error, ($error, STATUS_ERROR) is returned, 839# or (undef, STATUS_DECLINED) if the TOLERANT flag is set. 840# The optional $compiled parameter may be passed to specify 841# the name of a compiled template file to which the generated Perl 842# code should be written. Errors are (for now...) silently 843# ignored, assuming that failures to open a file for writing are 844# intentional (e.g directory write permission). 845#------------------------------------------------------------------------ 846 847sub _compile { 848 my ($self, $data, $compfile) = @_; 849 my $text = $data->{ text }; 850 my ($parsedoc, $error); 851 852 $self->debug("_compile($data, ", 853 defined $compfile ? $compfile : '<no compfile>', ')') 854 if $self->{ DEBUG }; 855 856 my $parser = $self->{ PARSER } 857 ||= Template::Config->parser($self->{ PARAMS }) 858 || return (Template::Config->error(), Template::Constants::STATUS_ERROR); 859 860 # discard the template text - we don't need it any more 861 delete $data->{ text }; 862 863 # call parser to compile template into Perl code 864 if ($parsedoc = $parser->parse($text, $data)) { 865 866 $parsedoc->{ METADATA } = { 867 'name' => $data->{ name }, 868 'modtime' => $data->{ 'time' }, 869 %{ $parsedoc->{ METADATA } }, 870 }; 871 872 # write the Perl code to the file $compfile, if defined 873 if ($compfile) { 874 my $basedir = &File::Basename::dirname($compfile); 875 { 876 no warnings 'syntax'; 877 $basedir = each %{ { $basedir => undef } } if ${^TAINT}; #untaint 878 } 879 880 unless (-d $basedir) { 881 eval { File::Path::mkpath($basedir) }; 882 $error = "failed to create compiled templates directory: $basedir ($@)" 883 if ($@); 884 } 885 886 unless ($error) { 887 my $docclass = $self->{ DOCUMENT }; 888 $error = 'cache failed to write ' 889 . &File::Basename::basename($compfile) 890 . ': ' . $docclass->error() 891 unless $docclass->write_perl_file($compfile, $parsedoc); 892 } 893 894 # set atime and mtime of newly compiled file, don't bother 895 # if time is undef 896 if (!defined($error) && defined $data->{ 'time' }) { 897 my $cfile = do { 898 no warnings 'syntax'; 899 each %{ { $compfile => undef } }; 900 }; 901 if (!length $cfile) { 902 return("invalid filename: $compfile", 903 Template::Constants::STATUS_ERROR); 904 }; 905 906 my $ctime = $data->{ time }; 907 if (!length $ctime || $ctime =~ tr{0-9}{}c) { 908 return("invalid time: $ctime", 909 Template::Constants::STATUS_ERROR); 910 } 911 utime($ctime, $ctime, $cfile); 912 913 $self->debug(" cached compiled template to file [$compfile]") 914 if $self->{ DEBUG }; 915 } 916 } 917 918 unless ($error) { 919 return $data ## RETURN ## 920 if $data->{ data } = $DOCUMENT->new($parsedoc); 921 $error = $Template::Document::ERROR; 922 } 923 } 924 else { 925 $error = Template::Exception->new( 'parse', "$data->{ name } " . 926 $parser->error() ); 927 } 928 929 # return STATUS_ERROR, or STATUS_DECLINED if we're being tolerant 930 return $self->{ TOLERANT } 931 ? (undef, Template::Constants::STATUS_DECLINED) 932 : ($error, Template::Constants::STATUS_ERROR) 933} 934 935#------------------------------------------------------------------------ 936# _compiled_is_current( $template_name ) 937# 938# Returns true if $template_name and its compiled name 939# exist and they have the same mtime. 940#------------------------------------------------------------------------ 941 942sub _compiled_is_current { 943 my ( $self, $template_name, $uncompiled_template_mtime ) = @_; 944 945 my $compiled_name = $self->_compiled_filename($template_name); 946 return unless defined $compiled_name; 947 948 my $compiled_mtime = (stat($compiled_name))[9]; 949 return unless defined $compiled_mtime; 950 951 my $template_mtime = $uncompiled_template_mtime || $self->_template_modified( $template_name ) or return; 952 return unless defined $template_mtime; 953 954 # This was >= in the 2.15, but meant that downgrading 955 # a source template would not get picked up. 956 return $compiled_mtime == $template_mtime ? $template_mtime : 0; 957} 958 959 960#------------------------------------------------------------------------ 961# _template_modified($path) 962# 963# Returns the last modified time of the $path. 964# Returns undef if the path does not exist. 965# Override if templates are not on disk, for example 966#------------------------------------------------------------------------ 967 968sub _template_modified { 969 my $self = shift; 970 my $template = shift || return; 971 return (stat( $template ))[9]; 972} 973 974#------------------------------------------------------------------------ 975# _template_content($path) 976# 977# Fetches content pointed to by $path. 978# Returns the content in scalar context. 979# Returns ($data, $error, $mtime) in list context where 980# $data - content 981# $error - error string if there was an error, otherwise undef 982# $mtime - last modified time from calling stat() on the path 983#------------------------------------------------------------------------ 984 985sub _template_content { 986 my ($self, $path) = @_; 987 988 return (undef, "No path specified to fetch content from ") 989 unless $path; 990 991 my $data; 992 my $mod_date; 993 my $error; 994 995 local *FH; 996 if(-d $path) { 997 $error = "$path: not a file"; 998 } 999 elsif (open(FH, "<", $path)) { 1000 local $/; 1001 binmode(FH); 1002 $data = <FH>; 1003 $mod_date = (stat($path))[9]; 1004 close(FH); 1005 } 1006 else { 1007 $error = "$path: $!"; 1008 } 1009 1010 return wantarray 1011 ? ( $data, $error, $mod_date ) 1012 : $data; 1013} 1014 1015 1016#------------------------------------------------------------------------ 1017# _modified($name) 1018# _modified($name, $time) 1019# 1020# When called with a single argument, it returns the modification time 1021# of the named template. When called with a second argument it returns 1022# true if $name has been modified since $time. 1023#------------------------------------------------------------------------ 1024 1025sub _modified { 1026 my ($self, $name, $time) = @_; 1027 my $load = $self->_template_modified($name); 1028 return $time ? 1 : 0 unless defined $load; 1029 1030 return $time 1031 ? $load > $time 1032 : $load; 1033} 1034 1035#------------------------------------------------------------------------ 1036# _decode_unicode 1037# 1038# Decodes encoded unicode text that starts with a BOM and 1039# turns it into perl's internal representation 1040#------------------------------------------------------------------------ 1041 1042sub _decode_unicode { 1043 my $self = shift; 1044 my $string = shift; 1045 return undef unless defined $string; 1046 1047 use bytes; 1048 require Encode; 1049 1050 return $string if Encode::is_utf8( $string ); 1051 1052 # try all the BOMs in order looking for one (order is important 1053 # 32bit BOMs look like 16bit BOMs) 1054 1055 my $count = 0; 1056 1057 while ($count < @{ $boms }) { 1058 my $enc = $boms->[$count++]; 1059 my $bom = $boms->[$count++]; 1060 1061 # does the string start with the bom? 1062 if ($bom eq substr($string, 0, length($bom))) { 1063 # decode it and hand it back 1064 return Encode::decode($enc, substr($string, length($bom)), 1); 1065 } 1066 } 1067 1068 return $self->{ ENCODING } 1069 ? Encode::decode( $self->{ ENCODING }, $string ) 1070 : $string; 1071} 1072 1073 10741; 1075 1076__END__ 1077 1078=head1 NAME 1079 1080Template::Provider - Provider module for loading/compiling templates 1081 1082=head1 SYNOPSIS 1083 1084 $provider = Template::Provider->new(\%options); 1085 1086 ($template, $error) = $provider->fetch($name); 1087 1088=head1 DESCRIPTION 1089 1090The L<Template::Provider> is used to load, parse, compile and cache template 1091documents. This object may be sub-classed to provide more specific facilities 1092for loading, or otherwise providing access to templates. 1093 1094The L<Template::Context> objects maintain a list of L<Template::Provider> 1095objects which are polled in turn (via L<fetch()|Template::Context#fetch()>) to 1096return a requested template. Each may return a compiled template, raise an 1097error, or decline to serve the request, giving subsequent providers a chance 1098to do so. 1099 1100The L<Template::Provider> can also be subclassed to provide templates from 1101a different source, e.g. a database. See L<SUBCLASSING> below. 1102 1103This documentation needs work. 1104 1105=head1 PUBLIC METHODS 1106 1107=head2 new(\%options) 1108 1109Constructor method which instantiates and returns a new C<Template::Provider> 1110object. A reference to a hash array of configuration options may be passed. 1111 1112See L<CONFIGURATION OPTIONS> below for a summary of configuration options 1113and L<Template::Manual::Config> for full details. 1114 1115=head2 fetch($name) 1116 1117Returns a compiled template for the name specified. If the template cannot be 1118found then C<(undef, STATUS_DECLINED)> is returned. If an error occurs (e.g. 1119read error, parse error) then C<($error, STATUS_ERROR)> is returned, where 1120C<$error> is the error message generated. If the L<TOLERANT> option is set the 1121the method returns C<(undef, STATUS_DECLINED)> instead of returning an error. 1122 1123=head2 load($name) 1124 1125Loads a template without parsing or compiling it. This is used by the 1126the L<INSERT|Template::Manual::Directives#INSERT> directive. 1127 1128=head2 store($name, $template) 1129 1130Stores the compiled template, C<$template>, in the cache under the name, 1131C<$name>. Susbequent calls to C<fetch($name)> will return this template in 1132preference to any disk-based file. 1133 1134=head2 include_path(\@newpath) 1135 1136Accessor method for the C<INCLUDE_PATH> setting. If called with an 1137argument, this method will replace the existing C<INCLUDE_PATH> with 1138the new value. 1139 1140=head2 paths() 1141 1142This method generates a copy of the C<INCLUDE_PATH> list. Any elements in the 1143list which are dynamic generators (e.g. references to subroutines or objects 1144implementing a C<paths()> method) will be called and the list of directories 1145returned merged into the output list. 1146 1147It is possible to provide a generator which returns itself, thus sending 1148this method into an infinite loop. To detect and prevent this from happening, 1149the C<$MAX_DIRS> package variable, set to C<64> by default, limits the maximum 1150number of paths that can be added to, or generated for the output list. If 1151this number is exceeded then the method will immediately return an error 1152reporting as much. 1153 1154=head1 CONFIGURATION OPTIONS 1155 1156The following list summarises the configuration options that can be provided 1157to the C<Template::Provider> L<new()> constructor. Please consult 1158L<Template::Manual::Config> for further details and examples of each 1159configuration option in use. 1160 1161=head2 INCLUDE_PATH 1162 1163The L<INCLUDE_PATH|Template::Manual::Config#INCLUDE_PATH> option is used to 1164specify one or more directories in which template files are located. 1165 1166 # single path 1167 my $provider = Template::Provider->new({ 1168 INCLUDE_PATH => '/usr/local/templates', 1169 }); 1170 1171 # multiple paths 1172 my $provider = Template::Provider->new({ 1173 INCLUDE_PATH => [ '/usr/local/templates', 1174 '/tmp/my/templates' ], 1175 }); 1176 1177=head2 ABSOLUTE 1178 1179The L<ABSOLUTE|Template::Manual::Config#ABSOLUTE> flag is used to indicate if 1180templates specified with absolute filenames (e.g. 'C</foo/bar>') should be 1181processed. It is disabled by default and any attempt to load a template by 1182such a name will cause a 'C<file>' exception to be raised. 1183 1184 my $provider = Template::Provider->new({ 1185 ABSOLUTE => 1, 1186 }); 1187 1188=head2 RELATIVE 1189 1190The L<RELATIVE|Template::Manual::Config#RELATIVE> flag is used to indicate if 1191templates specified with filenames relative to the current directory (e.g. 1192C<./foo/bar> or C<../../some/where/else>) should be loaded. It is also disabled 1193by default, and will raise a C<file> error if such template names are 1194encountered. 1195 1196 my $provider = Template::Provider->new({ 1197 RELATIVE => 1, 1198 }); 1199 1200=head2 DEFAULT 1201 1202The L<DEFAULT|Template::Manual::Config#DEFAULT> option can be used to specify 1203a default template which should be used whenever a specified template can't be 1204found in the L<INCLUDE_PATH>. 1205 1206 my $provider = Template::Provider->new({ 1207 DEFAULT => 'notfound.html', 1208 }); 1209 1210If a non-existant template is requested through the L<Template> 1211L<process()|Template#process()> method, or by an C<INCLUDE>, C<PROCESS> or 1212C<WRAPPER> directive, then the C<DEFAULT> template will instead be processed, if 1213defined. Note that the C<DEFAULT> template is not used when templates are 1214specified with absolute or relative filenames, or as a reference to a input 1215file handle or text string. 1216 1217=head2 ENCODING 1218 1219The Template Toolkit will automatically decode Unicode templates that 1220have a Byte Order Marker (BOM) at the start of the file. This option 1221can be used to set the default encoding for templates that don't define 1222a BOM. 1223 1224 my $provider = Template::Provider->new({ 1225 ENCODING => 'utf8', 1226 }); 1227 1228See L<Encode> for further information. 1229 1230=head2 CACHE_SIZE 1231 1232The L<CACHE_SIZE|Template::Manual::Config#CACHE_SIZE> option can be used to 1233limit the number of compiled templates that the module should cache. By 1234default, the L<CACHE_SIZE|Template::Manual::Config#CACHE_SIZE> is undefined 1235and all compiled templates are cached. 1236 1237 my $provider = Template::Provider->new({ 1238 CACHE_SIZE => 64, # only cache 64 compiled templates 1239 }); 1240 1241 1242=head2 STAT_TTL 1243 1244The L<STAT_TTL|Template::Manual::Config#STAT_TTL> value can be set to control 1245how long the C<Template::Provider> will keep a template cached in memory 1246before checking to see if the source template has changed. 1247 1248 my $provider = Template::Provider->new({ 1249 STAT_TTL => 60, # one minute 1250 }); 1251 1252=head2 COMPILE_EXT 1253 1254The L<COMPILE_EXT|Template::Manual::Config#COMPILE_EXT> option can be 1255provided to specify a filename extension for compiled template files. 1256It is undefined by default and no attempt will be made to read or write 1257any compiled template files. 1258 1259 my $provider = Template::Provider->new({ 1260 COMPILE_EXT => '.ttc', 1261 }); 1262 1263=head2 COMPILE_DIR 1264 1265The L<COMPILE_DIR|Template::Manual::Config#COMPILE_DIR> option is used to 1266specify an alternate directory root under which compiled template files should 1267be saved. 1268 1269 my $provider = Template::Provider->new({ 1270 COMPILE_DIR => '/tmp/ttc', 1271 }); 1272 1273=head2 TOLERANT 1274 1275The L<TOLERANT|Template::Manual::Config#TOLERANT> flag can be set to indicate 1276that the C<Template::Provider> module should ignore any errors encountered while 1277loading a template and instead return C<STATUS_DECLINED>. 1278 1279=head2 PARSER 1280 1281The L<PARSER|Template::Manual::Config#PARSER> option can be used to define 1282a parser module other than the default of L<Template::Parser>. 1283 1284 my $provider = Template::Provider->new({ 1285 PARSER => MyOrg::Template::Parser->new({ ... }), 1286 }); 1287 1288=head2 DEBUG 1289 1290The L<DEBUG|Template::Manual::Config#DEBUG> option can be used to enable 1291debugging messages from the L<Template::Provider> module by setting it to include 1292the C<DEBUG_PROVIDER> value. 1293 1294 use Template::Constants qw( :debug ); 1295 1296 my $template = Template->new({ 1297 DEBUG => DEBUG_PROVIDER, 1298 }); 1299 1300=head1 SUBCLASSING 1301 1302The C<Template::Provider> module can be subclassed to provide templates from a 1303different source (e.g. a database). In most cases you'll just need to provide 1304custom implementations of the C<_template_modified()> and C<_template_content()> 1305methods. If your provider requires and custom initialisation then you'll also 1306need to implement a new C<_init()> method. 1307 1308Caching in memory and on disk will still be applied (if enabled) 1309when overriding these methods. 1310 1311=head2 _template_modified($path) 1312 1313Returns a timestamp of the C<$path> passed in by calling C<stat()>. 1314This can be overridden, for example, to return a last modified value from 1315a database. The value returned should be a timestamp value (as returned by C<time()>, 1316although a sequence number should work as well. 1317 1318=head2 _template_content($path) 1319 1320This method returns the content of the template for all C<INCLUDE>, C<PROCESS>, 1321and C<INSERT> directives. 1322 1323When called in scalar context, the method returns the content of the template 1324located at C<$path>, or C<undef> if C<$path> is not found. 1325 1326When called in list context it returns C<($content, $error, $mtime)>, 1327where C<$content> is the template content, C<$error> is an error string 1328(e.g. "C<$path: File not found>"), and C<$mtime> is the template modification 1329time. 1330 1331=head1 AUTHOR 1332 1333Andy Wardley E<lt>abw@wardley.orgE<gt> L<http://wardley.org/> 1334 1335=head1 COPYRIGHT 1336 1337Copyright (C) 1996-2007 Andy Wardley. All Rights Reserved. 1338 1339This module is free software; you can redistribute it and/or 1340modify it under the same terms as Perl itself. 1341 1342=head1 SEE ALSO 1343 1344L<Template>, L<Template::Parser>, L<Template::Context> 1345 1346=cut 1347 1348# Local Variables: 1349# mode: perl 1350# perl-indent-level: 4 1351# indent-tabs-mode: nil 1352# End: 1353# 1354# vim: expandtab shiftwidth=4: 1355