11use LightnCandy\LightnCandy;
15use UnexpectedValueException;
25 private const CACHE_VERSION =
'2.2.0';
26 private const CACHE_TTL = BagOStuff::TTL_WEEK;
53 $this->templateDir =
$templateDir ?: __DIR__ .
'/../../resources/templates';
59 $this->compileFlags = LightnCandy::FLAG_ERROR_EXCEPTION | LightnCandy::FLAG_MUSTACHELOOKUP;
68 $this->compileFlags |= LightnCandy::FLAG_RUNTIMEPARTIAL;
70 $this->compileFlags &= ~LightnCandy::FLAG_RUNTIMEPARTIAL;
84 if ( strcspn( $templateName,
":/\\\000&<>'\"%" ) !== strlen( $templateName ) ) {
85 throw new UnexpectedValueException(
"Malformed \$templateName: $templateName" );
88 return "{$this->templateDir}/{$templateName}.mustache";
103 if ( isset( $this->renderers[$templateKey] ) &&
104 is_callable( $this->renderers[$templateKey] )
106 return $this->renderers[$templateKey];
117 $key = $this->cache->makeKey(
118 'lightncandy-compiled',
124 $compiledTemplate = $this->cache->get( $key );
128 if ( $compiledTemplate ) {
131 if ( $filesHash !== $compiledTemplate[
'filesHash'] ) {
132 $compiledTemplate =
null;
138 if ( $compiledTemplate ) {
139 $integrityHash = hash_hmac(
'sha256', $compiledTemplate[
'phpCode'], $secretKey );
141 if ( $integrityHash !== $compiledTemplate[
'integrityHash'] ) {
142 $compiledTemplate =
null;
148 if ( !$compiledTemplate ) {
149 $compiledTemplate = $this->
compile( $templateName );
151 $compiledTemplate[
'integrityHash'] = hash_hmac(
153 $compiledTemplate[
'phpCode'],
157 $this->cache->set( $key, $compiledTemplate, self::CACHE_TTL );
162 $compiledTemplate = $this->
compile( $templateName );
166 $renderer = eval( $compiledTemplate[
'phpCode'] );
167 if ( !is_callable( $renderer ) ) {
168 throw new RuntimeException(
"Compiled template `{$templateName}` is not callable" );
170 $this->renderers[$templateKey] = $renderer;
208 if ( !file_exists( $filename ) ) {
209 throw new RuntimeException(
"Could not find template `{$templateName}` at {$filename}" );
212 $files = [ $filename ];
213 $contents = file_get_contents( $filename );
214 $compiled = LightnCandy::compile(
217 'flags' => $this->compileFlags,
218 'basedir' => $this->templateDir,
219 'fileext' =>
'.mustache',
220 'partialresolver' =>
function ( $cx, $partialName ) use ( $templateName, &$files ) {
221 $filename =
"{$this->templateDir}/{$partialName}.mustache";
222 if ( !file_exists( $filename ) ) {
223 throw new RuntimeException( sprintf(
224 'Could not compile template `%s`: Could not find partial `%s` at %s',
231 $fileContents = file_get_contents( $filename );
233 if ( $fileContents ===
false ) {
234 throw new RuntimeException( sprintf(
235 'Could not compile template `%s`: Could not find partial `%s` at %s',
242 $files[] = $filename;
244 return $fileContents;
252 throw new RuntimeException(
"Could not compile template `{$filename}`" );
255 $files = array_values( array_unique( $files ) );
258 'phpCode' => $compiled,
286 return $template( $args, $scopes );
Generate hash digests of file contents to help with cache invalidation.
static getFileContentsHash( $filePaths)
Get a hash of the combined contents of one or more files, either by retrieving a previously-computed ...
A class containing constants representing the names of configuration variables.
const SecretKey
Name constant for the SecretKey setting, for use with Config::get()