Merge pull request #2689 from splitbrain/refactorCachePSR2

Refactor cache.php to better conform with PSR 2
This commit is contained in:
Andreas Gohr 2019-02-27 19:32:55 +01:00 committed by GitHub
commit d8b492882d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 764 additions and 371 deletions

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Cache\CacheRenderer;
class cache_stalecheck_test extends DokuWikiTest {
function test_staleness() {
global $ID;
@ -11,7 +13,7 @@ class cache_stalecheck_test extends DokuWikiTest {
saveWikiText($ID, 'Fresh', 'Created');
# Create stale cache
$cache = new cache_renderer($ID, $file, 'xhtml');
$cache = new CacheRenderer($ID, $file, 'xhtml');
$cache->storeCache('Stale');
$stale = $cache->retrieveCache();

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Cache\CacheRenderer;
/**
* Class cache_use_test
*
@ -8,7 +10,7 @@
* @todo tests marked as flaky until Ticket #694 has been fixed
*/
class cache_use_test extends DokuWikiTest {
/** @var cache_renderer $cache */
/** @var CacheRenderer $cache */
private $cache;
function setUp() {
@ -21,7 +23,7 @@ class cache_use_test extends DokuWikiTest {
saveWikiText($ID, 'Content', 'Created');
$this->cache = new cache_renderer($ID, $file, 'xhtml');
$this->cache = new CacheRenderer($ID, $file, 'xhtml');
$this->cache->storeCache('Test');
// set the modification times explicitly (overcome Issue #694)
@ -76,6 +78,6 @@ class cache_use_test extends DokuWikiTest {
$conf['cachetime'] = -1; // disables renderer caching
$this->assertFalse($this->cache->useCache());
$this->assertNotEmpty($this->cache->_nocache);
$this->assertNotEmpty($this->cache->isNoCache());
}
}

View File

@ -9,6 +9,7 @@
* @global Input $INPUT
*/
use dokuwiki\Cache\Cache;
use dokuwiki\ChangeLog\MediaChangeLog;
use dokuwiki\ChangeLog\PageChangeLog;
@ -31,7 +32,7 @@ $opt = rss_parseOptions();
// the feed is dynamic - we need a cache for each combo
// (but most people just use the default feed so it's still effective)
$key = join('', array_values($opt)).'$'.$_SERVER['REMOTE_USER'].'$'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
$cache = new cache($key, '.feed');
$cache = new Cache($key, '.feed');
// prepare cache depends
$depends['files'] = getConfigFiles('main');
@ -45,7 +46,7 @@ header('Pragma: public');
header('Content-Type: application/xml; charset=utf-8');
header('X-Robots-Tag: noindex');
if($cache->useCache($depends)) {
http_conditionalRequest($cache->_time);
http_conditionalRequest($cache->getTime());
if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
print $cache->retrieveCache();
exit;

234
inc/Cache/Cache.php Normal file
View File

@ -0,0 +1,234 @@
<?php
namespace dokuwiki\Cache;
use \dokuwiki\Debug\PropertyDeprecationHelper;
/**
* Generic handling of caching
*/
class Cache
{
use PropertyDeprecationHelper;
public $key = ''; // primary identifier for this item
public $ext = ''; // file ext for cache data, secondary identifier for this item
public $cache = ''; // cache file name
public $depends = array(); // array containing cache dependency information,
// used by makeDefaultCacheDecision to determine cache validity
// phpcs:disable
/**
* @deprecated since 2019-02-02 use the respective getters instead!
*/
protected $_event = ''; // event to be triggered during useCache
protected $_time;
protected $_nocache = false; // if set to true, cache will not be used or stored
// phpcs:enable
/**
* @param string $key primary identifier
* @param string $ext file extension
*/
public function __construct($key, $ext)
{
$this->key = $key;
$this->ext = $ext;
$this->cache = getCacheName($key, $ext);
/**
* @deprecated since 2019-02-02 use the respective getters instead!
*/
$this->deprecatePublicProperty('_event');
$this->deprecatePublicProperty('_time');
$this->deprecatePublicProperty('_nocache');
}
public function getTime()
{
return $this->_time;
}
public function getEvent()
{
return $this->_event;
}
public function setEvent($_event)
{
$this->_event = $_event;
}
/**
* public method to determine whether the cache can be used
*
* to assist in centralisation of event triggering and calculation of cache statistics,
* don't override this function override makeDefaultCacheDecision()
*
* @param array $depends array of cache dependencies, support dependecies:
* 'age' => max age of the cache in seconds
* 'files' => cache must be younger than mtime of each file
* (nb. dependency passes if file doesn't exist)
*
* @return bool true if cache can be used, false otherwise
*/
public function useCache($depends = array())
{
$this->depends = $depends;
$this->addDependencies();
if ($this->_event) {
return $this->stats(trigger_event($this->_event, $this, array($this, 'makeDefaultCacheDecision')));
} else {
return $this->stats($this->makeDefaultCacheDecision());
}
}
/**
* internal method containing cache use decision logic
*
* this function processes the following keys in the depends array
* purge - force a purge on any non empty value
* age - expire cache if older than age (seconds)
* files - expire cache if any file in this array was updated more recently than the cache
*
* Note that this function needs to be public as it is used as callback for the event handler
*
* can be overridden
*
* @internal This method may only be called by the event handler! Call \dokuwiki\Cache\Cache::useCache instead!
*
* @return bool see useCache()
*/
public function makeDefaultCacheDecision()
{
if ($this->_nocache) {
return false;
} // caching turned off
if (!empty($this->depends['purge'])) {
return false;
} // purge requested?
if (!($this->_time = @filemtime($this->cache))) {
return false;
} // cache exists?
// cache too old?
if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) {
return false;
}
if (!empty($this->depends['files'])) {
foreach ($this->depends['files'] as $file) {
if ($this->_time <= @filemtime($file)) {
return false;
} // cache older than files it depends on?
}
}
return true;
}
/**
* add dependencies to the depends array
*
* this method should only add dependencies,
* it should not remove any existing dependencies and
* it should only overwrite a dependency when the new value is more stringent than the old
*/
protected function addDependencies()
{
global $INPUT;
if ($INPUT->has('purge')) {
$this->depends['purge'] = true;
} // purge requested
}
/**
* retrieve the cached data
*
* @param bool $clean true to clean line endings, false to leave line endings alone
* @return string cache contents
*/
public function retrieveCache($clean = true)
{
return io_readFile($this->cache, $clean);
}
/**
* cache $data
*
* @param string $data the data to be cached
* @return bool true on success, false otherwise
*/
public function storeCache($data)
{
if ($this->_nocache) {
return false;
}
return io_savefile($this->cache, $data);
}
/**
* remove any cached data associated with this cache instance
*/
public function removeCache()
{
@unlink($this->cache);
}
/**
* Record cache hits statistics.
* (Only when debugging allowed, to reduce overhead.)
*
* @param bool $success result of this cache use attempt
* @return bool pass-thru $success value
*/
protected function stats($success)
{
global $conf;
static $stats = null;
static $file;
if (!$conf['allowdebug']) {
return $success;
}
if (is_null($stats)) {
$file = $conf['cachedir'] . '/cache_stats.txt';
$lines = explode("\n", io_readFile($file));
foreach ($lines as $line) {
$i = strpos($line, ',');
$stats[substr($line, 0, $i)] = $line;
}
}
if (isset($stats[$this->ext])) {
list($ext, $count, $hits) = explode(',', $stats[$this->ext]);
} else {
$ext = $this->ext;
$count = 0;
$hits = 0;
}
$count++;
if ($success) {
$hits++;
}
$stats[$this->ext] = "$ext,$count,$hits";
io_saveFile($file, join("\n", $stats));
return $success;
}
/**
* @return bool
*/
public function isNoCache()
{
return $this->_nocache;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace dokuwiki\Cache;
/**
* Caching of parser instructions
*/
class CacheInstructions extends \dokuwiki\Cache\CacheParser
{
/**
* @param string $id page id
* @param string $file source file for cache
*/
public function __construct($id, $file)
{
parent::__construct($id, $file, 'i');
}
/**
* retrieve the cached data
*
* @param bool $clean true to clean line endings, false to leave line endings alone
* @return array cache contents
*/
public function retrieveCache($clean = true)
{
$contents = io_readFile($this->cache, false);
return !empty($contents) ? unserialize($contents) : array();
}
/**
* cache $instructions
*
* @param array $instructions the instruction to be cached
* @return bool true on success, false otherwise
*/
public function storeCache($instructions)
{
if ($this->_nocache) {
return false;
}
return io_savefile($this->cache, serialize($instructions));
}
}

64
inc/Cache/CacheParser.php Normal file
View File

@ -0,0 +1,64 @@
<?php
namespace dokuwiki\Cache;
/**
* Parser caching
*/
class CacheParser extends Cache
{
public $file = ''; // source file for cache
public $mode = ''; // input mode (represents the processing the input file will undergo)
public $page = '';
/**
*
* @param string $id page id
* @param string $file source file for cache
* @param string $mode input mode
*/
public function __construct($id, $file, $mode)
{
if ($id) {
$this->page = $id;
}
$this->file = $file;
$this->mode = $mode;
$this->_event = 'PARSER_CACHE_USE';
parent::__construct($file . $_SERVER['HTTP_HOST'] . $_SERVER['SERVER_PORT'], '.' . $mode);
}
/**
* method contains cache use decision logic
*
* @return bool see useCache()
*/
public function makeDefaultCacheDecision()
{
if (!file_exists($this->file)) {
return false;
} // source exists?
return parent::makeDefaultCacheDecision();
}
protected function addDependencies()
{
// parser cache file dependencies ...
$files = array(
$this->file, // ... source
DOKU_INC . 'inc/parser/Parser.php', // ... parser
DOKU_INC . 'inc/parser/handler.php', // ... handler
);
$files = array_merge($files, getConfigFiles('main')); // ... wiki settings
$this->depends['files'] = !empty($this->depends['files']) ?
array_merge($files, $this->depends['files']) :
$files;
parent::addDependencies();
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace dokuwiki\Cache;
/**
* Caching of data of renderer
*/
class CacheRenderer extends CacheParser
{
/**
* method contains cache use decision logic
*
* @return bool see useCache()
*/
public function makeDefaultCacheDecision()
{
global $conf;
if (!parent::makeDefaultCacheDecision()) {
return false;
}
if (!isset($this->page)) {
return true;
}
// meta cache older than file it depends on?
if ($this->_time < @filemtime(metaFN($this->page, '.meta'))) {
return false;
}
// check current link existence is consistent with cache version
// first check the purgefile
// - if the cache is more recent than the purgefile we know no links can have been updated
if ($this->_time >= @filemtime($conf['cachedir'] . '/purgefile')) {
return true;
}
// for wiki pages, check metadata dependencies
$metadata = p_get_metadata($this->page);
if (!isset($metadata['relation']['references']) ||
empty($metadata['relation']['references'])) {
return true;
}
foreach ($metadata['relation']['references'] as $id => $exists) {
if ($exists != page_exists($id, '', false)) {
return false;
}
}
return true;
}
protected function addDependencies()
{
global $conf;
// default renderer cache file 'age' is dependent on 'cachetime' setting, two special values:
// -1 : do not cache (should not be overridden)
// 0 : cache never expires (can be overridden) - no need to set depends['age']
if ($conf['cachetime'] == -1) {
$this->_nocache = true;
return;
} elseif ($conf['cachetime'] > 0) {
$this->depends['age'] = isset($this->depends['age']) ?
min($this->depends['age'], $conf['cachetime']) : $conf['cachetime'];
}
// renderer cache file dependencies ...
$files = array(
DOKU_INC . 'inc/parser/' . $this->mode . '.php', // ... the renderer
);
// page implies metadata and possibly some other dependencies
if (isset($this->page)) {
// for xhtml this will render the metadata if needed
$valid = p_get_metadata($this->page, 'date valid');
if (!empty($valid['age'])) {
$this->depends['age'] = isset($this->depends['age']) ?
min($this->depends['age'], $valid['age']) : $valid['age'];
}
}
$this->depends['files'] = !empty($this->depends['files']) ?
array_merge($files, $this->depends['files']) :
$files;
parent::addDependencies();
}
}

116
inc/Debug/DebugHelper.php Normal file
View File

@ -0,0 +1,116 @@
<?php
namespace dokuwiki\Debug;
use Doku_Event;
class DebugHelper
{
const INFO_DEPRECATION_LOG_EVENT = 'INFO_DEPRECATION_LOG';
/**
* Log accesses to deprecated fucntions to the debug log
*
* @param string $alternative (optional) The function or method that should be used instead
* @param int $callerOffset (optional) How far the deprecated method is removed from this one
*
* @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
*/
public static function dbgDeprecatedFunction($alternative = '', $callerOffset = 1)
{
global $conf;
global $EVENT_HANDLER;
if (!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent(self::INFO_DEPRECATION_LOG_EVENT)) {
// avoid any work if no one cares
return;
}
$backtrace = debug_backtrace();
for ($i = 0; $i < $callerOffset; $i += 1) {
array_shift($backtrace);
}
list($self, $call) = $backtrace;
self::triggerDeprecationEvent(
$backtrace,
$alternative,
trim($self['class'] . '::' . $self['function'] . '()', ':'),
trim($call['class'] . '::' . $call['function'] . '()', ':'),
$call['file'],
$call['line']
);
}
/**
* This marks logs a deprecation warning for a property that should no longer be used
*
* This is usually called withing a magic getter or setter.
* For logging deprecated functions or methods see dbgDeprecatedFunction()
*
* @param string $class The class with the deprecated property
* @param string $propertyName The name of the deprecated property
*
* @triggers \dokuwiki\Debug::INFO_DEPRECATION_LOG_EVENT
*/
public static function dbgDeprecatedProperty($class, $propertyName)
{
global $conf;
global $EVENT_HANDLER;
if (!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent(self::INFO_DEPRECATION_LOG_EVENT)) {
// avoid any work if no one cares
return;
}
$backtrace = debug_backtrace();
array_shift($backtrace);
$call = $backtrace[1];
$caller = trim($call['class'] . '::' . $call['function'] . '()', ':');
$qualifiedName = $class . '::$' . $propertyName;
self::triggerDeprecationEvent(
$backtrace,
'',
$qualifiedName,
$caller,
$backtrace[0]['file'],
$backtrace[0]['line']
);
}
/**
* @param array $backtrace
* @param string $alternative
* @param string $deprecatedThing
* @param string $caller
* @param string $file
* @param int $line
*/
private static function triggerDeprecationEvent(
array $backtrace,
$alternative,
$deprecatedThing,
$caller,
$file,
$line
) {
$data = [
'trace' => $backtrace,
'alternative' => $alternative,
'called' => $deprecatedThing,
'caller' => $caller,
'file' => $file,
'line' => $line,
];
$event = new Doku_Event(self::INFO_DEPRECATION_LOG_EVENT, $data);
if ($event->advise_before()) {
$msg = $event->data['called'] . ' is deprecated. It was called from ';
$msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
if ($event->data['alternative']) {
$msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
}
dbglog($msg);
}
$event->advise_after();
}
}

View File

@ -0,0 +1,134 @@
<?php
/**
* Trait for issuing warnings on deprecated access.
*
* Adapted from https://github.com/wikimedia/mediawiki/blob/4aedefdbfd193f323097354bf581de1c93f02715/includes/debug/DeprecationHelper.php
*
*/
namespace dokuwiki\Debug;
/**
* Use this trait in classes which have properties for which public access
* is deprecated. Set the list of properties in $deprecatedPublicProperties
* and make the properties non-public. The trait will preserve public access
* but issue deprecation warnings when it is needed.
*
* Example usage:
* class Foo {
* use DeprecationHelper;
* protected $bar;
* public function __construct() {
* $this->deprecatePublicProperty( 'bar', '1.21', __CLASS__ );
* }
* }
*
* $foo = new Foo;
* $foo->bar; // works but logs a warning
*
* Cannot be used with classes that have their own __get/__set methods.
*
*/
trait PropertyDeprecationHelper
{
/**
* List of deprecated properties, in <property name> => <class> format
* where <class> is the the name of the class defining the property
*
* E.g. [ '_event' => '\dokuwiki\Cache\Cache' ]
* @var string[]
*/
protected $deprecatedPublicProperties = [];
/**
* Mark a property as deprecated. Only use this for properties that used to be public and only
* call it in the constructor.
*
* @param string $property The name of the property.
* @param null $class name of the class defining the property
* @see DebugHelper::dbgDeprecatedProperty
*/
protected function deprecatePublicProperty(
$property,
$class = null
) {
$this->deprecatedPublicProperties[$property] = $class ?: get_class();
}
public function __get($name)
{
if (isset($this->deprecatedPublicProperties[$name])) {
$class = $this->deprecatedPublicProperties[$name];
DebugHelper::dbgDeprecatedProperty($class, $name);
return $this->$name;
}
$qualifiedName = get_class() . '::$' . $name;
if ($this->deprecationHelperGetPropertyOwner($name)) {
// Someone tried to access a normal non-public property. Try to behave like PHP would.
trigger_error("Cannot access non-public property $qualifiedName", E_USER_ERROR);
} else {
// Non-existing property. Try to behave like PHP would.
trigger_error("Undefined property: $qualifiedName", E_USER_NOTICE);
}
return null;
}
public function __set($name, $value)
{
if (isset($this->deprecatedPublicProperties[$name])) {
$class = $this->deprecatedPublicProperties[$name];
DebugHelper::dbgDeprecatedProperty($class, $name);
$this->$name = $value;
return;
}
$qualifiedName = get_class() . '::$' . $name;
if ($this->deprecationHelperGetPropertyOwner($name)) {
// Someone tried to access a normal non-public property. Try to behave like PHP would.
trigger_error("Cannot access non-public property $qualifiedName", E_USER_ERROR);
} else {
// Non-existing property. Try to behave like PHP would.
$this->$name = $value;
}
}
/**
* Like property_exists but also check for non-visible private properties and returns which
* class in the inheritance chain declared the property.
* @param string $property
* @return string|bool Best guess for the class in which the property is defined.
*/
private function deprecationHelperGetPropertyOwner($property)
{
// Easy branch: check for protected property / private property of the current class.
if (property_exists($this, $property)) {
// The class name is not necessarily correct here but getting the correct class
// name would be expensive, this will work most of the time and getting it
// wrong is not a big deal.
return __CLASS__;
}
// property_exists() returns false when the property does exist but is private (and not
// defined by the current class, for some value of "current" that differs slightly
// between engines).
// Since PHP triggers an error on public access of non-public properties but happily
// allows public access to undefined properties, we need to detect this case as well.
// Reflection is slow so use array cast hack to check for that:
$obfuscatedProps = array_keys((array)$this);
$obfuscatedPropTail = "\0$property";
foreach ($obfuscatedProps as $obfuscatedProp) {
// private props are in the form \0<classname>\0<propname>
if (strpos($obfuscatedProp, $obfuscatedPropTail, 1) !== false) {
$classname = substr($obfuscatedProp, 1, -strlen($obfuscatedPropTail));
if ($classname === '*') {
// sanity; this shouldn't be possible as protected properties were handled earlier
$classname = __CLASS__;
}
return $classname;
}
}
return false;
}
}

View File

@ -1,342 +1,59 @@
<?php
/**
* Generic class to handle caching
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Chris Smith <chris@jalakai.co.uk>
*/
// phpcs:ignoreFile
use dokuwiki\Cache\CacheParser;
use dokuwiki\Cache\CacheInstructions;
use dokuwiki\Cache\CacheRenderer;
use dokuwiki\Debug\DebugHelper;
/**
* Generic handling of caching
* @deprecated since 2019-02-02 use \dokuwiki\Cache\Cache instead!
*/
class cache {
public $key = ''; // primary identifier for this item
public $ext = ''; // file ext for cache data, secondary identifier for this item
public $cache = ''; // cache file name
public $depends = array(); // array containing cache dependency information,
// used by _useCache to determine cache validity
class cache extends \dokuwiki\Cache\Cache
{
public $_event = ''; // event to be triggered during useCache
public $_time;
public $_nocache = false; // if set to true, cache will not be used or stored
/**
* @param string $key primary identifier
* @param string $ext file extension
*/
public function __construct($key,$ext) {
$this->key = $key;
$this->ext = $ext;
$this->cache = getCacheName($key,$ext);
}
/**
* public method to determine whether the cache can be used
*
* to assist in centralisation of event triggering and calculation of cache statistics,
* don't override this function override _useCache()
*
* @param array $depends array of cache dependencies, support dependecies:
* 'age' => max age of the cache in seconds
* 'files' => cache must be younger than mtime of each file
* (nb. dependency passes if file doesn't exist)
*
* @return bool true if cache can be used, false otherwise
*/
public function useCache($depends=array()) {
$this->depends = $depends;
$this->_addDependencies();
if ($this->_event) {
return $this->_stats(trigger_event($this->_event, $this, array($this,'_useCache')));
} else {
return $this->_stats($this->_useCache());
}
}
/**
* private method containing cache use decision logic
*
* this function processes the following keys in the depends array
* purge - force a purge on any non empty value
* age - expire cache if older than age (seconds)
* files - expire cache if any file in this array was updated more recently than the cache
*
* Note that this function needs to be public as it is used as callback for the event handler
*
* can be overridden
*
* @return bool see useCache()
*/
public function _useCache() {
if ($this->_nocache) return false; // caching turned off
if (!empty($this->depends['purge'])) return false; // purge requested?
if (!($this->_time = @filemtime($this->cache))) return false; // cache exists?
// cache too old?
if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) return false;
if (!empty($this->depends['files'])) {
foreach ($this->depends['files'] as $file) {
if ($this->_time <= @filemtime($file)) return false; // cache older than files it depends on?
}
}
return true;
}
/**
* add dependencies to the depends array
*
* this method should only add dependencies,
* it should not remove any existing dependencies and
* it should only overwrite a dependency when the new value is more stringent than the old
*/
protected function _addDependencies() {
global $INPUT;
if ($INPUT->has('purge')) $this->depends['purge'] = true; // purge requested
}
/**
* retrieve the cached data
*
* @param bool $clean true to clean line endings, false to leave line endings alone
* @return string cache contents
*/
public function retrieveCache($clean=true) {
return io_readFile($this->cache, $clean);
}
/**
* cache $data
*
* @param string $data the data to be cached
* @return bool true on success, false otherwise
*/
public function storeCache($data) {
if ($this->_nocache) return false;
return io_savefile($this->cache, $data);
}
/**
* remove any cached data associated with this cache instance
*/
public function removeCache() {
@unlink($this->cache);
}
/**
* Record cache hits statistics.
* (Only when debugging allowed, to reduce overhead.)
*
* @param bool $success result of this cache use attempt
* @return bool pass-thru $success value
*/
protected function _stats($success) {
global $conf;
static $stats = null;
static $file;
if (!$conf['allowdebug']) { return $success; }
if (is_null($stats)) {
$file = $conf['cachedir'].'/cache_stats.txt';
$lines = explode("\n",io_readFile($file));
foreach ($lines as $line) {
$i = strpos($line,',');
$stats[substr($line,0,$i)] = $line;
}
}
if (isset($stats[$this->ext])) {
list($ext,$count,$hits) = explode(',',$stats[$this->ext]);
} else {
$ext = $this->ext;
$count = 0;
$hits = 0;
}
$count++;
if ($success) $hits++;
$stats[$this->ext] = "$ext,$count,$hits";
io_saveFile($file,join("\n",$stats));
return $success;
}
}
/**
* Parser caching
*/
class cache_parser extends cache {
public $file = ''; // source file for cache
public $mode = ''; // input mode (represents the processing the input file will undergo)
public $page = '';
public $_event = 'PARSER_CACHE_USE';
/**
*
* @param string $id page id
* @param string $file source file for cache
* @param string $mode input mode
*/
public function __construct($id, $file, $mode) {
if ($id) $this->page = $id;
$this->file = $file;
$this->mode = $mode;
parent::__construct($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.$mode);
}
/**
* method contains cache use decision logic
*
* @return bool see useCache()
*/
public function _useCache() {
if (!file_exists($this->file)) return false; // source exists?
return parent::_useCache();
}
protected function _addDependencies() {
// parser cache file dependencies ...
$files = array($this->file, // ... source
DOKU_INC.'inc/parser/Parser.php', // ... parser
DOKU_INC.'inc/parser/handler.php', // ... handler
);
$files = array_merge($files, getConfigFiles('main')); // ... wiki settings
$this->depends['files'] = !empty($this->depends['files']) ?
array_merge($files, $this->depends['files']) :
$files;
parent::_addDependencies();
public function __construct($key, $ext)
{
DebugHelper::dbgDeprecatedFunction(dokuwiki\Cache\Cache::class);
parent::__construct($key, $ext);
}
}
/**
* Caching of data of renderer
* @deprecated since 2019-02-02 use \dokuwiki\Cache\CacheParser instead!
*/
class cache_renderer extends cache_parser {
class cache_parser extends \dokuwiki\Cache\CacheParser
{
/**
* method contains cache use decision logic
*
* @return bool see useCache()
*/
public function _useCache() {
global $conf;
if (!parent::_useCache()) return false;
if (!isset($this->page)) {
return true;
}
// meta cache older than file it depends on?
if ($this->_time < @filemtime(metaFN($this->page,'.meta'))) return false;
// check current link existence is consistent with cache version
// first check the purgefile
// - if the cache is more recent than the purgefile we know no links can have been updated
if ($this->_time >= @filemtime($conf['cachedir'].'/purgefile')) {
return true;
}
// for wiki pages, check metadata dependencies
$metadata = p_get_metadata($this->page);
if (!isset($metadata['relation']['references']) ||
empty($metadata['relation']['references'])) {
return true;
}
foreach ($metadata['relation']['references'] as $id => $exists) {
if ($exists != page_exists($id,'',false)) return false;
}
return true;
public function __construct($id, $file, $mode)
{
DebugHelper::dbgDeprecatedFunction(CacheParser::class);
parent::__construct($id, $file, $mode);
}
protected function _addDependencies() {
global $conf;
}
// default renderer cache file 'age' is dependent on 'cachetime' setting, two special values:
// -1 : do not cache (should not be overridden)
// 0 : cache never expires (can be overridden) - no need to set depends['age']
if ($conf['cachetime'] == -1) {
$this->_nocache = true;
return;
} elseif ($conf['cachetime'] > 0) {
$this->depends['age'] = isset($this->depends['age']) ?
min($this->depends['age'],$conf['cachetime']) : $conf['cachetime'];
}
/**
* @deprecated since 2019-02-02 use \dokuwiki\Cache\CacheRenderer instead!
*/
class cache_renderer extends \dokuwiki\Cache\CacheRenderer
{
// renderer cache file dependencies ...
$files = array(
DOKU_INC.'inc/parser/'.$this->mode.'.php', // ... the renderer
);
// page implies metadata and possibly some other dependencies
if (isset($this->page)) {
// for xhtml this will render the metadata if needed
$valid = p_get_metadata($this->page, 'date valid');
if (!empty($valid['age'])) {
$this->depends['age'] = isset($this->depends['age']) ?
min($this->depends['age'],$valid['age']) : $valid['age'];
}
}
$this->depends['files'] = !empty($this->depends['files']) ?
array_merge($files, $this->depends['files']) :
$files;
parent::_addDependencies();
public function __construct($id, $file, $mode)
{
DebugHelper::dbgDeprecatedFunction(CacheRenderer::class);
parent::__construct($id, $file, $mode);
}
}
/**
* Caching of parser instructions
* @deprecated since 2019-02-02 use \dokuwiki\Cache\CacheInstructions instead!
*/
class cache_instructions extends cache_parser {
/**
* @param string $id page id
* @param string $file source file for cache
*/
public function __construct($id, $file) {
parent::__construct($id, $file, 'i');
}
/**
* retrieve the cached data
*
* @param bool $clean true to clean line endings, false to leave line endings alone
* @return array cache contents
*/
public function retrieveCache($clean=true) {
$contents = io_readFile($this->cache, false);
return !empty($contents) ? unserialize($contents) : array();
}
/**
* cache $instructions
*
* @param array $instructions the instruction to be cached
* @return bool true on success, false otherwise
*/
public function storeCache($instructions) {
if ($this->_nocache) return false;
return io_savefile($this->cache,serialize($instructions));
class cache_instructions extends \dokuwiki\Cache\CacheInstructions
{
public function __construct($id, $file)
{
DebugHelper::dbgDeprecatedFunction(CacheInstructions::class);
parent::__construct($id, $file);
}
}

View File

@ -6,6 +6,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
use dokuwiki\Cache\CacheInstructions;
use dokuwiki\Cache\CacheRenderer;
use dokuwiki\ChangeLog\PageChangeLog;
/**
@ -1293,7 +1295,7 @@ function detectExternalEdit($id) {
$sizechange
);
// remove soon to be stale instructions
$cache = new cache_instructions($id, $fileLastMod);
$cache = new CacheInstructions($id, $fileLastMod);
$cache->removeCache();
}
}
@ -1423,7 +1425,7 @@ function saveWikiText($id, $text, $summary, $minor = false) {
if(useHeading('content')) {
$pages = ft_backlinks($id, true);
foreach($pages as $page) {
$cache = new cache_renderer($page, wikiFN($page), 'xhtml');
$cache = new CacheRenderer($page, wikiFN($page), 'xhtml');
$cache->removeCache();
}
}

View File

@ -450,40 +450,11 @@ function dbglog($msg,$header=''){
* Log accesses to deprecated fucntions to the debug log
*
* @param string $alternative The function or method that should be used instead
* @param string|null $deprecatedThing What is deprecated if not the current method
* @triggers INFO_DEPRECATION_LOG
*/
function dbg_deprecated($alternative = '') {
global $conf;
global $EVENT_HANDLER;
if(!$conf['allowdebug'] && !$EVENT_HANDLER->hasHandlerForEvent('INFO_DEPRECATION_LOG')) {
// avoid any work if no one cares
return;
}
$backtrace = debug_backtrace();
array_shift($backtrace);
$self = $backtrace[0];
$call = $backtrace[1];
$data = [
'trace' => $backtrace,
'alternative' => $alternative,
'called' => trim($self['class'] . '::' . $self['function'] . '()', ':'),
'caller' => trim($call['class'] . '::' . $call['function'] . '()', ':'),
'file' => $call['file'],
'line' => $call['line'],
];
$event = new Doku_Event('INFO_DEPRECATION_LOG', $data);
if($event->advise_before()) {
$msg = $event->data['called'] . ' is deprecated. It was called from ';
$msg .= $event->data['caller'] . ' in ' . $event->data['file'] . ':' . $event->data['line'];
if($event->data['alternative']) {
$msg .= ' ' . $event->data['alternative'] . ' should be used instead!';
}
dbglog($msg);
}
$event->advise_after();
\dokuwiki\Debug\DebugHelper::dbgDeprecatedFunction($alternative, 2);
}
/**

View File

@ -7,6 +7,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
use dokuwiki\Cache\CacheInstructions;
use dokuwiki\Cache\CacheRenderer;
use dokuwiki\Parsing\Parser;
/**
@ -127,7 +129,7 @@ function p_locale_xhtml($id){
function p_cached_output($file, $format='xhtml', $id='') {
global $conf;
$cache = new cache_renderer($id, $file, $format);
$cache = new CacheRenderer($id, $file, $format);
if ($cache->useCache()) {
$parsed = $cache->retrieveCache(false);
if($conf['allowdebug'] && $format=='xhtml') {
@ -167,7 +169,7 @@ function p_cached_instructions($file,$cacheonly=false,$id='') {
static $run = null;
if(is_null($run)) $run = array();
$cache = new cache_instructions($id, $file);
$cache = new CacheInstructions($id, $file);
if ($cacheonly || $cache->useCache() || (isset($run[$file]) && !defined('DOKU_UNITTEST'))) {
return $cache->retrieveCache();
@ -254,7 +256,7 @@ function p_get_metadata($id, $key='', $render=METADATA_RENDER_USING_CACHE){
if (!$recursion && $render != METADATA_DONT_RENDER && !isset($rendered_pages[$id])&& page_exists($id)){
$recursion = true;
$cachefile = new cache_renderer($id, wikiFN($id), 'metadata');
$cachefile = new CacheRenderer($id, wikiFN($id), 'metadata');
$do_render = false;
if ($render & METADATA_RENDER_UNLIMITED || $render_count < P_GET_METADATA_RENDER_LIMIT) {

View File

@ -6,6 +6,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
use dokuwiki\Cache\Cache;
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
@ -100,7 +102,7 @@ function css_out(){
}
// The generated script depends on some dynamic options
$cache = new cache(
$cache = new Cache(
'styles' .
$_SERVER['HTTP_HOST'] .
$_SERVER['SERVER_PORT'] .
@ -110,7 +112,7 @@ function css_out(){
$type,
'.css'
);
$cache->_event = 'CSS_CACHE_USE';
$cache->setEvent('CSS_CACHE_USE');
// check cache age & handle conditional request
// This may exit if a cache can be used

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Cache\Cache;
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__) . '/../../');
if(!defined('NOSESSION')) define('NOSESSION', true); // we do not use a session or authentication here (better caching)
if(!defined('NL')) define('NL', "\n");
@ -19,7 +21,7 @@ jquery_out();
* uses cache or fills it
*/
function jquery_out() {
$cache = new cache('jquery', '.js');
$cache = new Cache('jquery', '.js');
$files = array(
DOKU_INC . 'lib/scripts/jquery/jquery.min.js',
DOKU_INC . 'lib/scripts/jquery/jquery-ui.min.js',

View File

@ -6,6 +6,8 @@
* @author Andreas Gohr <andi@splitbrain.org>
*/
use dokuwiki\Cache\Cache;
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session or authentication here (better caching)
if(!defined('NL')) define('NL',"\n");
@ -76,8 +78,8 @@ function js_out(){
trigger_event('JS_SCRIPT_LIST', $files);
// The generated script depends on some dynamic options
$cache = new cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].md5(serialize($files)),'.js');
$cache->_event = 'JS_CACHE_USE';
$cache = new Cache('scripts'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'].md5(serialize($files)),'.js');
$cache->setEvent('JS_CACHE_USE');
$cache_files = array_merge($files, getConfigFiles('main'));
$cache_files[] = __FILE__;

View File

@ -6,6 +6,8 @@
* @author Michael Hamann <michael@content-space.de>
*/
use dokuwiki\Cache\Cache;
/**
* Class helper_plugin_extension_repository provides access to the extension repository on dokuwiki.org
*/
@ -29,7 +31,7 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin
$request_data = array('fmt' => 'php');
$request_needed = false;
foreach ($list as $name) {
$cache = new cache('##extension_manager##'.$name, '.repo');
$cache = new Cache('##extension_manager##'.$name, '.repo');
if (!isset($this->loaded_extensions[$name]) &&
$this->hasAccess() &&
@ -47,7 +49,7 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin
if ($data !== false) {
$extensions = unserialize($data);
foreach ($extensions as $extension) {
$cache = new cache('##extension_manager##'.$extension['plugin'], '.repo');
$cache = new Cache('##extension_manager##'.$extension['plugin'], '.repo');
$cache->storeCache(serialize($extension));
}
} else {
@ -65,7 +67,7 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin
public function hasAccess()
{
if ($this->has_access === null) {
$cache = new cache('##extension_manager###hasAccess', '.repo');
$cache = new Cache('##extension_manager###hasAccess', '.repo');
if (!$cache->useCache(array('age' => 3600 * 24, 'purge'=>1))) {
$httpclient = new DokuHTTPClient();
@ -93,7 +95,7 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin
*/
public function getData($name)
{
$cache = new cache('##extension_manager##'.$name, '.repo');
$cache = new Cache('##extension_manager##'.$name, '.repo');
if (!isset($this->loaded_extensions[$name]) &&
$this->hasAccess() &&
@ -137,7 +139,7 @@ class helper_plugin_extension_repository extends DokuWiki_Plugin
// store cache info for each extension
foreach ($result as $ext) {
$name = $ext['plugin'];
$cache = new cache('##extension_manager##'.$name, '.repo');
$cache = new Cache('##extension_manager##'.$name, '.repo');
$cache->storeCache(serialize($ext));
$ids[] = $name;
}