mirror of
https://github.com/processwire/processwire.git
synced 2025-08-18 12:31:17 +02:00
Add new $cache->renderFile() method that works like $files->render() but caches the output according to WireCache rules. Also updated $files->render() to support a 'cache' option, which provides the same result.
This commit is contained in:
@@ -404,7 +404,7 @@ class WireCache extends Wire {
|
|||||||
*
|
*
|
||||||
* @param string $name Name of cache, can be any string up to 255 chars
|
* @param string $name Name of cache, can be any string up to 255 chars
|
||||||
* @param string|array|PageArray $data Data that you want to cache. May be string, array of non-object values, or PageArray.
|
* @param string|array|PageArray $data Data that you want to cache. May be string, array of non-object values, or PageArray.
|
||||||
* @param int|Page $expire Lifetime of this cache, in seconds, OR one of the following:
|
* @param int|string|Page $expire Lifetime of this cache, in seconds, OR one of the following:
|
||||||
* - Specify one of the `WireCache::expire*` constants.
|
* - Specify one of the `WireCache::expire*` constants.
|
||||||
* - Specify the future date you want it to expire (as unix timestamp or any `strtotime()` compatible date format)
|
* - Specify the future date you want it to expire (as unix timestamp or any `strtotime()` compatible date format)
|
||||||
* - Provide a `Page` object to expire when any page using that template is saved.
|
* - Provide a `Page` object to expire when any page using that template is saved.
|
||||||
@@ -1070,6 +1070,155 @@ class WireCache extends Wire {
|
|||||||
return $all;
|
return $all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a file as a ProcessWire template file and cache the output
|
||||||
|
*
|
||||||
|
* This method is similar to the `$files->render()` method and actually delegates the file
|
||||||
|
* rendering to that method (when creating the cache). The important difference is that this
|
||||||
|
* method caches the output according to WireCache rules for the `$expire` argument, rather
|
||||||
|
* than re-rendering the file on every call.
|
||||||
|
*
|
||||||
|
* If there are any changes to the source file `$filename` the cache will be automatically
|
||||||
|
* re-created, regardless of what is specified for the `$expire` argument.
|
||||||
|
*
|
||||||
|
* ~~~~~~
|
||||||
|
* // render primary nav from site/templates/partials/primary-nav.php
|
||||||
|
* // and cache for 3600 seconds (1 hour)
|
||||||
|
* echo $cache->renderFile('partials/primary-nav.php', 3600);
|
||||||
|
* ~~~~~~
|
||||||
|
*
|
||||||
|
* @param string $filename Filename to render (typically PHP file).
|
||||||
|
* Can be full path/file, or dir/file relative to current work directory (which is typically /site/templates/).
|
||||||
|
* If providing a file relative to current dir, it should not start with "/".
|
||||||
|
* File must be somewhere within site/templates/, site/modules/ or wire/modules/, or provide your own `allowedPaths` option.
|
||||||
|
* Please note that $filename receives API variables already (you don’t have to provide them).
|
||||||
|
* @param int|Page|string|null $expire Lifetime of this cache, in seconds, OR one of the following:
|
||||||
|
* - Specify one of the `WireCache::expire*` constants.
|
||||||
|
* - Specify the future date you want it to expire (as unix timestamp or any `strtotime()` compatible date format)
|
||||||
|
* - Provide a `Page` object to expire when any page using that template is saved.
|
||||||
|
* - Specify `WireCache::expireNever` to prevent expiration.
|
||||||
|
* - Specify `WireCache::expireSave` to expire when any page or template is saved.
|
||||||
|
* - Specify selector string matching pages that–when saved–expire the cache.
|
||||||
|
* - Omit for default value, which is `WireCache::expireDaily`.
|
||||||
|
* @param array $options Accepts all options for the `WireFileTools::render()` method, plus these additional ones:
|
||||||
|
* - `name` (string): Optionally specify a unique name for this cache, otherwise $filename will be used as the unique name. (default='')
|
||||||
|
* - `vars` (array): Optional associative array of extra variables to send to template file. (default=[])
|
||||||
|
* - `allowedPaths` (array): Array of paths that are allowed (default is anywhere within templates, core modules and site modules)
|
||||||
|
* - `throwExceptions` (bool): Throw exceptions when fatal error occurs? (default=true)
|
||||||
|
* @return string|bool Rendered template file or boolean false on fatal error (and throwExceptions disabled)
|
||||||
|
* @throws WireException if given file doesn’t exist
|
||||||
|
* @see WireFileTools::render()
|
||||||
|
* @since 3.0.130
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function renderFile($filename, $expire = null, array $options = array()) {
|
||||||
|
|
||||||
|
$defaults = array(
|
||||||
|
'name' => '',
|
||||||
|
'vars' => array(),
|
||||||
|
'throwExceptions' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
$out = null;
|
||||||
|
$paths = $this->wire('config')->paths;
|
||||||
|
$files = $this->wire('files');
|
||||||
|
$filename = $files->unixFileName($filename);
|
||||||
|
|
||||||
|
if(strpos($filename, '/') !== 0 && strpos($filename, ':') === false && strpos($filename, '//') === false) {
|
||||||
|
// make relative to current path
|
||||||
|
$currentPath = $files->currentPath();
|
||||||
|
if($files->fileInPath($filename, $currentPath)) {
|
||||||
|
$f = $currentPath . $filename;
|
||||||
|
if(file_exists($f)) $filename = $f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$options = array_merge($defaults, $options);
|
||||||
|
$mtime = filemtime($filename);
|
||||||
|
$name = str_replace($paths->root, '', $filename);
|
||||||
|
$ns = 'cache.' . ($options['name'] ? $options['name'] : 'renderFile');
|
||||||
|
$cacheName = $this->cacheName($name, $ns);
|
||||||
|
|
||||||
|
if($mtime === false) {
|
||||||
|
if($options['throwExceptions']) throw new WireException("File not found: $filename");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->get($cacheName, $expire);
|
||||||
|
|
||||||
|
// cache value is array where [ 0=created, 1='value' ]
|
||||||
|
if(!is_array($data) || $data[0] < $mtime) {
|
||||||
|
// cache does not exist or is older source file mtime
|
||||||
|
$out = $this->wire('files')->render($filename, $options['vars'], $options);
|
||||||
|
if($out === false) return false;
|
||||||
|
$data = array(time(), $out);
|
||||||
|
if($expire === null) $expire = self::expireDaily;
|
||||||
|
$this->save($cacheName, $data, $expire);
|
||||||
|
} else {
|
||||||
|
$out = $data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure a cache name is of the right length and format for a cache name
|
||||||
|
*
|
||||||
|
* @param string $name Name including namespace (if applicable)
|
||||||
|
* @param bool|string $ns True to allow namespace present, false to prevent, or specify namespace to add to name if not already present.
|
||||||
|
* @return string
|
||||||
|
* @since 3.0.130
|
||||||
|
* @todo update other methods in this class to use this method
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function cacheName($name, $ns = true) {
|
||||||
|
|
||||||
|
$maxLength = 190;
|
||||||
|
$name = trim($name);
|
||||||
|
|
||||||
|
if($ns === false) {
|
||||||
|
// namespace not allowed (cache name is NAME only)
|
||||||
|
while(strpos($name, '__') !== false) $name = str_replace('__', '_', $name);
|
||||||
|
if(strlen($name) > $maxLength) $name = md5($name);
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_string($ns) && strlen($ns)) {
|
||||||
|
// a namespace has been supplied
|
||||||
|
while(strpos($name, '__') !== false) $name = str_replace('__', '_', $name);
|
||||||
|
while(strpos($ns, '__') !== false) $ns = str_replace('__', '_', $ns);
|
||||||
|
$ns = rtrim($ns, '_') . '__';
|
||||||
|
if(strpos($name, $ns) === 0) {
|
||||||
|
// name already has this namespace
|
||||||
|
} else {
|
||||||
|
// prepend namespace to name
|
||||||
|
$name = $ns . $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen($name) <= $maxLength) {
|
||||||
|
// name already in bounds
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point we have a cache name that is too long
|
||||||
|
if(strpos($name, '__') !== false) {
|
||||||
|
// has namespace
|
||||||
|
list($ns, $name) = explode('__', $name, 2);
|
||||||
|
while(strpos($name, '__') !== false) $name = str_replace('__', '_', $name);
|
||||||
|
if(strlen($name) > 32) $name = md5($name);
|
||||||
|
if(strlen($ns . '__' . $name) > $maxLength) $ns = md5($ns); // not likely
|
||||||
|
$name = $ns . '__' . $name;
|
||||||
|
} else {
|
||||||
|
// no namespace
|
||||||
|
$name = md5($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the given string look like it might be JSON?
|
* Does the given string look like it might be JSON?
|
||||||
*
|
*
|
||||||
|
@@ -861,6 +861,8 @@ class WireFileTools extends Wire {
|
|||||||
* - `allowedPaths` (array): Array of paths that are allowed (default is templates, core modules and site modules)
|
* - `allowedPaths` (array): Array of paths that are allowed (default is templates, core modules and site modules)
|
||||||
* - `allowDotDot` (bool): Allow use of ".." in paths? (default=false)
|
* - `allowDotDot` (bool): Allow use of ".." in paths? (default=false)
|
||||||
* - `throwExceptions` (bool): Throw exceptions when fatal error occurs? (default=true)
|
* - `throwExceptions` (bool): Throw exceptions when fatal error occurs? (default=true)
|
||||||
|
* - `cache` (int|string|Page): Specify non-zero value to cache rendered result for this many seconds, or see the `WireCache::renderFile()`
|
||||||
|
* method `$expire` argument for more options you can specify here. (default=0, no cache) *Note: this option added in 3.0.130*
|
||||||
* @return string|bool Rendered template file or boolean false on fatal error (and throwExceptions disabled)
|
* @return string|bool Rendered template file or boolean false on fatal error (and throwExceptions disabled)
|
||||||
* @throws WireException if template file doesn't exist
|
* @throws WireException if template file doesn't exist
|
||||||
* @see WireFileTools::include()
|
* @see WireFileTools::include()
|
||||||
@@ -881,6 +883,7 @@ class WireFileTools extends Wire {
|
|||||||
),
|
),
|
||||||
'allowDotDot' => false,
|
'allowDotDot' => false,
|
||||||
'throwExceptions' => true,
|
'throwExceptions' => true,
|
||||||
|
'cache' => 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
$options = array_merge($defaults, $options);
|
$options = array_merge($defaults, $options);
|
||||||
@@ -923,6 +926,15 @@ class WireFileTools extends Wire {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($options['cache']) {
|
||||||
|
/** @var WireCache $cache */
|
||||||
|
$cache = $this->wire('cache');
|
||||||
|
$o = $options;
|
||||||
|
unset($o['cache']);
|
||||||
|
$o['vars'] = $vars;
|
||||||
|
return $cache->renderFile($filename, $options['cache'], $o);
|
||||||
|
}
|
||||||
|
|
||||||
// render file and return output
|
// render file and return output
|
||||||
$t = new TemplateFile();
|
$t = new TemplateFile();
|
||||||
@@ -1317,4 +1329,19 @@ class WireFileTools extends Wire {
|
|||||||
return strpos($file, $path) === 0;
|
return strpos($file, $path) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current path / work directory
|
||||||
|
*
|
||||||
|
* This is like PHP’s getcwd() function except that is in ProcessWire format as unix path with trailing slash.
|
||||||
|
*
|
||||||
|
* #pw-group-filenames
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* @since 3.0.130
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function currentPath() {
|
||||||
|
return $this->unixDirName(getcwd());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user