diff --git a/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php new file mode 100644 index 0000000000..713e9fd7d8 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/ApcuAdapter.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Traits\ApcuTrait; + +class ApcuAdapter extends AbstractAdapter +{ + use ApcuTrait; + + public function __construct($namespace = '', $defaultLifetime = 0, $version = null) + { + $this->init($namespace, $defaultLifetime, $version); + } +} diff --git a/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php b/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php new file mode 100644 index 0000000000..befff7ca8e --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Doctrine\Common\Cache\CacheProvider; +use Symfony\Component\Cache\Traits\DoctrineTrait; + +class DoctrineAdapter extends AbstractAdapter +{ + use DoctrineTrait; + + public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0) + { + parent::__construct('', $defaultLifetime); + $this->provider = $provider; + $provider->setNamespace($namespace); + } +} diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php new file mode 100644 index 0000000000..f37cde290f --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Traits\FilesystemTrait; + +class FilesystemAdapter extends AbstractAdapter +{ + use FilesystemTrait; + + public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + { + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } +} diff --git a/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php new file mode 100644 index 0000000000..5c8784e69c --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Traits\MemcachedTrait; + +class MemcachedAdapter extends AbstractAdapter +{ + use MemcachedTrait; + + protected $maxIdLength = 250; + + public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) + { + $this->init($client, $namespace, $defaultLifetime); + } +} diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php new file mode 100644 index 0000000000..832185629b --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Traits\PdoTrait; + +class PdoAdapter extends AbstractAdapter +{ + use PdoTrait; + + protected $maxIdLength = 255; + + /** + * Constructor. + * + * You can either pass an existing database connection as PDO instance or + * a Doctrine DBAL Connection or a DSN string that will be used to + * lazy-connect to the database when the cache is actually used. + * + * List of available options: + * * db_table: The name of the table [default: cache_items] + * * db_id_col: The column where to store the cache id [default: item_id] + * * db_data_col: The column where to store the cache data [default: item_data] + * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime] + * * db_time_col: The column where to store the timestamp [default: item_time] + * * db_username: The username when lazy-connect [default: ''] + * * db_password: The password when lazy-connect [default: ''] + * * db_connection_options: An array of driver-specific connection options [default: array()] + * + * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null + * @param string $namespace + * @param int $defaultLifetime + * @param array $options An associative array of options + * + * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string + * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION + * @throws InvalidArgumentException When namespace contains invalid characters + */ + public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = array()) + { + $this->init($connOrDsn, $namespace, $defaultLifetime, $options); + } +} diff --git a/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php new file mode 100644 index 0000000000..12480c7436 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\CacheException; +use Symfony\Component\Cache\Traits\PhpFilesTrait; + +class PhpFilesAdapter extends AbstractAdapter +{ + use PhpFilesTrait; + + public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + { + if (!static::isSupported()) { + throw new CacheException('OPcache is not enabled'); + } + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + + $e = new \Exception(); + $this->includeHandler = function () use ($e) { throw $e; }; + } +} diff --git a/src/Symfony/Component/Cache/Adapter/RedisAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisAdapter.php new file mode 100644 index 0000000000..75cb764f40 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/RedisAdapter.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Traits\RedisTrait; + +class RedisAdapter extends AbstractAdapter +{ + use RedisTrait; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient + */ + public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) + { + $this->init($redisClient, $namespace, $defaultLifetime); + } +} diff --git a/src/Symfony/Component/Cache/CHANGELOG.md b/src/Symfony/Component/Cache/CHANGELOG.md index 94bbe13699..57a0780ae2 100644 --- a/src/Symfony/Component/Cache/CHANGELOG.md +++ b/src/Symfony/Component/Cache/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG ========= +3.3.0 +----- + + * added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters + * added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16 + * added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16) + * added TraceableAdapter (PSR-6) and TraceableCache (PSR-16) + 3.2.0 ----- diff --git a/src/Symfony/Component/Cache/Simple/AbstractCache.php b/src/Symfony/Component/Cache/Simple/AbstractCache.php new file mode 100644 index 0000000000..4c44b9b323 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/AbstractCache.php @@ -0,0 +1,177 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Psr\Log\LoggerAwareInterface; +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Traits\AbstractTrait; + +/** + * @author Nicolas Grekas
+ */ +abstract class AbstractCache implements CacheInterface, LoggerAwareInterface +{ + use AbstractTrait { + deleteItems as private; + AbstractTrait::deleteItem as delete; + AbstractTrait::hasItem as has; + } + + private $defaultLifetime; + + protected function __construct($namespace = '', $defaultLifetime = 0) + { + $this->defaultLifetime = max(0, (int) $defaultLifetime); + $this->namespace = '' === $namespace ? '' : $this->getId($namespace).':'; + if (null !== $this->maxIdLength && strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, strlen($namespace), $namespace)); + } + } + + /** + * {@inheritdoc} + */ + public function get($key, $default = null) + { + $id = $this->getId($key); + + try { + foreach ($this->doFetch(array($id)) as $value) { + return $value; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch key "{key}"', array('key' => $key, 'exception' => $e)); + } + + return $default; + } + + /** + * {@inheritdoc} + */ + public function set($key, $value, $ttl = null) + { + CacheItem::validateKey($key); + + return $this->setMultiple(array($key => $value), $ttl); + } + + /** + * {@inheritdoc} + */ + public function getMultiple($keys, $default = null) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys))); + } + $ids = array(); + + foreach ($keys as $key) { + $ids[] = $this->getId($key); + } + try { + $values = $this->doFetch($ids); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch requested values', array('keys' => $keys, 'exception' => $e)); + $values = array(); + } + $ids = array_combine($ids, $keys); + + return $this->generateValues($values, $ids, $default); + } + + /** + * {@inheritdoc} + */ + public function setMultiple($values, $ttl = null) + { + if (!is_array($values) && !$values instanceof \Traversable) { + throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', is_object($values) ? get_class($values) : gettype($values))); + } + $valuesById = array(); + + foreach ($values as $key => $value) { + if (is_int($key)) { + $key = (string) $key; + } + $valuesById[$this->getId($key)] = $value; + } + if (false === $ttl = $this->normalizeTtl($ttl)) { + return $this->doDelete(array_keys($valuesById)); + } + + try { + $e = $this->doSave($valuesById, $ttl); + } catch (\Exception $e) { + } + if (true === $e || array() === $e) { + return true; + } + $keys = array(); + foreach (is_array($e) ? $e : array_keys($valuesById) as $id) { + $keys[] = substr($id, strlen($this->namespace)); + } + CacheItem::log($this->logger, 'Failed to save values', array('keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null)); + + return false; + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple($keys) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys))); + } + + return $this->deleteItems($keys); + } + + private function normalizeTtl($ttl) + { + if (null === $ttl) { + return $this->defaultLifetime; + } + if ($ttl instanceof \DateInterval) { + $ttl = (int) \DateTime::createFromFormat('U', 0)->add($ttl)->format('U'); + } + if (is_int($ttl)) { + return 0 < $ttl ? $ttl : false; + } + + throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', is_object($ttl) ? get_class($ttl) : gettype($ttl))); + } + + private function generateValues($values, &$keys, $default) + { + try { + foreach ($values as $id => $value) { + $key = $keys[$id]; + unset($keys[$id]); + yield $key => $value; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch requested values', array('keys' => array_values($keys), 'exception' => $e)); + } + + foreach ($keys as $key) { + yield $key => $default; + } + } +} diff --git a/src/Symfony/Component/Cache/Simple/ApcuCache.php b/src/Symfony/Component/Cache/Simple/ApcuCache.php new file mode 100644 index 0000000000..16aa8661f0 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/ApcuCache.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Symfony\Component\Cache\Traits\ApcuTrait; + +class ApcuCache extends AbstractCache +{ + use ApcuTrait; + + public function __construct($namespace = '', $defaultLifetime = 0, $version = null) + { + $this->init($namespace, $defaultLifetime, $version); + } +} diff --git a/src/Symfony/Component/Cache/Simple/ArrayCache.php b/src/Symfony/Component/Cache/Simple/ArrayCache.php new file mode 100644 index 0000000000..a89768b0e2 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/ArrayCache.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Psr\Log\LoggerAwareInterface; +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Traits\ArrayTrait; + +/** + * @author Nicolas Grekas
+ */ +class ArrayCache implements CacheInterface, LoggerAwareInterface +{ + use ArrayTrait { + ArrayTrait::deleteItem as delete; + ArrayTrait::hasItem as has; + } + + private $defaultLifetime; + + /** + * @param int $defaultLifetime + * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise + */ + public function __construct($defaultLifetime = 0, $storeSerialized = true) + { + $this->defaultLifetime = (int) $defaultLifetime; + $this->storeSerialized = $storeSerialized; + } + + /** + * {@inheritdoc} + */ + public function get($key, $default = null) + { + foreach ($this->getMultiple(array($key), $default) as $v) { + return $v; + } + } + + /** + * {@inheritdoc} + */ + public function getMultiple($keys, $default = null) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys))); + } + foreach ($keys as $key) { + CacheItem::validateKey($key); + } + + return $this->generateItems($keys, time(), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; }); + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple($keys) + { + if (!is_array($keys) && !$keys instanceof \Traversable) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys))); + } + foreach ($keys as $key) { + $this->delete($key); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function set($key, $value, $ttl = null) + { + CacheItem::validateKey($key); + + return $this->setMultiple(array($key => $value), $ttl); + } + + /** + * {@inheritdoc} + */ + public function setMultiple($values, $ttl = null) + { + if (!is_array($values) && !$values instanceof \Traversable) { + throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', is_object($values) ? get_class($values) : gettype($values))); + } + $valuesArray = array(); + + foreach ($values as $key => $value) { + is_int($key) || CacheItem::validateKey($key); + $valuesArray[$key] = $value; + } + if (false === $ttl = $this->normalizeTtl($ttl)) { + return $this->deleteMultiple(array_keys($valuesArray)); + } + if ($this->storeSerialized) { + foreach ($valuesArray as $key => $value) { + try { + $valuesArray[$key] = serialize($value); + } catch (\Exception $e) { + $type = is_object($value) ? get_class($value) : gettype($value); + CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); + + return false; + } + } + } + $expiry = 0 < $ttl ? time() + $ttl : PHP_INT_MAX; + + foreach ($valuesArray as $key => $value) { + $this->values[$key] = $value; + $this->expiries[$key] = $expiry; + } + + return true; + } + + private function normalizeTtl($ttl) + { + if (null === $ttl) { + return $this->defaultLifetime; + } + if ($ttl instanceof \DateInterval) { + $ttl = (int) \DateTime::createFromFormat('U', 0)->add($ttl)->format('U'); + } + if (is_int($ttl)) { + return 0 < $ttl ? $ttl : false; + } + + throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', is_object($ttl) ? get_class($ttl) : gettype($ttl))); + } +} diff --git a/src/Symfony/Component/Cache/Simple/ChainCache.php b/src/Symfony/Component/Cache/Simple/ChainCache.php new file mode 100644 index 0000000000..08bb4881b4 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/ChainCache.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\Exception\InvalidArgumentException; + +/** + * Chains several caches together. + * + * Cached items are fetched from the first cache having them in its data store. + * They are saved and deleted in all caches at once. + * + * @author Nicolas Grekas
+ */ +class ChainCache implements CacheInterface +{ + private $miss; + private $caches = array(); + private $defaultLifetime; + private $cacheCount; + + /** + * @param CacheInterface[] $caches The ordered list of caches used to fetch cached items + * @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones + */ + public function __construct(array $caches, $defaultLifetime = 0) + { + if (!$caches) { + throw new InvalidArgumentException('At least one cache must be specified.'); + } + + foreach ($caches as $cache) { + if (!$cache instanceof CacheInterface) { + throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', get_class($cache), CacheInterface::class)); + } + } + + $this->miss = new \stdClass(); + $this->caches = array_values($caches); + $this->cacheCount = count($this->caches); + $this->defaultLifetime = 0 < $defaultLifetime ? (int) $defaultLifetime : null; + } + + /** + * {@inheritdoc} + */ + public function get($key, $default = null) + { + $miss = null !== $default && is_object($default) ? $default : $this->miss; + + foreach ($this->caches as $i => $cache) { + $value = $cache->get($key, $miss); + + if ($miss !== $value) { + while (0 <= --$i) { + $this->caches[$i]->set($key, $value, $this->defaultLifetime); + } + + return $value; + } + } + + return $default; + } + + /** + * {@inheritdoc} + */ + public function getMultiple($keys, $default = null) + { + $miss = null !== $default && is_object($default) ? $default : $this->miss; + + return $this->generateItems($this->caches[0]->getMultiple($keys, $miss), 0, $miss, $default); + } + + private function generateItems($values, $cacheIndex, $miss, $default) + { + $missing = array(); + $nextCacheIndex = $cacheIndex + 1; + $nextCache = isset($this->caches[$nextCacheIndex]) ? $this->caches[$nextCacheIndex] : null; + + foreach ($values as $k => $value) { + if ($miss !== $value) { + yield $k => $value; + } elseif (!$nextCache) { + yield $k => $default; + } else { + $missing[] = $k; + } + } + + if ($missing) { + $cache = $this->caches[$cacheIndex]; + $values = $this->generateItems($nextCache->getMultiple($missing, $miss), $nextCacheIndex, $miss, $default); + + foreach ($values as $k => $value) { + if ($miss !== $value) { + $cache->set($k, $value, $this->defaultLifetime); + yield $k => $value; + } else { + yield $k => $default; + } + } + } + } + + /** + * {@inheritdoc} + */ + public function has($key) + { + foreach ($this->caches as $cache) { + if ($cache->has($key)) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function clear() + { + $cleared = true; + $i = $this->cacheCount; + + while ($i--) { + $cleared = $this->caches[$i]->clear() && $cleared; + } + + return $cleared; + } + + /** + * {@inheritdoc} + */ + public function delete($key) + { + $deleted = true; + $i = $this->cacheCount; + + while ($i--) { + $deleted = $this->caches[$i]->delete($key) && $deleted; + } + + return $deleted; + } + + /** + * {@inheritdoc} + */ + public function deleteMultiple($keys) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } + $deleted = true; + $i = $this->cacheCount; + + while ($i--) { + $deleted = $this->caches[$i]->deleteMultiple($keys) && $deleted; + } + + return $deleted; + } + + /** + * {@inheritdoc} + */ + public function set($key, $value, $ttl = null) + { + $saved = true; + $i = $this->cacheCount; + + while ($i--) { + $saved = $this->caches[$i]->set($key, $value, $ttl) && $saved; + } + + return $saved; + } + + /** + * {@inheritdoc} + */ + public function setMultiple($values, $ttl = null) + { + if ($values instanceof \Traversable) { + $valuesIterator = $values; + $values = function () use ($valuesIterator, &$values) { + $generatedValues = array(); + + foreach ($valuesIterator as $key => $value) { + yield $key => $value; + $generatedValues[$key] = $value; + } + + $values = $generatedValues; + }; + $values = $values(); + } + $saved = true; + $i = $this->cacheCount; + + while ($i--) { + $saved = $this->caches[$i]->setMultiple($values, $ttl) && $saved; + } + + return $saved; + } +} diff --git a/src/Symfony/Component/Cache/Simple/DoctrineCache.php b/src/Symfony/Component/Cache/Simple/DoctrineCache.php new file mode 100644 index 0000000000..395c34dd81 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/DoctrineCache.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Doctrine\Common\Cache\CacheProvider; +use Symfony\Component\Cache\Traits\DoctrineTrait; + +class DoctrineCache extends AbstractCache +{ + use DoctrineTrait; + + public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0) + { + parent::__construct('', $defaultLifetime); + $this->provider = $provider; + $provider->setNamespace($namespace); + } +} diff --git a/src/Symfony/Component/Cache/Simple/FilesystemCache.php b/src/Symfony/Component/Cache/Simple/FilesystemCache.php new file mode 100644 index 0000000000..a60312ea57 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/FilesystemCache.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Symfony\Component\Cache\Traits\FilesystemTrait; + +class FilesystemCache extends AbstractCache +{ + use FilesystemTrait; + + public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + { + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } +} diff --git a/src/Symfony/Component/Cache/Simple/MemcachedCache.php b/src/Symfony/Component/Cache/Simple/MemcachedCache.php new file mode 100644 index 0000000000..1d5ee73c31 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/MemcachedCache.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Symfony\Component\Cache\Traits\MemcachedTrait; + +class MemcachedCache extends AbstractCache +{ + use MemcachedTrait; + + protected $maxIdLength = 250; + + public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) + { + $this->init($client, $namespace, $defaultLifetime); + } +} diff --git a/src/Symfony/Component/Cache/Simple/NullCache.php b/src/Symfony/Component/Cache/Simple/NullCache.php new file mode 100644 index 0000000000..fa986aebd1 --- /dev/null +++ b/src/Symfony/Component/Cache/Simple/NullCache.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Simple; + +use Psr\SimpleCache\CacheInterface; + +/** + * @author Nicolas Grekas
+ */
+class NullCache implements CacheInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get($key, $default = null)
+ {
+ return $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMultiple($keys, $default = null)
+ {
+ foreach ($keys as $key) {
+ yield $key => $default;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($key)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete($key)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteMultiple($keys)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($key, $value, $ttl = null)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setMultiple($values, $ttl = null)
+ {
+ return false;
+ }
+}
diff --git a/src/Symfony/Component/Cache/Simple/PdoCache.php b/src/Symfony/Component/Cache/Simple/PdoCache.php
new file mode 100644
index 0000000000..3e698e2f95
--- /dev/null
+++ b/src/Symfony/Component/Cache/Simple/PdoCache.php
@@ -0,0 +1,52 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Simple;
+
+use Symfony\Component\Cache\Traits\PdoTrait;
+
+class PdoCache extends AbstractCache
+{
+ use PdoTrait;
+
+ protected $maxIdLength = 255;
+
+ /**
+ * Constructor.
+ *
+ * You can either pass an existing database connection as PDO instance or
+ * a Doctrine DBAL Connection or a DSN string that will be used to
+ * lazy-connect to the database when the cache is actually used.
+ *
+ * List of available options:
+ * * db_table: The name of the table [default: cache_items]
+ * * db_id_col: The column where to store the cache id [default: item_id]
+ * * db_data_col: The column where to store the cache data [default: item_data]
+ * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]
+ * * db_time_col: The column where to store the timestamp [default: item_time]
+ * * db_username: The username when lazy-connect [default: '']
+ * * db_password: The password when lazy-connect [default: '']
+ * * db_connection_options: An array of driver-specific connection options [default: array()]
+ *
+ * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null
+ * @param string $namespace
+ * @param int $defaultLifetime
+ * @param array $options An associative array of options
+ *
+ * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
+ * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
+ * @throws InvalidArgumentException When namespace contains invalid characters
+ */
+ public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = array())
+ {
+ $this->init($connOrDsn, $namespace, $defaultLifetime, $options);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Simple/PhpArrayCache.php b/src/Symfony/Component/Cache/Simple/PhpArrayCache.php
new file mode 100644
index 0000000000..3c61f5e8f6
--- /dev/null
+++ b/src/Symfony/Component/Cache/Simple/PhpArrayCache.php
@@ -0,0 +1,256 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Simple;
+
+use Psr\SimpleCache\CacheInterface;
+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.
+ * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
+ *
+ * @author Titouan Galopin
+ */
+class PhpArrayCache implements CacheInterface
+{
+ use PhpArrayTrait;
+
+ /**
+ * @param string $file The PHP file were values are cached
+ * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit
+ */
+ public function __construct($file, CacheInterface $fallbackPool)
+ {
+ $this->file = $file;
+ $this->fallbackPool = $fallbackPool;
+ }
+
+ /**
+ * This adapter should only be used on PHP 7.0+ to take advantage of how PHP
+ * stores arrays in its latest versions. This factory method decorates the given
+ * fallback pool with this adapter only if the current PHP version is supported.
+ *
+ * @param string $file The PHP file were values are cached
+ *
+ * @return CacheInterface
+ */
+ public static function create($file, CacheInterface $fallbackPool)
+ {
+ // Shared memory is available in PHP 7.0+ with OPCache enabled and in HHVM
+ if ((PHP_VERSION_ID >= 70000 && ini_get('opcache.enable')) || defined('HHVM_VERSION')) {
+ return new static($file, $fallbackPool);
+ }
+
+ return $fallbackPool;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($key, $default = null)
+ {
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+ if (!isset($this->values[$key])) {
+ return $this->fallbackPool->get($key, $default);
+ }
+
+ $value = $this->values[$key];
+
+ if ('N;' === $value) {
+ $value = null;
+ } elseif (is_string($value) && isset($value[2]) && ':' === $value[1]) {
+ try {
+ $e = null;
+ $value = unserialize($value);
+ } catch (\Error $e) {
+ } catch (\Exception $e) {
+ }
+ if (null !== $e) {
+ return $default;
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMultiple($keys, $default = null)
+ {
+ if ($keys instanceof \Traversable) {
+ $keys = iterator_to_array($keys, false);
+ } elseif (!is_array($keys)) {
+ throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys)));
+ }
+ foreach ($keys as $key) {
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return $this->generateItems($keys, $default);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($key)
+ {
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return isset($this->values[$key]) || $this->fallbackPool->has($key);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete($key)
+ {
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return !isset($this->values[$key]) && $this->fallbackPool->delete($key);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteMultiple($keys)
+ {
+ if (!is_array($keys) && !$keys instanceof \Traversable) {
+ throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys)));
+ }
+
+ $deleted = true;
+ $fallbackKeys = array();
+
+ foreach ($keys as $key) {
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+
+ if (isset($this->values[$key])) {
+ $deleted = false;
+ } else {
+ $fallbackKeys[] = $key;
+ }
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ if ($fallbackKeys) {
+ $deleted = $this->fallbackPool->deleteMultiple($fallbackKeys) && $deleted;
+ }
+
+ return $deleted;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($key, $value, $ttl = null)
+ {
+ if (!is_string($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+ if (null === $this->values) {
+ $this->initialize();
+ }
+
+ return !isset($this->values[$key]) && $this->fallbackPool->set($key, $value, $ttl);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setMultiple($values, $ttl = null)
+ {
+ if (!is_array($values) && !$values instanceof \Traversable) {
+ throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given', is_object($values) ? get_class($values) : gettype($values)));
+ }
+
+ $saved = true;
+ $fallbackValues = array();
+
+ foreach ($values as $key => $value) {
+ if (!is_string($key) && !is_int($key)) {
+ throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
+ }
+
+ if (isset($this->values[$key])) {
+ $saved = false;
+ } else {
+ $fallbackValues[$key] = $value;
+ }
+ }
+
+ if ($fallbackValues) {
+ $saved = $this->fallbackPool->setMultiple($fallbackValues, $ttl) && $saved;
+ }
+
+ return $saved;
+ }
+
+ private function generateItems(array $keys, $default)
+ {
+ $fallbackKeys = array();
+
+ foreach ($keys as $key) {
+ if (isset($this->values[$key])) {
+ $value = $this->values[$key];
+
+ if ('N;' === $value) {
+ yield $key => null;
+ } elseif (is_string($value) && isset($value[2]) && ':' === $value[1]) {
+ try {
+ yield $key => unserialize($value);
+ } catch (\Error $e) {
+ yield $key => $default;
+ } catch (\Exception $e) {
+ yield $key => $default;
+ }
+ } else {
+ yield $key => $value;
+ }
+ } else {
+ $fallbackKeys[] = $key;
+ }
+ }
+
+ if ($fallbackKeys) {
+ foreach ($this->fallbackPool->getMultiple($fallbackKeys, $default) as $key => $item) {
+ yield $key => $item;
+ }
+ }
+ }
+}
diff --git a/src/Symfony/Component/Cache/Simple/PhpFilesCache.php b/src/Symfony/Component/Cache/Simple/PhpFilesCache.php
new file mode 100644
index 0000000000..c4d1200806
--- /dev/null
+++ b/src/Symfony/Component/Cache/Simple/PhpFilesCache.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Simple;
+
+use Symfony\Component\Cache\Exception\CacheException;
+use Symfony\Component\Cache\Traits\PhpFilesTrait;
+
+class PhpFilesCache extends AbstractCache
+{
+ use PhpFilesTrait;
+
+ public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
+ {
+ if (!static::isSupported()) {
+ throw new CacheException('OPcache is not enabled');
+ }
+ parent::__construct('', $defaultLifetime);
+ $this->init($namespace, $directory);
+
+ $e = new \Exception();
+ $this->includeHandler = function () use ($e) { throw $e; };
+ }
+}
diff --git a/src/Symfony/Component/Cache/Simple/RedisCache.php b/src/Symfony/Component/Cache/Simple/RedisCache.php
new file mode 100644
index 0000000000..799a3d082f
--- /dev/null
+++ b/src/Symfony/Component/Cache/Simple/RedisCache.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Simple;
+
+use Symfony\Component\Cache\Traits\RedisTrait;
+
+class RedisCache extends AbstractCache
+{
+ use RedisTrait;
+
+ /**
+ * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
+ */
+ public function __construct($redisClient, $namespace = '', $defaultLifetime = 0)
+ {
+ $this->init($redisClient, $namespace, $defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Simple/TraceableCache.php b/src/Symfony/Component/Cache/Simple/TraceableCache.php
new file mode 100644
index 0000000000..40b689dd5d
--- /dev/null
+++ b/src/Symfony/Component/Cache/Simple/TraceableCache.php
@@ -0,0 +1,190 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Simple;
+
+use Psr\SimpleCache\CacheInterface;
+
+/**
+ * An adapter that collects data about all cache calls.
+ *
+ * @author Nicolas Grekas
+ */
+class TraceableCache implements CacheInterface
+{
+ private $pool;
+ private $miss;
+ private $calls = array();
+
+ public function __construct(CacheInterface $pool)
+ {
+ $this->pool = $pool;
+ $this->miss = new \stdClass();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($key, $default = null)
+ {
+ $miss = null !== $default && is_object($default) ? $default : $this->miss;
+ $event = $this->start(__FUNCTION__, compact('key', 'default'));
+ try {
+ $value = $this->pool->get($key, $miss);
+ } finally {
+ $event->end = microtime(true);
+ }
+ if ($miss !== $value) {
+ ++$event->hits;
+ } else {
+ ++$event->misses;
+ $value = $default;
+ }
+
+ return $event->result = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($key)
+ {
+ $event = $this->start(__FUNCTION__, compact('key'));
+ try {
+ return $event->result = $this->pool->has($key);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete($key)
+ {
+ $event = $this->start(__FUNCTION__, compact('key'));
+ try {
+ return $event->result = $this->pool->delete($key);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($key, $value, $ttl = null)
+ {
+ $event = $this->start(__FUNCTION__, compact('key', 'value', 'ttl'));
+ try {
+ return $event->result = $this->pool->set($key, $value, $ttl);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setMultiple($values, $ttl = null)
+ {
+ $event = $this->start(__FUNCTION__, compact('values', 'ttl'));
+ try {
+ return $event->result = $this->pool->setMultiple($values, $ttl);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMultiple($keys, $default = null)
+ {
+ $miss = null !== $default && is_object($default) ? $default : $this->miss;
+ $event = $this->start(__FUNCTION__, compact('keys', 'default'));
+ try {
+ $result = $this->pool->getMultiple($keys, $miss);
+ } finally {
+ $event->end = microtime(true);
+ }
+ $f = function () use ($result, $event, $miss, $default) {
+ $event->result = array();
+ foreach ($result as $key => $value) {
+ if ($miss !== $value) {
+ ++$event->hits;
+ } else {
+ ++$event->misses;
+ $value = $default;
+ }
+ yield $key => $event->result[$key] = $value;
+ }
+ };
+
+ return $f();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ $event = $this->start(__FUNCTION__);
+ try {
+ return $event->result = $this->pool->clear();
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteMultiple($keys)
+ {
+ $event = $this->start(__FUNCTION__, compact('keys'));
+ try {
+ return $event->result = $this->pool->deleteMultiple($keys);
+ } finally {
+ $event->end = microtime(true);
+ }
+ }
+
+ public function getCalls()
+ {
+ try {
+ return $this->calls;
+ } finally {
+ $this->calls = array();
+ }
+ }
+
+ private function start($name, array $arguments = null)
+ {
+ $this->calls[] = $event = new TraceableCacheEvent();
+ $event->name = $name;
+ $event->arguments = $arguments;
+ $event->start = microtime(true);
+
+ return $event;
+ }
+}
+
+class TraceableCacheEvent
+{
+ public $name;
+ public $arguments;
+ public $start;
+ public $end;
+ public $result;
+ public $hits = 0;
+ public $misses = 0;
+}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php
index 50206bb278..7ebc36f0a5 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/ApcuAdapterTest.php
@@ -48,7 +48,7 @@ class ApcuAdapterTest extends AdapterTestCase
public function testVersion()
{
- $namespace = str_replace('\\', '.', __CLASS__);
+ $namespace = str_replace('\\', '.', get_class($this));
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
index 6567740d68..82b41c3b4d 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/MemcachedAdapterTest.php
@@ -22,7 +22,7 @@ class MemcachedAdapterTest extends AdapterTestCase
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
);
- private static $client;
+ protected static $client;
public static function setupBeforeClass()
{
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
index ff3351ddf6..ae0edb7d11 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php
@@ -51,7 +51,7 @@ class PhpArrayAdapterTest extends AdapterTestCase
'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
);
- private static $file;
+ protected static $file;
public static function setupBeforeClass()
{
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php
index 7030c0e9c5..45a50d2323 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php
@@ -25,10 +25,9 @@ class PhpArrayAdapterWithFallbackTest extends AdapterTestCase
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
- 'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
);
- private static $file;
+ protected static $file;
public static function setupBeforeClass()
{
@@ -42,8 +41,8 @@ class PhpArrayAdapterWithFallbackTest extends AdapterTestCase
}
}
- public function createCachePool()
+ public function createCachePool($defaultLifetime = 0)
{
- return new PhpArrayAdapter(self::$file, new FilesystemAdapter('php-array-fallback'));
+ return new PhpArrayAdapter(self::$file, new FilesystemAdapter('php-array-fallback', $defaultLifetime));
}
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php
index 3f3f17b883..1e0297c69e 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/SimpleCacheAdapterTest.php
@@ -11,9 +11,8 @@
namespace Symfony\Component\Cache\Tests\Adapter;
-use Symfony\Component\Cache\Adapter\FilesystemAdapter;
+use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Adapter\SimpleCacheAdapter;
-use Symfony\Component\Cache\Simple\Psr6Cache;
/**
* @group time-sensitive
@@ -22,6 +21,6 @@ class SimpleCacheAdapterTest extends AdapterTestCase
{
public function createCachePool($defaultLifetime = 0)
{
- return new SimpleCacheAdapter(new Psr6Cache(new FilesystemAdapter()), '', $defaultLifetime);
+ return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime);
}
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TraceableAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TraceableAdapterTest.php
index ad55218b0d..f05fbf9cfb 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/TraceableAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/TraceableAdapterTest.php
@@ -32,10 +32,10 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(1, $calls);
$call = $calls[0];
- $this->assertEquals('getItem', $call->name);
- $this->assertEquals('k', $call->argument);
- $this->assertEquals(0, $call->hits);
- $this->assertEquals(1, $call->misses);
+ $this->assertSame('getItem', $call->name);
+ $this->assertSame('k', $call->argument);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(1, $call->misses);
$this->assertNull($call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
@@ -51,8 +51,8 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(3, $calls);
$call = $calls[2];
- $this->assertEquals(1, $call->hits);
- $this->assertEquals(0, $call->misses);
+ $this->assertSame(1, $call->hits);
+ $this->assertSame(0, $call->misses);
}
public function testGetItemsMiss()
@@ -66,9 +66,9 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(1, $calls);
$call = $calls[0];
- $this->assertEquals('getItems', $call->name);
- $this->assertEquals($arg, $call->argument);
- $this->assertEquals(2, $call->misses);
+ $this->assertSame('getItems', $call->name);
+ $this->assertSame($arg, $call->argument);
+ $this->assertSame(2, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
@@ -81,8 +81,8 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(1, $calls);
$call = $calls[0];
- $this->assertEquals('hasItem', $call->name);
- $this->assertEquals('k', $call->argument);
+ $this->assertSame('hasItem', $call->name);
+ $this->assertSame('k', $call->argument);
$this->assertFalse($call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
@@ -98,8 +98,8 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(3, $calls);
$call = $calls[2];
- $this->assertEquals('hasItem', $call->name);
- $this->assertEquals('k', $call->argument);
+ $this->assertSame('hasItem', $call->name);
+ $this->assertSame('k', $call->argument);
$this->assertTrue($call->result);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
@@ -113,10 +113,10 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(1, $calls);
$call = $calls[0];
- $this->assertEquals('deleteItem', $call->name);
- $this->assertEquals('k', $call->argument);
- $this->assertEquals(0, $call->hits);
- $this->assertEquals(0, $call->misses);
+ $this->assertSame('deleteItem', $call->name);
+ $this->assertSame('k', $call->argument);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
@@ -130,10 +130,10 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(1, $calls);
$call = $calls[0];
- $this->assertEquals('deleteItems', $call->name);
- $this->assertEquals($arg, $call->argument);
- $this->assertEquals(0, $call->hits);
- $this->assertEquals(0, $call->misses);
+ $this->assertSame('deleteItems', $call->name);
+ $this->assertSame($arg, $call->argument);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
@@ -147,10 +147,10 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(2, $calls);
$call = $calls[1];
- $this->assertEquals('save', $call->name);
- $this->assertEquals($item, $call->argument);
- $this->assertEquals(0, $call->hits);
- $this->assertEquals(0, $call->misses);
+ $this->assertSame('save', $call->name);
+ $this->assertSame($item, $call->argument);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
@@ -164,10 +164,10 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(2, $calls);
$call = $calls[1];
- $this->assertEquals('saveDeferred', $call->name);
- $this->assertEquals($item, $call->argument);
- $this->assertEquals(0, $call->hits);
- $this->assertEquals(0, $call->misses);
+ $this->assertSame('saveDeferred', $call->name);
+ $this->assertSame($item, $call->argument);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
@@ -180,10 +180,10 @@ class TraceableAdapterTest extends AdapterTestCase
$this->assertCount(1, $calls);
$call = $calls[0];
- $this->assertEquals('commit', $call->name);
+ $this->assertSame('commit', $call->name);
$this->assertNull(null, $call->argument);
- $this->assertEquals(0, $call->hits);
- $this->assertEquals(0, $call->misses);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
$this->assertNotEmpty($call->start);
$this->assertNotEmpty($call->end);
}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/AbstractRedisCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/AbstractRedisCacheTest.php
new file mode 100644
index 0000000000..1d097fff85
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/AbstractRedisCacheTest.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\RedisCache;
+
+abstract class AbstractRedisCacheTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testSetTtl' => 'Testing expiration slows down the test suite',
+ 'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
+ 'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
+ );
+
+ protected static $redis;
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new RedisCache(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
+ }
+
+ public static function setupBeforeClass()
+ {
+ if (!extension_loaded('redis')) {
+ self::markTestSkipped('Extension redis required.');
+ }
+ if (!@((new \Redis())->connect(getenv('REDIS_HOST')))) {
+ $e = error_get_last();
+ self::markTestSkipped($e['message']);
+ }
+ }
+
+ public static function tearDownAfterClass()
+ {
+ self::$redis->flushDB();
+ self::$redis = null;
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/ApcuCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/ApcuCacheTest.php
new file mode 100644
index 0000000000..297a41756f
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/ApcuCacheTest.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\ApcuCache;
+
+class ApcuCacheTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testSetTtl' => 'Testing expiration slows down the test suite',
+ 'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
+ 'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
+ );
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ if (!function_exists('apcu_fetch') || !ini_get('apc.enabled') || ('cli' === PHP_SAPI && !ini_get('apc.enable_cli'))) {
+ $this->markTestSkipped('APCu extension is required.');
+ }
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Fails transiently on Windows.');
+ }
+
+ return new ApcuCache(str_replace('\\', '.', __CLASS__), $defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/ArrayCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/ArrayCacheTest.php
new file mode 100644
index 0000000000..26c3e14d09
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/ArrayCacheTest.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\ArrayCache;
+
+/**
+ * @group time-sensitive
+ */
+class ArrayCacheTest extends CacheTestCase
+{
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new ArrayCache($defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
new file mode 100644
index 0000000000..81d412bd66
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Cache\IntegrationTests\SimpleCacheTest;
+
+abstract class CacheTestCase extends SimpleCacheTest
+{
+ public function testDefaultLifeTime()
+ {
+ if (isset($this->skippedTests[__FUNCTION__])) {
+ $this->markTestSkipped($this->skippedTests[__FUNCTION__]);
+ }
+
+ $cache = $this->createSimpleCache(2);
+
+ $cache->set('key.dlt', 'value');
+ sleep(1);
+
+ $this->assertSame('value', $cache->get('key.dlt'));
+
+ sleep(2);
+ $this->assertNull($cache->get('key.dlt'));
+ }
+
+ public function testNotUnserializable()
+ {
+ if (isset($this->skippedTests[__FUNCTION__])) {
+ $this->markTestSkipped($this->skippedTests[__FUNCTION__]);
+ }
+
+ $cache = $this->createSimpleCache();
+
+ $cache->set('foo', new NotUnserializable());
+
+ $this->assertNull($cache->get('foo'));
+
+ $cache->setMultiple(array('foo' => new NotUnserializable()));
+
+ foreach ($cache->getMultiple(array('foo')) as $value) {
+ }
+ $this->assertNull($value);
+ }
+}
+
+class NotUnserializable implements \Serializable
+{
+ public function serialize()
+ {
+ return serialize(123);
+ }
+
+ public function unserialize($ser)
+ {
+ throw new \Exception(__CLASS__);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/ChainCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/ChainCacheTest.php
new file mode 100644
index 0000000000..282bb62a65
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/ChainCacheTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\ArrayCache;
+use Symfony\Component\Cache\Simple\ChainCache;
+use Symfony\Component\Cache\Simple\FilesystemCache;
+
+/**
+ * @group time-sensitive
+ */
+class ChainCacheTest extends CacheTestCase
+{
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new ChainCache(array(new ArrayCache($defaultLifetime), new FilesystemCache('', $defaultLifetime)), $defaultLifetime);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
+ * @expectedExceptionMessage At least one cache must be specified.
+ */
+ public function testEmptyCachesException()
+ {
+ new ChainCache(array());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
+ * @expectedExceptionMessage The class "stdClass" does not implement
+ */
+ public function testInvalidCacheException()
+ {
+ new Chaincache(array(new \stdClass()));
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php
new file mode 100644
index 0000000000..0a185297ab
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/DoctrineCacheTest.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Doctrine\Common\Cache\ArrayCache;
+use Symfony\Component\Cache\Simple\DoctrineCache;
+
+/**
+ * @group time-sensitive
+ */
+class DoctrineCacheTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testObjectDoesNotChangeInCache' => 'ArrayCache does not use serialize/unserialize',
+ 'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
+ );
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new DoctrineCache(new ArrayCache($defaultLifetime), '', $defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/FilesystemCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/FilesystemCacheTest.php
new file mode 100644
index 0000000000..0f2d519cad
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/FilesystemCacheTest.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\FilesystemCache;
+
+/**
+ * @group time-sensitive
+ */
+class FilesystemCacheTest extends CacheTestCase
+{
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new FilesystemCache('', $defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/MemcachedCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/MemcachedCacheTest.php
new file mode 100644
index 0000000000..c4af891af7
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/MemcachedCacheTest.php
@@ -0,0 +1,165 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Adapter\AbstractAdapter;
+use Symfony\Component\Cache\Simple\MemcachedCache;
+
+class MemcachedCacheTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testSetTtl' => 'Testing expiration slows down the test suite',
+ 'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
+ 'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
+ );
+
+ protected static $client;
+
+ public static function setupBeforeClass()
+ {
+ if (!MemcachedCache::isSupported()) {
+ self::markTestSkipped('Extension memcached >=2.2.0 required.');
+ }
+ self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'));
+ self::$client->get('foo');
+ $code = self::$client->getResultCode();
+
+ if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
+ self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage()));
+ }
+ }
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ $client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), array('binary_protocol' => false)) : self::$client;
+
+ return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
+ }
+
+ public function testOptions()
+ {
+ $client = MemcachedCache::createConnection(array(), array(
+ 'libketama_compatible' => false,
+ 'distribution' => 'modula',
+ 'compression' => true,
+ 'serializer' => 'php',
+ 'hash' => 'md5',
+ ));
+
+ $this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER));
+ $this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH));
+ $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
+ $this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
+ $this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION));
+ }
+
+ /**
+ * @dataProvider provideBadOptions
+ * @expectedException \ErrorException
+ * @expectedExceptionMessage constant(): Couldn't find constant Memcached::
+ */
+ public function testBadOptions($name, $value)
+ {
+ MemcachedCache::createConnection(array(), array($name => $value));
+ }
+
+ public function provideBadOptions()
+ {
+ return array(
+ array('foo', 'bar'),
+ array('hash', 'zyx'),
+ array('serializer', 'zyx'),
+ array('distribution', 'zyx'),
+ );
+ }
+
+ public function testDefaultOptions()
+ {
+ $this->assertTrue(MemcachedCache::isSupported());
+
+ $client = MemcachedCache::createConnection(array());
+
+ $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
+ $this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL));
+ $this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Cache\Exception\CacheException
+ * @expectedExceptionMessage MemcachedAdapter: "serializer" option must be "php" or "igbinary".
+ */
+ public function testOptionSerializer()
+ {
+ if (!\Memcached::HAVE_JSON) {
+ $this->markTestSkipped('Memcached::HAVE_JSON required');
+ }
+
+ new MemcachedCache(MemcachedCache::createConnection(array(), array('serializer' => 'json')));
+ }
+
+ /**
+ * @dataProvider provideServersSetting
+ */
+ public function testServersSetting($dsn, $host, $port)
+ {
+ $client1 = MemcachedCache::createConnection($dsn);
+ $client2 = MemcachedCache::createConnection(array($dsn));
+ $client3 = MemcachedCache::createConnection(array(array($host, $port)));
+ $expect = array(
+ 'host' => $host,
+ 'port' => $port,
+ );
+
+ $f = function ($s) { return array('host' => $s['host'], 'port' => $s['port']); };
+ $this->assertSame(array($expect), array_map($f, $client1->getServerList()));
+ $this->assertSame(array($expect), array_map($f, $client2->getServerList()));
+ $this->assertSame(array($expect), array_map($f, $client3->getServerList()));
+ }
+
+ public function provideServersSetting()
+ {
+ yield array(
+ 'memcached://127.0.0.1/50',
+ '127.0.0.1',
+ 11211,
+ );
+ yield array(
+ 'memcached://localhost:11222?weight=25',
+ 'localhost',
+ 11222,
+ );
+ if (ini_get('memcached.use_sasl')) {
+ yield array(
+ 'memcached://user:password@127.0.0.1?weight=50',
+ '127.0.0.1',
+ 11211,
+ );
+ }
+ yield array(
+ 'memcached:///var/run/memcached.sock?weight=25',
+ '/var/run/memcached.sock',
+ 0,
+ );
+ yield array(
+ 'memcached:///var/local/run/memcached.socket?weight=25',
+ '/var/local/run/memcached.socket',
+ 0,
+ );
+ if (ini_get('memcached.use_sasl')) {
+ yield array(
+ 'memcached://user:password@/var/local/run/memcached.socket?weight=25',
+ '/var/local/run/memcached.socket',
+ 0,
+ );
+ }
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/NullCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/NullCacheTest.php
new file mode 100644
index 0000000000..e7b9674ff1
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/NullCacheTest.php
@@ -0,0 +1,95 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\NullCache;
+
+/**
+ * @group time-sensitive
+ */
+class NullCacheTest extends \PHPUnit_Framework_TestCase
+{
+ public function createCachePool()
+ {
+ return new NullCache();
+ }
+
+ public function testGetItem()
+ {
+ $cache = $this->createCachePool();
+
+ $this->assertNull($cache->get('key'));
+ }
+
+ public function testHas()
+ {
+ $this->assertFalse($this->createCachePool()->has('key'));
+ }
+
+ public function testGetMultiple()
+ {
+ $cache = $this->createCachePool();
+
+ $keys = array('foo', 'bar', 'baz', 'biz');
+
+ $default = new \stdClass();
+ $items = $cache->getMultiple($keys, $default);
+ $count = 0;
+
+ foreach ($items as $key => $item) {
+ $this->assertTrue(in_array($key, $keys), 'Cache key can not change.');
+ $this->assertSame($default, $item);
+
+ // Remove $key for $keys
+ foreach ($keys as $k => $v) {
+ if ($v === $key) {
+ unset($keys[$k]);
+ }
+ }
+
+ ++$count;
+ }
+
+ $this->assertSame(4, $count);
+ }
+
+ public function testClear()
+ {
+ $this->assertTrue($this->createCachePool()->clear());
+ }
+
+ public function testDelete()
+ {
+ $this->assertTrue($this->createCachePool()->delete('key'));
+ }
+
+ public function testDeleteMultiple()
+ {
+ $this->assertTrue($this->createCachePool()->deleteMultiple(array('key', 'foo', 'bar')));
+ }
+
+ public function testSet()
+ {
+ $cache = $this->createCachePool();
+
+ $this->assertFalse($cache->set('key', 'val'));
+ $this->assertNull($cache->get('key'));
+ }
+
+ public function testSetMultiple()
+ {
+ $cache = $this->createCachePool();
+
+ $this->assertFalse($cache->setMultiple(array('key' => 'val')));
+ $this->assertNull($cache->get('key'));
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/PdoCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PdoCacheTest.php
new file mode 100644
index 0000000000..2605ba9201
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/PdoCacheTest.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\PdoCache;
+
+/**
+ * @group time-sensitive
+ */
+class PdoCacheTest extends CacheTestCase
+{
+ protected static $dbFile;
+
+ public static function setupBeforeClass()
+ {
+ if (!extension_loaded('pdo_sqlite')) {
+ throw new \PHPUnit_Framework_SkippedTestError('Extension pdo_sqlite required.');
+ }
+
+ self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
+
+ $pool = new PdoCache('sqlite:'.self::$dbFile);
+ $pool->createTable();
+ }
+
+ public static function tearDownAfterClass()
+ {
+ @unlink(self::$dbFile);
+ }
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new PdoCache('sqlite:'.self::$dbFile, 'ns', $defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php
new file mode 100644
index 0000000000..18847ad925
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/PdoDbalCacheTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Doctrine\DBAL\DriverManager;
+use Symfony\Component\Cache\Simple\PdoCache;
+
+/**
+ * @group time-sensitive
+ */
+class PdoDbalCacheTest extends CacheTestCase
+{
+ protected static $dbFile;
+
+ public static function setupBeforeClass()
+ {
+ if (!extension_loaded('pdo_sqlite')) {
+ throw new \PHPUnit_Framework_SkippedTestError('Extension pdo_sqlite required.');
+ }
+
+ self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
+
+ $pool = new PdoCache(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile)));
+ $pool->createTable();
+ }
+
+ public static function tearDownAfterClass()
+ {
+ @unlink(self::$dbFile);
+ }
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new PdoCache(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile)), '', $defaultLifetime);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php
new file mode 100644
index 0000000000..3016ac560e
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php
@@ -0,0 +1,139 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest;
+use Symfony\Component\Cache\Simple\NullCache;
+use Symfony\Component\Cache\Simple\PhpArrayCache;
+
+/**
+ * @group time-sensitive
+ */
+class PhpArrayCacheTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testDelete' => 'PhpArrayCache does no writes',
+ 'testDeleteMultiple' => 'PhpArrayCache does no writes',
+ 'testDeleteMultipleGenerator' => 'PhpArrayCache does no writes',
+
+ 'testSetTtl' => 'PhpArrayCache does no expiration',
+ 'testSetMultipleTtl' => 'PhpArrayCache does no expiration',
+ 'testSetExpiredTtl' => 'PhpArrayCache does no expiration',
+ 'testSetMultipleExpiredTtl' => 'PhpArrayCache does no expiration',
+
+ 'testGetInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testSetInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testDeleteInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testSetInvalidTtl' => 'PhpArrayCache does no validation',
+ 'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation',
+ 'testHasInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testSetValidData' => 'PhpArrayCache does no validation',
+
+ 'testDefaultLifeTime' => 'PhpArrayCache does not allow configuring a default lifetime.',
+ );
+
+ protected static $file;
+
+ public static function setupBeforeClass()
+ {
+ self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
+ }
+
+ protected function tearDown()
+ {
+ if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
+ FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
+ }
+ }
+ public function createSimpleCache()
+ {
+ return new PhpArrayCacheWrapper(self::$file, new NullCache());
+ }
+
+ public function testStore()
+ {
+ $arrayWithRefs = array();
+ $arrayWithRefs[0] = 123;
+ $arrayWithRefs[1] = &$arrayWithRefs[0];
+
+ $object = (object) array(
+ 'foo' => 'bar',
+ 'foo2' => 'bar2',
+ );
+
+ $expected = array(
+ 'null' => null,
+ 'serializedString' => serialize($object),
+ 'arrayWithRefs' => $arrayWithRefs,
+ 'object' => $object,
+ 'arrayWithObject' => array('bar' => $object),
+ );
+
+ $cache = new PhpArrayCache(self::$file, new NullCache());
+ $cache->warmUp($expected);
+
+ foreach ($expected as $key => $value) {
+ $this->assertSame(serialize($value), serialize($cache->get($key)), 'Warm up should create a PHP file that OPCache can load in memory');
+ }
+ }
+
+ public function testStoredFile()
+ {
+ $expected = array(
+ 'integer' => 42,
+ 'float' => 42.42,
+ 'boolean' => true,
+ 'array_simple' => array('foo', 'bar'),
+ 'array_associative' => array('foo' => 'bar', 'foo2' => 'bar2'),
+ );
+
+ $cache = new PhpArrayCache(self::$file, new NullCache());
+ $cache->warmUp($expected);
+
+ $values = eval(substr(file_get_contents(self::$file), 6));
+
+ $this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory');
+ }
+}
+
+class PhpArrayCacheWrapper extends PhpArrayCache
+{
+ public function set($key, $value, $ttl = null)
+ {
+ call_user_func(\Closure::bind(function () use ($key, $value) {
+ $this->values[$key] = $value;
+ $this->warmUp($this->values);
+ $this->values = eval(substr(file_get_contents($this->file), 6));
+ }, $this, PhpArrayCache::class));
+
+ return true;
+ }
+
+ public function setMultiple($values, $ttl = null)
+ {
+ if (!is_array($values) && !$values instanceof \Traversable) {
+ return parent::setMultiple($values, $ttl);
+ }
+ call_user_func(\Closure::bind(function () use ($values) {
+ foreach ($values as $key => $value) {
+ $this->values[$key] = $value;
+ }
+ $this->warmUp($this->values);
+ $this->values = eval(substr(file_get_contents($this->file), 6));
+ }, $this, PhpArrayCache::class));
+
+ return true;
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php
new file mode 100644
index 0000000000..a624fa73e7
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\FilesystemCache;
+use Symfony\Component\Cache\Simple\PhpArrayCache;
+use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest;
+
+/**
+ * @group time-sensitive
+ */
+class PhpArrayCacheWithFallbackTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testGetInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testDeleteInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation',
+ //'testSetValidData' => 'PhpArrayCache does no validation',
+ 'testSetInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testSetInvalidTtl' => 'PhpArrayCache does no validation',
+ 'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
+ 'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation',
+ 'testHasInvalidKeys' => 'PhpArrayCache does no validation',
+ );
+
+ protected static $file;
+
+ public static function setupBeforeClass()
+ {
+ self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
+ }
+
+ protected function tearDown()
+ {
+ if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
+ FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
+ }
+ }
+
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new PhpArrayCache(self::$file, new FilesystemCache('php-array-fallback', $defaultLifetime));
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpFilesCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpFilesCacheTest.php
new file mode 100644
index 0000000000..3118fcf94e
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/PhpFilesCacheTest.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\PhpFilesCache;
+
+/**
+ * @group time-sensitive
+ */
+class PhpFilesCacheTest extends CacheTestCase
+{
+ protected $skippedTests = array(
+ 'testDefaultLifeTime' => 'PhpFilesCache does not allow configuring a default lifetime.',
+ );
+
+ public function createSimpleCache()
+ {
+ if (!PhpFilesCache::isSupported()) {
+ $this->markTestSkipped('OPcache extension is not enabled.');
+ }
+
+ return new PhpFilesCache('sf-cache');
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/Psr6CacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/Psr6CacheTest.php
new file mode 100644
index 0000000000..16e21d0c0b
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/Psr6CacheTest.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Adapter\FilesystemAdapter;
+use Symfony\Component\Cache\Simple\Psr6Cache;
+
+/**
+ * @group time-sensitive
+ */
+class Psr6CacheTest extends CacheTestCase
+{
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new Psr6Cache(new FilesystemAdapter('', $defaultLifetime));
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/RedisArrayCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/RedisArrayCacheTest.php
new file mode 100644
index 0000000000..3c903c8a9b
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/RedisArrayCacheTest.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+class RedisArrayCacheTest extends AbstractRedisCacheTest
+{
+ public static function setupBeforeClass()
+ {
+ parent::setupBeforeClass();
+ if (!class_exists('RedisArray')) {
+ self::markTestSkipped('The RedisArray class is required.');
+ }
+ self::$redis = new \RedisArray(array(getenv('REDIS_HOST')), array('lazy_connect' => true));
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/RedisCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/RedisCacheTest.php
new file mode 100644
index 0000000000..d33421f9aa
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/RedisCacheTest.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\RedisCache;
+
+class RedisCacheTest extends AbstractRedisCacheTest
+{
+ public static function setupBeforeClass()
+ {
+ parent::setupBeforeClass();
+ self::$redis = RedisCache::createConnection('redis://'.getenv('REDIS_HOST'));
+ }
+
+ public function testCreateConnection()
+ {
+ $redisHost = getenv('REDIS_HOST');
+
+ $redis = RedisCache::createConnection('redis://'.$redisHost);
+ $this->assertInstanceOf(\Redis::class, $redis);
+ $this->assertTrue($redis->isConnected());
+ $this->assertSame(0, $redis->getDbNum());
+
+ $redis = RedisCache::createConnection('redis://'.$redisHost.'/2');
+ $this->assertSame(2, $redis->getDbNum());
+
+ $redis = RedisCache::createConnection('redis://'.$redisHost, array('timeout' => 3));
+ $this->assertEquals(3, $redis->getTimeout());
+
+ $redis = RedisCache::createConnection('redis://'.$redisHost.'?timeout=4');
+ $this->assertEquals(4, $redis->getTimeout());
+
+ $redis = RedisCache::createConnection('redis://'.$redisHost, array('read_timeout' => 5));
+ $this->assertEquals(5, $redis->getReadTimeout());
+ }
+
+ /**
+ * @dataProvider provideFailedCreateConnection
+ * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Redis connection failed
+ */
+ public function testFailedCreateConnection($dsn)
+ {
+ RedisCache::createConnection($dsn);
+ }
+
+ public function provideFailedCreateConnection()
+ {
+ return array(
+ array('redis://localhost:1234'),
+ array('redis://foo@localhost'),
+ array('redis://localhost/123'),
+ );
+ }
+
+ /**
+ * @dataProvider provideInvalidCreateConnection
+ * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Invalid Redis DSN
+ */
+ public function testInvalidCreateConnection($dsn)
+ {
+ RedisCache::createConnection($dsn);
+ }
+
+ public function provideInvalidCreateConnection()
+ {
+ return array(
+ array('foo://localhost'),
+ array('redis://'),
+ );
+ }
+}
diff --git a/src/Symfony/Component/Cache/Tests/Simple/TraceableCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/TraceableCacheTest.php
new file mode 100644
index 0000000000..ebdc770add
--- /dev/null
+++ b/src/Symfony/Component/Cache/Tests/Simple/TraceableCacheTest.php
@@ -0,0 +1,170 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Cache\Tests\Simple;
+
+use Symfony\Component\Cache\Simple\FilesystemCache;
+use Symfony\Component\Cache\Simple\TraceableCache;
+
+/**
+ * @group time-sensitive
+ */
+class TraceableCacheTest extends CacheTestCase
+{
+ public function createSimpleCache($defaultLifetime = 0)
+ {
+ return new TraceableCache(new FilesystemCache('', $defaultLifetime));
+ }
+
+ public function testGetMiss()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->get('k');
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('get', $call->name);
+ $this->assertSame(array('key' => 'k', 'default' => null), $call->arguments);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(1, $call->misses);
+ $this->assertNull($call->result);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testGetHit()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->set('k', 'foo');
+ $pool->get('k');
+ $calls = $pool->getCalls();
+ $this->assertCount(2, $calls);
+
+ $call = $calls[1];
+ $this->assertSame(1, $call->hits);
+ $this->assertSame(0, $call->misses);
+ }
+
+ public function testGetMultipleMiss()
+ {
+ $pool = $this->createSimpleCache();
+ $arg = array('k0', 'k1');
+ $values = $pool->getMultiple($arg);
+ foreach ($values as $value) {
+ }
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('getMultiple', $call->name);
+ $this->assertSame(array('keys' => $arg, 'default' => null), $call->arguments);
+ $this->assertSame(2, $call->misses);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testHasMiss()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->has('k');
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('has', $call->name);
+ $this->assertSame(array('key' => 'k'), $call->arguments);
+ $this->assertFalse($call->result);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testHasHit()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->set('k', 'foo');
+ $pool->has('k');
+ $calls = $pool->getCalls();
+ $this->assertCount(2, $calls);
+
+ $call = $calls[1];
+ $this->assertSame('has', $call->name);
+ $this->assertSame(array('key' => 'k'), $call->arguments);
+ $this->assertTrue($call->result);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testDelete()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->delete('k');
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('delete', $call->name);
+ $this->assertSame(array('key' => 'k'), $call->arguments);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testDeleteMultiple()
+ {
+ $pool = $this->createSimpleCache();
+ $arg = array('k0', 'k1');
+ $pool->deleteMultiple($arg);
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('deleteMultiple', $call->name);
+ $this->assertSame(array('keys' => $arg), $call->arguments);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testSet()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->set('k', 'foo');
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('set', $call->name);
+ $this->assertSame(array('key' => 'k', 'value' => 'foo', 'ttl' => null), $call->arguments);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+
+ public function testSetMultiple()
+ {
+ $pool = $this->createSimpleCache();
+ $pool->setMultiple(array('k' => 'foo'));
+ $calls = $pool->getCalls();
+ $this->assertCount(1, $calls);
+
+ $call = $calls[0];
+ $this->assertSame('setMultiple', $call->name);
+ $this->assertSame(array('values' => array('k' => 'foo'), 'ttl' => null), $call->arguments);
+ $this->assertSame(0, $call->hits);
+ $this->assertSame(0, $call->misses);
+ $this->assertNotEmpty($call->start);
+ $this->assertNotEmpty($call->end);
+ }
+}
diff --git a/src/Symfony/Component/Cache/Traits/ApcuTrait.php b/src/Symfony/Component/Cache/Traits/ApcuTrait.php
index f0ca04d76b..578aee881e 100644
--- a/src/Symfony/Component/Cache/Traits/ApcuTrait.php
+++ b/src/Symfony/Component/Cache/Traits/ApcuTrait.php
@@ -26,7 +26,7 @@ trait ApcuTrait
return function_exists('apcu_fetch') && ini_get('apc.enabled') && !('cli' === PHP_SAPI && !ini_get('apc.enable_cli'));
}
- public function __construct($namespace = '', $defaultLifetime = 0, $version = null)
+ private function init($namespace, $defaultLifetime, $version)
{
if (!static::isSupported()) {
throw new CacheException('APCu is not enabled');
diff --git a/src/Symfony/Component/Cache/Traits/DoctrineTrait.php b/src/Symfony/Component/Cache/Traits/DoctrineTrait.php
index 3655af3bcf..be351cf53a 100644
--- a/src/Symfony/Component/Cache/Traits/DoctrineTrait.php
+++ b/src/Symfony/Component/Cache/Traits/DoctrineTrait.php
@@ -11,8 +11,6 @@
namespace Symfony\Component\Cache\Traits;
-use Doctrine\Common\Cache\CacheProvider;
-
/**
* @author Nicolas Grekas
*
@@ -22,13 +20,6 @@ trait DoctrineTrait
{
private $provider;
- public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
- {
- parent::__construct('', $defaultLifetime);
- $this->provider = $provider;
- $provider->setNamespace($namespace);
- }
-
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Component/Cache/Traits/FilesystemTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemTrait.php
index a06c964adb..1db720452f 100644
--- a/src/Symfony/Component/Cache/Traits/FilesystemTrait.php
+++ b/src/Symfony/Component/Cache/Traits/FilesystemTrait.php
@@ -22,12 +22,6 @@ trait FilesystemTrait
{
use FilesystemCommonTrait;
- public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
- {
- parent::__construct('', $defaultLifetime);
- $this->init($namespace, $directory);
- }
-
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
index 957595e2cb..ac5c385f9f 100644
--- a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
+++ b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
@@ -35,7 +35,7 @@ trait MemcachedTrait
return extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
}
- public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0)
+ private function init(\Memcached $client, $namespace, $defaultLifetime)
{
if (!static::isSupported()) {
throw new CacheException('Memcached >= 2.2.0 is required');
diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php
index 90796e0153..08b55ab72c 100644
--- a/src/Symfony/Component/Cache/Traits/PdoTrait.php
+++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php
@@ -35,33 +35,7 @@ trait PdoTrait
private $password = '';
private $connectionOptions = array();
- /**
- * Constructor.
- *
- * You can either pass an existing database connection as PDO instance or
- * a Doctrine DBAL Connection or a DSN string that will be used to
- * lazy-connect to the database when the cache is actually used.
- *
- * List of available options:
- * * db_table: The name of the table [default: cache_items]
- * * db_id_col: The column where to store the cache id [default: item_id]
- * * db_data_col: The column where to store the cache data [default: item_data]
- * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime]
- * * db_time_col: The column where to store the timestamp [default: item_time]
- * * db_username: The username when lazy-connect [default: '']
- * * db_password: The password when lazy-connect [default: '']
- * * db_connection_options: An array of driver-specific connection options [default: array()]
- *
- * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null
- * @param string $namespace
- * @param int $defaultLifetime
- * @param array $options An associative array of options
- *
- * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string
- * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION
- * @throws InvalidArgumentException When namespace contains invalid characters
- */
- public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = array())
+ private function init($connOrDsn, $namespace, $defaultLifetime, array $options)
{
if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
diff --git a/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php b/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php
index d83587e3bc..f915cd46c8 100644
--- a/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php
+++ b/src/Symfony/Component/Cache/Traits/PhpFilesTrait.php
@@ -31,18 +31,6 @@ trait PhpFilesTrait
return function_exists('opcache_compile_file') && ini_get('opcache.enable');
}
- public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
- {
- if (!static::isSupported()) {
- throw new CacheException('OPcache is not enabled');
- }
- parent::__construct('', $defaultLifetime);
- $this->init($namespace, $directory);
-
- $e = new \Exception();
- $this->includeHandler = function () use ($e) { throw $e; };
- }
-
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php
index 4ca468a68f..803e3aa93e 100644
--- a/src/Symfony/Component/Cache/Traits/RedisTrait.php
+++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php
@@ -37,7 +37,7 @@ trait RedisTrait
/**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
*/
- public function __construct($redisClient, $namespace = '', $defaultLifetime = 0)
+ public function init($redisClient, $namespace = '', $defaultLifetime = 0)
{
parent::__construct($namespace, $defaultLifetime);