[Cache] Move adapter implementations to traits
This commit is contained in:
parent
848a33ed3e
commit
99ae9d6a35
@ -13,31 +13,24 @@ namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\Traits\AbstractTrait;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
use AbstractTrait;
|
||||
|
||||
private static $apcuSupported;
|
||||
private static $phpFilesSupported;
|
||||
|
||||
private $namespace;
|
||||
private $deferred = array();
|
||||
private $createCacheItem;
|
||||
private $mergeByLifetime;
|
||||
|
||||
/**
|
||||
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
|
||||
*/
|
||||
protected $maxIdLength;
|
||||
|
||||
protected function __construct($namespace = '', $defaultLifetime = 0)
|
||||
{
|
||||
$this->namespace = '' === $namespace ? '' : $this->getId($namespace).':';
|
||||
@ -130,52 +123,6 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
throw new InvalidArgumentException(sprintf('Unsupported DSN: %s.', $dsn));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches several cache items.
|
||||
*
|
||||
* @param array $ids The cache identifiers to fetch
|
||||
*
|
||||
* @return array|\Traversable The corresponding values found in the cache
|
||||
*/
|
||||
abstract protected function doFetch(array $ids);
|
||||
|
||||
/**
|
||||
* Confirms if the cache contains specified cache item.
|
||||
*
|
||||
* @param string $id The identifier for which to check existence
|
||||
*
|
||||
* @return bool True if item exists in the cache, false otherwise
|
||||
*/
|
||||
abstract protected function doHave($id);
|
||||
|
||||
/**
|
||||
* Deletes all items in the pool.
|
||||
*
|
||||
* @param string The prefix used for all identifiers managed by this pool
|
||||
*
|
||||
* @return bool True if the pool was successfully cleared, false otherwise
|
||||
*/
|
||||
abstract protected function doClear($namespace);
|
||||
|
||||
/**
|
||||
* Removes multiple items from the pool.
|
||||
*
|
||||
* @param array $ids An array of identifiers that should be removed from the pool
|
||||
*
|
||||
* @return bool True if the items were successfully removed, false otherwise
|
||||
*/
|
||||
abstract protected function doDelete(array $ids);
|
||||
|
||||
/**
|
||||
* Persists several cache items immediately.
|
||||
*
|
||||
* @param array $values The values to cache, indexed by their cache identifier
|
||||
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
|
||||
*
|
||||
* @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
|
||||
*/
|
||||
abstract protected function doSave(array $values, $lifetime);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -225,87 +172,6 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
return $this->generateItems($items, $ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
$id = $this->getId($key);
|
||||
|
||||
if (isset($this->deferred[$key])) {
|
||||
$this->commit();
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->doHave($id);
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', array('key' => $key, 'exception' => $e));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->deferred = array();
|
||||
|
||||
try {
|
||||
return $this->doClear($this->namespace);
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to clear the cache', array('exception' => $e));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
return $this->deleteItems(array($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
$ids = array();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$ids[$key] = $this->getId($key);
|
||||
unset($this->deferred[$key]);
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->doDelete($ids)) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
$ok = true;
|
||||
|
||||
// When bulk-delete failed, retry each item individually
|
||||
foreach ($ids as $key => $id) {
|
||||
try {
|
||||
$e = null;
|
||||
if ($this->doDelete(array($id))) {
|
||||
continue;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -394,47 +260,6 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the native unserialize() function but throws an exception if anything goes wrong.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected static function unserialize($value)
|
||||
{
|
||||
if ('b:0;' === $value) {
|
||||
return false;
|
||||
}
|
||||
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
|
||||
try {
|
||||
if (false !== $value = unserialize($value)) {
|
||||
return $value;
|
||||
}
|
||||
throw new \DomainException('Failed to unserialize cached value');
|
||||
} catch (\Error $e) {
|
||||
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
|
||||
} finally {
|
||||
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private function getId($key)
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
if (null === $this->maxIdLength) {
|
||||
return $this->namespace.$key;
|
||||
}
|
||||
if (strlen($id = $this->namespace.$key) > $this->maxIdLength) {
|
||||
$id = $this->namespace.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -22);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
private function generateItems($items, &$keys)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
@ -453,12 +278,4 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
yield $key => $f($key, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function handleUnserializeCallback($class)
|
||||
{
|
||||
throw new \DomainException('Class not found: '.$class);
|
||||
}
|
||||
}
|
||||
|
@ -13,19 +13,16 @@ namespace Symfony\Component\Cache\Adapter;
|
||||
|
||||
use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Traits\ArrayTrait;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
use ArrayTrait;
|
||||
|
||||
private $storeSerialized;
|
||||
private $values = array();
|
||||
private $expiries = array();
|
||||
private $createCacheItem;
|
||||
|
||||
/**
|
||||
@ -86,49 +83,7 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
CacheItem::validateKey($key);
|
||||
}
|
||||
|
||||
return $this->generateItems($keys, time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all cached values, with cache miss as null.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
return isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->values = $this->expiries = array();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
unset($this->values[$key], $this->expiries[$key]);
|
||||
|
||||
return true;
|
||||
return $this->generateItems($keys, time(), $this->createCacheItem);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,35 +151,4 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function generateItems(array $keys, $now)
|
||||
{
|
||||
$f = $this->createCacheItem;
|
||||
|
||||
foreach ($keys as $i => $key) {
|
||||
try {
|
||||
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
|
||||
$this->values[$key] = $value = null;
|
||||
} elseif (!$this->storeSerialized) {
|
||||
$value = $this->values[$key];
|
||||
} elseif ('b:0;' === $value = $this->values[$key]) {
|
||||
$value = false;
|
||||
} elseif (false === $value = unserialize($value)) {
|
||||
$this->values[$key] = $value = null;
|
||||
$isHit = false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
|
||||
$this->values[$key] = $value = null;
|
||||
$isHit = false;
|
||||
}
|
||||
unset($keys[$i]);
|
||||
|
||||
yield $key => $f($key, $value, $isHit);
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
yield $key => $f($key, null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use Psr\Cache\CacheItemInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Cache\Traits\PhpArrayTrait;
|
||||
|
||||
/**
|
||||
* Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
|
||||
@ -25,10 +26,9 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
*/
|
||||
class PhpArrayAdapter implements AdapterInterface
|
||||
{
|
||||
private $file;
|
||||
private $values;
|
||||
use PhpArrayTrait;
|
||||
|
||||
private $createCacheItem;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* @param string $file The PHP file were values are cached
|
||||
@ -75,89 +75,6 @@ class PhpArrayAdapter implements AdapterInterface
|
||||
return $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an array of cached values.
|
||||
*
|
||||
* @param array $values The cached values
|
||||
*/
|
||||
public function warmUp(array $values)
|
||||
{
|
||||
if (file_exists($this->file)) {
|
||||
if (!is_file($this->file)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
|
||||
}
|
||||
|
||||
if (!is_writable($this->file)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
|
||||
}
|
||||
} else {
|
||||
$directory = dirname($this->file);
|
||||
|
||||
if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
|
||||
}
|
||||
|
||||
if (!is_writable($directory)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
|
||||
}
|
||||
}
|
||||
|
||||
$dump = <<<'EOF'
|
||||
<?php
|
||||
|
||||
// This file has been auto-generated by the Symfony Cache Component.
|
||||
|
||||
return array(
|
||||
|
||||
|
||||
EOF;
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
CacheItem::validateKey(is_int($key) ? (string) $key : $key);
|
||||
|
||||
if (null === $value || is_object($value)) {
|
||||
try {
|
||||
$value = serialize($value);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, get_class($value)), 0, $e);
|
||||
}
|
||||
} elseif (is_array($value)) {
|
||||
try {
|
||||
$serialized = serialize($value);
|
||||
$unserialized = unserialize($serialized);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
|
||||
}
|
||||
// Store arrays serialized if they contain any objects or references
|
||||
if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
|
||||
$value = $serialized;
|
||||
}
|
||||
} elseif (is_string($value)) {
|
||||
// Serialize strings if they could be confused with serialized objects or arrays
|
||||
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
|
||||
$value = serialize($value);
|
||||
}
|
||||
} elseif (!is_scalar($value)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, gettype($value)));
|
||||
}
|
||||
|
||||
$dump .= var_export($key, true).' => '.var_export($value, true).",\n";
|
||||
}
|
||||
|
||||
$dump .= "\n);\n";
|
||||
$dump = str_replace("' . \"\\0\" . '", "\0", $dump);
|
||||
|
||||
$tmpFile = uniqid($this->file, true);
|
||||
|
||||
file_put_contents($tmpFile, $dump);
|
||||
@chmod($tmpFile, 0666);
|
||||
unset($serialized, $unserialized, $value, $dump);
|
||||
|
||||
@rename($tmpFile, $this->file);
|
||||
|
||||
$this->values = (include $this->file) ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -228,18 +145,6 @@ EOF;
|
||||
return isset($this->values[$key]) || $this->fallbackPool->hasItem($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->values = array();
|
||||
|
||||
$cleared = @unlink($this->file) || !file_exists($this->file);
|
||||
|
||||
return $this->fallbackPool->clear() && $cleared;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -317,14 +222,6 @@ EOF;
|
||||
return $this->fallbackPool->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the cache file.
|
||||
*/
|
||||
private function initialize()
|
||||
{
|
||||
$this->values = file_exists($this->file) ? (include $this->file ?: array()) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generator for items.
|
||||
*
|
||||
|
209
src/Symfony/Component/Cache/Traits/AbstractTrait.php
Normal file
209
src/Symfony/Component/Cache/Traits/AbstractTrait.php
Normal file
@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait AbstractTrait
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
private $namespace;
|
||||
private $deferred = array();
|
||||
|
||||
/**
|
||||
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
|
||||
*/
|
||||
protected $maxIdLength;
|
||||
|
||||
/**
|
||||
* Fetches several cache items.
|
||||
*
|
||||
* @param array $ids The cache identifiers to fetch
|
||||
*
|
||||
* @return array|\Traversable The corresponding values found in the cache
|
||||
*/
|
||||
abstract protected function doFetch(array $ids);
|
||||
|
||||
/**
|
||||
* Confirms if the cache contains specified cache item.
|
||||
*
|
||||
* @param string $id The identifier for which to check existence
|
||||
*
|
||||
* @return bool True if item exists in the cache, false otherwise
|
||||
*/
|
||||
abstract protected function doHave($id);
|
||||
|
||||
/**
|
||||
* Deletes all items in the pool.
|
||||
*
|
||||
* @param string The prefix used for all identifiers managed by this pool
|
||||
*
|
||||
* @return bool True if the pool was successfully cleared, false otherwise
|
||||
*/
|
||||
abstract protected function doClear($namespace);
|
||||
|
||||
/**
|
||||
* Removes multiple items from the pool.
|
||||
*
|
||||
* @param array $ids An array of identifiers that should be removed from the pool
|
||||
*
|
||||
* @return bool True if the items were successfully removed, false otherwise
|
||||
*/
|
||||
abstract protected function doDelete(array $ids);
|
||||
|
||||
/**
|
||||
* Persists several cache items immediately.
|
||||
*
|
||||
* @param array $values The values to cache, indexed by their cache identifier
|
||||
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning
|
||||
*
|
||||
* @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not
|
||||
*/
|
||||
abstract protected function doSave(array $values, $lifetime);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
$id = $this->getId($key);
|
||||
|
||||
if (isset($this->deferred[$key])) {
|
||||
$this->commit();
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->doHave($id);
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', array('key' => $key, 'exception' => $e));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->deferred = array();
|
||||
|
||||
try {
|
||||
return $this->doClear($this->namespace);
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to clear the cache', array('exception' => $e));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
return $this->deleteItems(array($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItems(array $keys)
|
||||
{
|
||||
$ids = array();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$ids[$key] = $this->getId($key);
|
||||
unset($this->deferred[$key]);
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->doDelete($ids)) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
$ok = true;
|
||||
|
||||
// When bulk-delete failed, retry each item individually
|
||||
foreach ($ids as $key => $id) {
|
||||
try {
|
||||
$e = null;
|
||||
if ($this->doDelete(array($id))) {
|
||||
continue;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the native unserialize() function but throws an exception if anything goes wrong.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected static function unserialize($value)
|
||||
{
|
||||
if ('b:0;' === $value) {
|
||||
return false;
|
||||
}
|
||||
$unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
|
||||
try {
|
||||
if (false !== $value = unserialize($value)) {
|
||||
return $value;
|
||||
}
|
||||
throw new \DomainException('Failed to unserialize cached value');
|
||||
} catch (\Error $e) {
|
||||
throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine());
|
||||
} finally {
|
||||
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private function getId($key)
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
if (null === $this->maxIdLength) {
|
||||
return $this->namespace.$key;
|
||||
}
|
||||
if (strlen($id = $this->namespace.$key) > $this->maxIdLength) {
|
||||
$id = $this->namespace.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -22);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function handleUnserializeCallback($class)
|
||||
{
|
||||
throw new \DomainException('Class not found: '.$class);
|
||||
}
|
||||
}
|
@ -9,15 +9,17 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\CacheException;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ApcuAdapter extends AbstractAdapter
|
||||
trait ApcuTrait
|
||||
{
|
||||
public static function isSupported()
|
||||
{
|
100
src/Symfony/Component/Cache/Traits/ArrayTrait.php
Normal file
100
src/Symfony/Component/Cache/Traits/ArrayTrait.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait ArrayTrait
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
private $storeSerialized;
|
||||
private $values = array();
|
||||
private $expiries = array();
|
||||
|
||||
/**
|
||||
* Returns all cached values, with cache miss as null.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasItem($key)
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
return isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->values = $this->expiries = array();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteItem($key)
|
||||
{
|
||||
CacheItem::validateKey($key);
|
||||
|
||||
unset($this->values[$key], $this->expiries[$key]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function generateItems(array $keys, $now, $f)
|
||||
{
|
||||
foreach ($keys as $i => $key) {
|
||||
try {
|
||||
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
|
||||
$this->values[$key] = $value = null;
|
||||
} elseif (!$this->storeSerialized) {
|
||||
$value = $this->values[$key];
|
||||
} elseif ('b:0;' === $value = $this->values[$key]) {
|
||||
$value = false;
|
||||
} elseif (false === $value = unserialize($value)) {
|
||||
$this->values[$key] = $value = null;
|
||||
$isHit = false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
|
||||
$this->values[$key] = $value = null;
|
||||
$isHit = false;
|
||||
}
|
||||
unset($keys[$i]);
|
||||
|
||||
yield $key => $f($key, $value, $isHit);
|
||||
}
|
||||
|
||||
foreach ($keys as $key) {
|
||||
yield $key => $f($key, null, false);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,14 +9,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Doctrine\Common\Cache\CacheProvider;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DoctrineAdapter extends AbstractAdapter
|
||||
trait DoctrineTrait
|
||||
{
|
||||
private $provider;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
|
||||
@ -18,7 +18,7 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait FilesystemAdapterTrait
|
||||
trait FilesystemCommonTrait
|
||||
{
|
||||
private $directory;
|
||||
private $tmp;
|
@ -9,16 +9,18 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Symfony\Component\Cache\Exception\CacheException;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FilesystemAdapter extends AbstractAdapter
|
||||
trait FilesystemTrait
|
||||
{
|
||||
use FilesystemAdapterTrait;
|
||||
use FilesystemCommonTrait;
|
||||
|
||||
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
|
||||
{
|
@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Symfony\Component\Cache\Exception\CacheException;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
@ -17,8 +17,10 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
/**
|
||||
* @author Rob Frawley 2nd <rmf@src.run>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MemcachedAdapter extends AbstractAdapter
|
||||
trait MemcachedTrait
|
||||
{
|
||||
private static $defaultClientOptions = array(
|
||||
'persistent_id' => null,
|
||||
@ -26,8 +28,6 @@ class MemcachedAdapter extends AbstractAdapter
|
||||
'password' => null,
|
||||
);
|
||||
|
||||
protected $maxIdLength = 250;
|
||||
|
||||
private $client;
|
||||
|
||||
public static function isSupported()
|
@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
|
||||
@ -17,10 +17,11 @@ use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
|
||||
class PdoAdapter extends AbstractAdapter
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait PdoTrait
|
||||
{
|
||||
protected $maxIdLength = 255;
|
||||
|
||||
private $conn;
|
||||
private $dsn;
|
||||
private $driver;
|
131
src/Symfony/Component/Cache/Traits/PhpArrayTrait.php
Normal file
131
src/Symfony/Component/Cache/Traits/PhpArrayTrait.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait PhpArrayTrait
|
||||
{
|
||||
private $file;
|
||||
private $values;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* Store an array of cached values.
|
||||
*
|
||||
* @param array $values The cached values
|
||||
*/
|
||||
public function warmUp(array $values)
|
||||
{
|
||||
if (file_exists($this->file)) {
|
||||
if (!is_file($this->file)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
|
||||
}
|
||||
|
||||
if (!is_writable($this->file)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
|
||||
}
|
||||
} else {
|
||||
$directory = dirname($this->file);
|
||||
|
||||
if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
|
||||
}
|
||||
|
||||
if (!is_writable($directory)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
|
||||
}
|
||||
}
|
||||
|
||||
$dump = <<<'EOF'
|
||||
<?php
|
||||
|
||||
// This file has been auto-generated by the Symfony Cache Component.
|
||||
|
||||
return array(
|
||||
|
||||
|
||||
EOF;
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
CacheItem::validateKey(is_int($key) ? (string) $key : $key);
|
||||
|
||||
if (null === $value || is_object($value)) {
|
||||
try {
|
||||
$value = serialize($value);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, get_class($value)), 0, $e);
|
||||
}
|
||||
} elseif (is_array($value)) {
|
||||
try {
|
||||
$serialized = serialize($value);
|
||||
$unserialized = unserialize($serialized);
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
|
||||
}
|
||||
// Store arrays serialized if they contain any objects or references
|
||||
if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
|
||||
$value = $serialized;
|
||||
}
|
||||
} elseif (is_string($value)) {
|
||||
// Serialize strings if they could be confused with serialized objects or arrays
|
||||
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
|
||||
$value = serialize($value);
|
||||
}
|
||||
} elseif (!is_scalar($value)) {
|
||||
throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, gettype($value)));
|
||||
}
|
||||
|
||||
$dump .= var_export($key, true).' => '.var_export($value, true).",\n";
|
||||
}
|
||||
|
||||
$dump .= "\n);\n";
|
||||
$dump = str_replace("' . \"\\0\" . '", "\0", $dump);
|
||||
|
||||
$tmpFile = uniqid($this->file, true);
|
||||
|
||||
file_put_contents($tmpFile, $dump);
|
||||
@chmod($tmpFile, 0666);
|
||||
unset($serialized, $unserialized, $value, $dump);
|
||||
|
||||
@rename($tmpFile, $this->file);
|
||||
|
||||
$this->values = (include $this->file) ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->values = array();
|
||||
|
||||
$cleared = @unlink($this->file) || !file_exists($this->file);
|
||||
|
||||
return $this->fallbackPool->clear() && $cleared;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the cache file.
|
||||
*/
|
||||
private function initialize()
|
||||
{
|
||||
$this->values = @(include $this->file) ?: array();
|
||||
}
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Symfony\Component\Cache\Exception\CacheException;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
@ -17,10 +17,12 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
/**
|
||||
* @author Piotr Stankowski <git@trakos.pl>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PhpFilesAdapter extends AbstractAdapter
|
||||
trait PhpFilesTrait
|
||||
{
|
||||
use FilesystemAdapterTrait;
|
||||
use FilesystemCommonTrait;
|
||||
|
||||
private $includeHandler;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Adapter;
|
||||
namespace Symfony\Component\Cache\Traits;
|
||||
|
||||
use Predis\Connection\Factory;
|
||||
use Predis\Connection\Aggregate\PredisCluster;
|
||||
@ -19,8 +19,10 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
/**
|
||||
* @author Aurimas Niekis <aurimas@niekis.lt>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RedisAdapter extends AbstractAdapter
|
||||
trait RedisTrait
|
||||
{
|
||||
private static $defaultConnectionOptions = array(
|
||||
'class' => null,
|
Reference in New Issue
Block a user