Created
June 10, 2018 18:55
-
-
Save lgescobar/7addb3b2397cce827ab4bf51d1ee9d15 to your computer and use it in GitHub Desktop.
Simple LRU cache for TYPO3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
if (!defined('TYPO3_MODE')) { | |
die('Access denied.'); | |
} | |
/* ************************************************************* | |
* Copyright notice | |
* | |
* (c) 2018 Luis Antonio García Escobar <[email protected]> | |
* | |
* All rights reserved | |
* | |
* This script is part of the TYPO3 project. The TYPO3 project is | |
* free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* The GNU General Public License can be found at | |
* http://www.gnu.org/copyleft/gpl.html. | |
* | |
* This script is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* This copyright notice MUST APPEAR in all copies of the script! | |
***************************************************************/ | |
// Register cache | |
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname'])) { | |
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname'] = []; | |
} | |
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['backend'])) { | |
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['backend'] = | |
\Vendor\Product\Cache\Backend\TransientMemoryLRUBackend::class; | |
} | |
// Define string frontend as default frontend because only the token (of type string) will be stored in cache. | |
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['frontend'])) { | |
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['frontend'] = | |
\Vendor\Product\Cache\Frontend\RawFrontend::class; | |
} | |
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['options'])) { | |
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['options'] = | |
['maximumSize' => 10]; | |
} | |
if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['groups'])) { | |
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['extname']['groups'] = ['all']; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Vendor\Product\Cache\Frontend; | |
/* ************************************************************* | |
* Copyright notice | |
* | |
* (c) 2018 Luis Antonio García Escobar <[email protected]> | |
* | |
* All rights reserved | |
* | |
* This script is part of the TYPO3 project. The TYPO3 project is | |
* free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* The GNU General Public License can be found at | |
* http://www.gnu.org/copyleft/gpl.html. | |
* | |
* This script is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* This copyright notice MUST APPEAR in all copies of the script! | |
***************************************************************/ | |
use TYPO3\CMS\Core\Cache\Frontend\StringFrontend; | |
/** | |
* A cache frontend for the LRU cache. | |
*/ | |
class RawFrontend extends StringFrontend | |
{ | |
/** | |
* Saves the value of a PHP variable in the cache. | |
* | |
* @param string|int|float $entryIdentifier An identifier used for this cache entry | |
* @param mixed $string The variable to cache | |
* @param array $tags Tags to associate with this cache entry | |
* @param int $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime. | |
* @return void | |
* | |
* @throws \InvalidArgumentException If the identifier or tag is not valid | |
* @throws \TYPO3\CMS\Core\Cache\Exception If no cache frontend has been set | |
* @throws \TYPO3\CMS\Core\Cache\Exception\InvalidDataException It doesn't apply | |
*/ | |
public function set($entryIdentifier, $string, array $tags = [], $lifetime = null) | |
{ | |
if (!$this->isValidEntryIdentifier($entryIdentifier)) { | |
throw new \InvalidArgumentException('"' . $entryIdentifier . '" is not a valid cache entry identifier.', 1233057566); | |
} | |
foreach ($tags as $tag) { | |
if (!$this->isValidTag($tag)) { | |
throw new \InvalidArgumentException('"' . $tag . '" is not a valid tag for a cache entry.', 1233057512); | |
} | |
} | |
$this->backend->set($entryIdentifier, $string, $tags, $lifetime); | |
} | |
/** | |
* Checks the validity of an entry identifier. Returns TRUE if it's valid. | |
* | |
* @param string $identifier An identifier to be checked for validity | |
* @return bool | |
*/ | |
public function isValidEntryIdentifier($identifier) | |
{ | |
return is_string($identifier) || is_int($identifier) || is_float($identifier); | |
} | |
/** | |
* Checks the validity of a tag. Returns TRUE if it's valid. | |
* | |
* @param string $tag An identifier to be checked for validity | |
* @return bool | |
*/ | |
public function isValidTag($tag) | |
{ | |
return is_string($tag); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Vendor\Product\Domain\Model; | |
/* ************************************************************* | |
* Copyright notice | |
* | |
* (c) 2018 Luis Antonio García Escobar <[email protected]> | |
* | |
* All rights reserved | |
* | |
* This script is part of the TYPO3 project. The TYPO3 project is | |
* free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* The GNU General Public License can be found at | |
* http://www.gnu.org/copyleft/gpl.html. | |
* | |
* This script is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* This copyright notice MUST APPEAR in all copies of the script! | |
***************************************************************/ | |
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy; | |
trait RelationUidTrait | |
{ | |
/** | |
* @param string $propertyName relation name (plural, lower camelCase) | |
* @return int | |
* @throws \ReflectionException | |
*/ | |
protected function getRelationUid($propertyName) | |
{ | |
if ($this->$propertyName instanceof LazyLoadingProxy) { | |
/** @var \ReflectionClass $reflectionClass */ | |
$reflectionClass = new \ReflectionClass(LazyLoadingProxy::class); | |
$reflectionProperty = $reflectionClass->getProperty('fieldValue'); | |
$reflectionProperty->setAccessible(true); | |
$uid = (int)$reflectionProperty->getValue($this->$propertyName); | |
} elseif (is_numeric($this->$propertyName)) { | |
$uid = $this->$propertyName; | |
} elseif (is_null($this->$propertyName)) { | |
$uid = 0; | |
} else { | |
$uid = $this->$propertyName->getUid(); | |
} | |
return $uid; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Vendor\Product\Cache\Backend; | |
/* ************************************************************* | |
* Copyright notice | |
* | |
* (c) 2018 Luis Antonio García Escobar <[email protected]> | |
* | |
* All rights reserved | |
* | |
* This script is part of the TYPO3 project. The TYPO3 project is | |
* free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* The GNU General Public License can be found at | |
* http://www.gnu.org/copyleft/gpl.html. | |
* | |
* This script is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* This copyright notice MUST APPEAR in all copies of the script! | |
***************************************************************/ | |
use TYPO3\CMS\Core\Cache\Backend\AbstractBackend; | |
use TYPO3\CMS\Core\Cache\Backend\TransientBackendInterface; | |
class TransientMemoryLRUBackend extends AbstractBackend implements TransientBackendInterface | |
{ | |
const FALLBACK_CACHE_SIZE = 25; | |
/** | |
* @var int | |
*/ | |
protected $maximumSize; | |
/** | |
* @var array | |
*/ | |
protected $entries = []; | |
protected $accessCount = 0; | |
protected $hitCount = 0; | |
protected $missCount = 0; | |
protected $setCount = 0; | |
protected $evictionCount = 0; | |
/** | |
* @param int $maximumSize | |
*/ | |
public function setMaximumSize($maximumSize) | |
{ | |
if (is_numeric($maximumSize)) { | |
$maximumSize = (int)$maximumSize; | |
} | |
if (is_int($maximumSize) && $maximumSize > 0) { | |
$this->maximumSize = $maximumSize; | |
} else { | |
$this->maximumSize = self::FALLBACK_CACHE_SIZE; | |
} | |
} | |
function __destruct() | |
{ | |
if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) { | |
echo json_encode([ | |
'accessCount' => $this->accessCount, | |
'hitCount' => $this->hitCount, | |
'missCount' => $this->missCount, | |
'setCount' => $this->setCount, | |
'evictionCount' => $this->evictionCount, | |
'memoryPeakUsage' => memory_get_peak_usage() . ' B', | |
]); | |
} | |
} | |
/** | |
* Saves data in the cache. | |
* | |
* @param string $entryIdentifier An identifier for this specific cache entry | |
* @param string $data The data to be stored | |
* @param array $tags Tags to associate with this cache entry | |
* @param int $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is | |
* used. "0" means unlimited liftime. | |
* @return void | |
* | |
* @throws \TYPO3\CMS\Core\Cache\Exception if no cache frontend has been set. | |
*/ | |
public function set($entryIdentifier, $data, array $tags = [], $lifetime = null) | |
{ | |
if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) { | |
throw new \TYPO3\CMS\Core\Cache\Exception('No cache frontend has been set yet via setCache().', 1238244992); | |
} | |
$this->setCount++; | |
if (isset($this->entries[$entryIdentifier])) { | |
$data = $this->entries[$entryIdentifier]; | |
unset($this->entries[$entryIdentifier]); | |
$this->entries[$entryIdentifier] = $data; | |
} else { | |
if (count($this->entries) >= $this->maximumSize) { | |
// remove least recently used element (front of array) | |
$this->evictionCount++; | |
reset($this->entries); | |
unset($this->entries[key($this->entries)]); | |
} | |
$this->entries[$entryIdentifier] = $data; | |
} | |
} | |
/** | |
* Loads data from the cache. | |
* | |
* @param string $entryIdentifier An identifier which describes the cache entry to load | |
* @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded | |
* @api | |
*/ | |
public function get($entryIdentifier) | |
{ | |
$this->accessCount++; | |
if (isset($this->entries[$entryIdentifier])) { | |
$this->hitCount++; | |
$data = $this->entries[$entryIdentifier]; | |
unset($this->entries[$entryIdentifier]); | |
$this->entries[$entryIdentifier] = $data; | |
return $data; | |
} else { | |
$this->missCount++; | |
return false; | |
} | |
} | |
/** | |
* Checks if a cache entry with the specified identifier exists. | |
* | |
* @param string $entryIdentifier An identifier specifying the cache entry | |
* @return bool TRUE if such an entry exists, FALSE if not | |
* @api | |
*/ | |
public function has($entryIdentifier) | |
{ | |
return isset($this->entries[$entryIdentifier]); | |
} | |
/** | |
* Removes all cache entries matching the specified identifier. | |
* | |
* @param string $entryIdentifier Specifies the cache entry to remove | |
* @return bool TRUE if the entry could be removed or FALSE if no entry was found | |
* @api | |
*/ | |
public function remove($entryIdentifier) | |
{ | |
if (isset($this->entries[$entryIdentifier])) { | |
unset($this->entries[$entryIdentifier]); | |
return true; | |
} else { | |
return false; | |
} | |
} | |
/** | |
* Removes all cache entries of this cache. | |
* | |
* @return void | |
* @api | |
*/ | |
public function flush() | |
{ | |
$this->entries = []; | |
} | |
/** | |
* Does nothing | |
* | |
* @return void | |
*/ | |
public function collectGarbage() | |
{ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment