[Cache] Create PSR-16 variants of all PSR-6 adapters
This commit is contained in:
parent
99ae9d6a35
commit
6219dd6b62
24
src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
Normal file
24
src/Symfony/Component/Cache/Adapter/ApcuAdapter.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
27
src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php
Normal file
27
src/Symfony/Component/Cache/Adapter/DoctrineAdapter.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
25
src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
Normal file
25
src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
26
src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
Normal file
26
src/Symfony/Component/Cache/Adapter/MemcachedAdapter.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
52
src/Symfony/Component/Cache/Adapter/PdoAdapter.php
Normal file
52
src/Symfony/Component/Cache/Adapter/PdoAdapter.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
32
src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
Normal file
32
src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?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\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; };
|
||||||
|
}
|
||||||
|
}
|
27
src/Symfony/Component/Cache/Adapter/RedisAdapter.php
Normal file
27
src/Symfony/Component/Cache/Adapter/RedisAdapter.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,14 @@
|
|||||||
CHANGELOG
|
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
|
3.2.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
177
src/Symfony/Component/Cache/Simple/AbstractCache.php
Normal file
177
src/Symfony/Component/Cache/Simple/AbstractCache.php
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<?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\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 <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
src/Symfony/Component/Cache/Simple/ApcuCache.php
Normal file
24
src/Symfony/Component/Cache/Simple/ApcuCache.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
147
src/Symfony/Component/Cache/Simple/ArrayCache.php
Normal file
147
src/Symfony/Component/Cache/Simple/ArrayCache.php
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?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\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 <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
}
|
222
src/Symfony/Component/Cache/Simple/ChainCache.php
Normal file
222
src/Symfony/Component/Cache/Simple/ChainCache.php
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
<?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\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 <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
27
src/Symfony/Component/Cache/Simple/DoctrineCache.php
Normal file
27
src/Symfony/Component/Cache/Simple/DoctrineCache.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
25
src/Symfony/Component/Cache/Simple/FilesystemCache.php
Normal file
25
src/Symfony/Component/Cache/Simple/FilesystemCache.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
26
src/Symfony/Component/Cache/Simple/MemcachedCache.php
Normal file
26
src/Symfony/Component/Cache/Simple/MemcachedCache.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
86
src/Symfony/Component/Cache/Simple/NullCache.php
Normal file
86
src/Symfony/Component/Cache/Simple/NullCache.php
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<?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\Simple;
|
||||||
|
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
52
src/Symfony/Component/Cache/Simple/PdoCache.php
Normal file
52
src/Symfony/Component/Cache/Simple/PdoCache.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
256
src/Symfony/Component/Cache/Simple/PhpArrayCache.php
Normal file
256
src/Symfony/Component/Cache/Simple/PhpArrayCache.php
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
<?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\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 <galopintitouan@gmail.com>
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
src/Symfony/Component/Cache/Simple/PhpFilesCache.php
Normal file
32
src/Symfony/Component/Cache/Simple/PhpFilesCache.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?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\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; };
|
||||||
|
}
|
||||||
|
}
|
27
src/Symfony/Component/Cache/Simple/RedisCache.php
Normal file
27
src/Symfony/Component/Cache/Simple/RedisCache.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
190
src/Symfony/Component/Cache/Simple/TraceableCache.php
Normal file
190
src/Symfony/Component/Cache/Simple/TraceableCache.php
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<?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\Simple;
|
||||||
|
|
||||||
|
use Psr\SimpleCache\CacheInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An adapter that collects data about all cache calls.
|
||||||
|
*
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
@ -48,7 +48,7 @@ class ApcuAdapterTest extends AdapterTestCase
|
|||||||
|
|
||||||
public function testVersion()
|
public function testVersion()
|
||||||
{
|
{
|
||||||
$namespace = str_replace('\\', '.', __CLASS__);
|
$namespace = str_replace('\\', '.', get_class($this));
|
||||||
|
|
||||||
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
|
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class MemcachedAdapterTest extends AdapterTestCase
|
|||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
||||||
);
|
);
|
||||||
|
|
||||||
private static $client;
|
protected static $client;
|
||||||
|
|
||||||
public static function setupBeforeClass()
|
public static function setupBeforeClass()
|
||||||
{
|
{
|
||||||
|
@ -51,7 +51,7 @@ class PhpArrayAdapterTest extends AdapterTestCase
|
|||||||
'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
|
'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
|
||||||
);
|
);
|
||||||
|
|
||||||
private static $file;
|
protected static $file;
|
||||||
|
|
||||||
public static function setupBeforeClass()
|
public static function setupBeforeClass()
|
||||||
{
|
{
|
||||||
|
@ -25,10 +25,9 @@ class PhpArrayAdapterWithFallbackTest extends AdapterTestCase
|
|||||||
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
||||||
'testDeleteItemInvalidKeys' => '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.',
|
'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()
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Cache\Tests\Adapter;
|
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\Adapter\SimpleCacheAdapter;
|
||||||
use Symfony\Component\Cache\Simple\Psr6Cache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group time-sensitive
|
* @group time-sensitive
|
||||||
@ -22,6 +21,6 @@ class SimpleCacheAdapterTest extends AdapterTestCase
|
|||||||
{
|
{
|
||||||
public function createCachePool($defaultLifetime = 0)
|
public function createCachePool($defaultLifetime = 0)
|
||||||
{
|
{
|
||||||
return new SimpleCacheAdapter(new Psr6Cache(new FilesystemAdapter()), '', $defaultLifetime);
|
return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(1, $calls);
|
$this->assertCount(1, $calls);
|
||||||
|
|
||||||
$call = $calls[0];
|
$call = $calls[0];
|
||||||
$this->assertEquals('getItem', $call->name);
|
$this->assertSame('getItem', $call->name);
|
||||||
$this->assertEquals('k', $call->argument);
|
$this->assertSame('k', $call->argument);
|
||||||
$this->assertEquals(0, $call->hits);
|
$this->assertSame(0, $call->hits);
|
||||||
$this->assertEquals(1, $call->misses);
|
$this->assertSame(1, $call->misses);
|
||||||
$this->assertNull($call->result);
|
$this->assertNull($call->result);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
@ -51,8 +51,8 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(3, $calls);
|
$this->assertCount(3, $calls);
|
||||||
|
|
||||||
$call = $calls[2];
|
$call = $calls[2];
|
||||||
$this->assertEquals(1, $call->hits);
|
$this->assertSame(1, $call->hits);
|
||||||
$this->assertEquals(0, $call->misses);
|
$this->assertSame(0, $call->misses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetItemsMiss()
|
public function testGetItemsMiss()
|
||||||
@ -66,9 +66,9 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(1, $calls);
|
$this->assertCount(1, $calls);
|
||||||
|
|
||||||
$call = $calls[0];
|
$call = $calls[0];
|
||||||
$this->assertEquals('getItems', $call->name);
|
$this->assertSame('getItems', $call->name);
|
||||||
$this->assertEquals($arg, $call->argument);
|
$this->assertSame($arg, $call->argument);
|
||||||
$this->assertEquals(2, $call->misses);
|
$this->assertSame(2, $call->misses);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
}
|
}
|
||||||
@ -81,8 +81,8 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(1, $calls);
|
$this->assertCount(1, $calls);
|
||||||
|
|
||||||
$call = $calls[0];
|
$call = $calls[0];
|
||||||
$this->assertEquals('hasItem', $call->name);
|
$this->assertSame('hasItem', $call->name);
|
||||||
$this->assertEquals('k', $call->argument);
|
$this->assertSame('k', $call->argument);
|
||||||
$this->assertFalse($call->result);
|
$this->assertFalse($call->result);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
@ -98,8 +98,8 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(3, $calls);
|
$this->assertCount(3, $calls);
|
||||||
|
|
||||||
$call = $calls[2];
|
$call = $calls[2];
|
||||||
$this->assertEquals('hasItem', $call->name);
|
$this->assertSame('hasItem', $call->name);
|
||||||
$this->assertEquals('k', $call->argument);
|
$this->assertSame('k', $call->argument);
|
||||||
$this->assertTrue($call->result);
|
$this->assertTrue($call->result);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
@ -113,10 +113,10 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(1, $calls);
|
$this->assertCount(1, $calls);
|
||||||
|
|
||||||
$call = $calls[0];
|
$call = $calls[0];
|
||||||
$this->assertEquals('deleteItem', $call->name);
|
$this->assertSame('deleteItem', $call->name);
|
||||||
$this->assertEquals('k', $call->argument);
|
$this->assertSame('k', $call->argument);
|
||||||
$this->assertEquals(0, $call->hits);
|
$this->assertSame(0, $call->hits);
|
||||||
$this->assertEquals(0, $call->misses);
|
$this->assertSame(0, $call->misses);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
}
|
}
|
||||||
@ -130,10 +130,10 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(1, $calls);
|
$this->assertCount(1, $calls);
|
||||||
|
|
||||||
$call = $calls[0];
|
$call = $calls[0];
|
||||||
$this->assertEquals('deleteItems', $call->name);
|
$this->assertSame('deleteItems', $call->name);
|
||||||
$this->assertEquals($arg, $call->argument);
|
$this->assertSame($arg, $call->argument);
|
||||||
$this->assertEquals(0, $call->hits);
|
$this->assertSame(0, $call->hits);
|
||||||
$this->assertEquals(0, $call->misses);
|
$this->assertSame(0, $call->misses);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
}
|
}
|
||||||
@ -147,10 +147,10 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(2, $calls);
|
$this->assertCount(2, $calls);
|
||||||
|
|
||||||
$call = $calls[1];
|
$call = $calls[1];
|
||||||
$this->assertEquals('save', $call->name);
|
$this->assertSame('save', $call->name);
|
||||||
$this->assertEquals($item, $call->argument);
|
$this->assertSame($item, $call->argument);
|
||||||
$this->assertEquals(0, $call->hits);
|
$this->assertSame(0, $call->hits);
|
||||||
$this->assertEquals(0, $call->misses);
|
$this->assertSame(0, $call->misses);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
}
|
}
|
||||||
@ -164,10 +164,10 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(2, $calls);
|
$this->assertCount(2, $calls);
|
||||||
|
|
||||||
$call = $calls[1];
|
$call = $calls[1];
|
||||||
$this->assertEquals('saveDeferred', $call->name);
|
$this->assertSame('saveDeferred', $call->name);
|
||||||
$this->assertEquals($item, $call->argument);
|
$this->assertSame($item, $call->argument);
|
||||||
$this->assertEquals(0, $call->hits);
|
$this->assertSame(0, $call->hits);
|
||||||
$this->assertEquals(0, $call->misses);
|
$this->assertSame(0, $call->misses);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
}
|
}
|
||||||
@ -180,10 +180,10 @@ class TraceableAdapterTest extends AdapterTestCase
|
|||||||
$this->assertCount(1, $calls);
|
$this->assertCount(1, $calls);
|
||||||
|
|
||||||
$call = $calls[0];
|
$call = $calls[0];
|
||||||
$this->assertEquals('commit', $call->name);
|
$this->assertSame('commit', $call->name);
|
||||||
$this->assertNull(null, $call->argument);
|
$this->assertNull(null, $call->argument);
|
||||||
$this->assertEquals(0, $call->hits);
|
$this->assertSame(0, $call->hits);
|
||||||
$this->assertEquals(0, $call->misses);
|
$this->assertSame(0, $call->misses);
|
||||||
$this->assertNotEmpty($call->start);
|
$this->assertNotEmpty($call->start);
|
||||||
$this->assertNotEmpty($call->end);
|
$this->assertNotEmpty($call->end);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<?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\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;
|
||||||
|
}
|
||||||
|
}
|
35
src/Symfony/Component/Cache/Tests/Simple/ApcuCacheTest.php
Normal file
35
src/Symfony/Component/Cache/Tests/Simple/ApcuCacheTest.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
25
src/Symfony/Component/Cache/Tests/Simple/ArrayCacheTest.php
Normal file
25
src/Symfony/Component/Cache/Tests/Simple/ArrayCacheTest.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?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\Tests\Simple;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Simple\ArrayCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group time-sensitive
|
||||||
|
*/
|
||||||
|
class ArrayCacheTest extends CacheTestCase
|
||||||
|
{
|
||||||
|
public function createSimpleCache($defaultLifetime = 0)
|
||||||
|
{
|
||||||
|
return new ArrayCache($defaultLifetime);
|
||||||
|
}
|
||||||
|
}
|
66
src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
Normal file
66
src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?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\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__);
|
||||||
|
}
|
||||||
|
}
|
45
src/Symfony/Component/Cache/Tests/Simple/ChainCacheTest.php
Normal file
45
src/Symfony/Component/Cache/Tests/Simple/ChainCacheTest.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?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\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()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
<?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\Tests\Simple;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Simple\FilesystemCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group time-sensitive
|
||||||
|
*/
|
||||||
|
class FilesystemCacheTest extends CacheTestCase
|
||||||
|
{
|
||||||
|
public function createSimpleCache($defaultLifetime = 0)
|
||||||
|
{
|
||||||
|
return new FilesystemCache('', $defaultLifetime);
|
||||||
|
}
|
||||||
|
}
|
165
src/Symfony/Component/Cache/Tests/Simple/MemcachedCacheTest.php
Normal file
165
src/Symfony/Component/Cache/Tests/Simple/MemcachedCacheTest.php
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<?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\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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
src/Symfony/Component/Cache/Tests/Simple/NullCacheTest.php
Normal file
95
src/Symfony/Component/Cache/Tests/Simple/NullCacheTest.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?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\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'));
|
||||||
|
}
|
||||||
|
}
|
44
src/Symfony/Component/Cache/Tests/Simple/PdoCacheTest.php
Normal file
44
src/Symfony/Component/Cache/Tests/Simple/PdoCacheTest.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
139
src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php
Normal file
139
src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?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\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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
<?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\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));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
<?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\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');
|
||||||
|
}
|
||||||
|
}
|
26
src/Symfony/Component/Cache/Tests/Simple/Psr6CacheTest.php
Normal file
26
src/Symfony/Component/Cache/Tests/Simple/Psr6CacheTest.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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\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));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?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\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));
|
||||||
|
}
|
||||||
|
}
|
82
src/Symfony/Component/Cache/Tests/Simple/RedisCacheTest.php
Normal file
82
src/Symfony/Component/Cache/Tests/Simple/RedisCacheTest.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?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\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://'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
170
src/Symfony/Component/Cache/Tests/Simple/TraceableCacheTest.php
Normal file
170
src/Symfony/Component/Cache/Tests/Simple/TraceableCacheTest.php
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?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\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);
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ trait ApcuTrait
|
|||||||
return function_exists('apcu_fetch') && ini_get('apc.enabled') && !('cli' === PHP_SAPI && !ini_get('apc.enable_cli'));
|
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()) {
|
if (!static::isSupported()) {
|
||||||
throw new CacheException('APCu is not enabled');
|
throw new CacheException('APCu is not enabled');
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Cache\Traits;
|
namespace Symfony\Component\Cache\Traits;
|
||||||
|
|
||||||
use Doctrine\Common\Cache\CacheProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Nicolas Grekas <p@tchwork.com>
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
*
|
*
|
||||||
@ -22,13 +20,6 @@ trait DoctrineTrait
|
|||||||
{
|
{
|
||||||
private $provider;
|
private $provider;
|
||||||
|
|
||||||
public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
parent::__construct('', $defaultLifetime);
|
|
||||||
$this->provider = $provider;
|
|
||||||
$provider->setNamespace($namespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -22,12 +22,6 @@ trait FilesystemTrait
|
|||||||
{
|
{
|
||||||
use FilesystemCommonTrait;
|
use FilesystemCommonTrait;
|
||||||
|
|
||||||
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
|
|
||||||
{
|
|
||||||
parent::__construct('', $defaultLifetime);
|
|
||||||
$this->init($namespace, $directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -35,7 +35,7 @@ trait MemcachedTrait
|
|||||||
return extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>=');
|
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()) {
|
if (!static::isSupported()) {
|
||||||
throw new CacheException('Memcached >= 2.2.0 is required');
|
throw new CacheException('Memcached >= 2.2.0 is required');
|
||||||
|
@ -35,33 +35,7 @@ trait PdoTrait
|
|||||||
private $password = '';
|
private $password = '';
|
||||||
private $connectionOptions = array();
|
private $connectionOptions = array();
|
||||||
|
|
||||||
/**
|
private function init($connOrDsn, $namespace, $defaultLifetime, array $options)
|
||||||
* 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())
|
|
||||||
{
|
{
|
||||||
if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) {
|
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]));
|
throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0]));
|
||||||
|
@ -31,18 +31,6 @@ trait PhpFilesTrait
|
|||||||
return function_exists('opcache_compile_file') && ini_get('opcache.enable');
|
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}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,7 @@ trait RedisTrait
|
|||||||
/**
|
/**
|
||||||
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
|
* @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);
|
parent::__construct($namespace, $defaultLifetime);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user