Rajout du code core qui n'était pas gitté

This commit is contained in:
2020-05-08 20:00:41 +02:00
parent 4821ab2b5e
commit 096d58ea33
1654 changed files with 615177 additions and 0 deletions

3
core/vendor/symfony/cache/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
composer.lock
phpunit.xml
vendor/

View File

@@ -0,0 +1,376 @@
<?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 Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
private $namespace;
private $deferred = array();
private $createCacheItem;
private $mergeByLifetime;
protected function __construct($namespace = '', $defaultLifetime = 0)
{
$this->namespace = '' === $namespace ? '' : $this->getId($namespace);
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
$item->defaultLifetime = $defaultLifetime;
return $item;
},
$this,
CacheItem::class
);
$this->mergeByLifetime = \Closure::bind(
function ($deferred, $namespace, &$expiredIds) {
$byLifetime = array();
$now = time();
$expiredIds = array();
foreach ($deferred as $key => $item) {
if (null === $item->expiry) {
$byLifetime[0][$namespace.$key] = $item->value;
} elseif ($item->expiry > $now) {
$byLifetime[$item->expiry - $now][$namespace.$key] = $item->value;
} else {
$expiredIds[] = $namespace.$key;
}
}
return $byLifetime;
},
$this,
CacheItem::class
);
}
public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
{
$fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory);
if (null !== $logger) {
$fs->setLogger($logger);
}
if (!ApcuAdapter::isSupported()) {
return $fs;
}
$apcu = new ApcuAdapter($namespace, $defaultLifetime / 5, $version);
if (null !== $logger) {
$apcu->setLogger($logger);
}
return new ChainAdapter(array($apcu, $fs));
}
/**
* Fetches several cache items.
*
* @param array $ids The cache identifiers to fetch.
*
* @return array|\Traversable The corresponding values found in the cache.
*/
abstract protected function doFetch(array $ids);
/**
* Confirms if the cache contains specified cache item.
*
* @param string $id The identifier for which to check existence.
*
* @return bool True if item exists in the cache, false otherwise.
*/
abstract protected function doHave($id);
/**
* Deletes all items in the pool.
*
* @param string The prefix used for all identifiers managed by this pool.
*
* @return bool True if the pool was successfully cleared, false otherwise.
*/
abstract protected function doClear($namespace);
/**
* Removes multiple items from the pool.
*
* @param array $ids An array of identifiers that should be removed from the pool.
*
* @return bool True if the items were successfully removed, false otherwise.
*/
abstract protected function doDelete(array $ids);
/**
* Persists several cache items immediately.
*
* @param array $values The values to cache, indexed by their cache identifier.
* @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning.
*
* @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not.
*/
abstract protected function doSave(array $values, $lifetime);
/**
* {@inheritdoc}
*/
public function getItem($key)
{
if ($this->deferred) {
$this->commit();
}
$id = $this->getId($key);
$f = $this->createCacheItem;
$isHit = false;
$value = null;
try {
foreach ($this->doFetch(array($id)) as $value) {
$isHit = true;
}
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch key "{key}"', array('key' => $key, 'exception' => $e));
}
return $f($key, $value, $isHit);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
if ($this->deferred) {
$this->commit();
}
$ids = array();
foreach ($keys as $key) {
$ids[] = $this->getId($key);
}
try {
$items = $this->doFetch($ids);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to fetch requested items', array('keys' => $keys, 'exception' => $e));
$items = array();
}
$ids = array_combine($ids, $keys);
return $this->generateItems($items, $ids);
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
$id = $this->getId($key);
if (isset($this->deferred[$key])) {
$this->commit();
}
try {
return $this->doHave($id);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', array('key' => $key, 'exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->deferred = array();
try {
return $this->doClear($this->namespace);
} catch (\Exception $e) {
CacheItem::log($this->logger, 'Failed to clear the cache', array('exception' => $e));
return false;
}
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->deleteItems(array($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$ids = array();
foreach ($keys as $key) {
$ids[$key] = $this->getId($key);
unset($this->deferred[$key]);
}
try {
if ($this->doDelete($ids)) {
return true;
}
} catch (\Exception $e) {
}
$ok = true;
// When bulk-delete failed, retry each item individually
foreach ($ids as $key => $id) {
try {
$e = null;
if ($this->doDelete(array($id))) {
continue;
}
} catch (\Exception $e) {
}
CacheItem::log($this->logger, 'Failed to delete key "{key}"', array('key' => $key, 'exception' => $e));
$ok = false;
}
return $ok;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
if ($this->deferred) {
$this->commit();
}
$this->deferred[$item->getKey()] = $item;
return $this->commit();
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$this->deferred[$item->getKey()] = $item;
return true;
}
/**
* {@inheritdoc}
*/
public function commit()
{
$ok = true;
$byLifetime = $this->mergeByLifetime;
$byLifetime = $byLifetime($this->deferred, $this->namespace, $expiredIds);
$retry = $this->deferred = array();
if ($expiredIds) {
$this->doDelete($expiredIds);
}
foreach ($byLifetime as $lifetime => $values) {
try {
$e = $this->doSave($values, $lifetime);
} catch (\Exception $e) {
}
if (true === $e || array() === $e) {
continue;
}
if (is_array($e) || 1 === count($values)) {
foreach (is_array($e) ? $e : array_keys($values) as $id) {
$ok = false;
$v = $values[$id];
$type = is_object($v) ? get_class($v) : gettype($v);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => substr($id, strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
}
} else {
foreach ($values as $id => $v) {
$retry[$lifetime][] = $id;
}
}
}
// When bulk-save failed, retry each item individually
foreach ($retry as $lifetime => $ids) {
foreach ($ids as $id) {
try {
$v = $byLifetime[$lifetime][$id];
$e = $this->doSave(array($id => $v), $lifetime);
} catch (\Exception $e) {
}
if (true === $e || array() === $e) {
continue;
}
$ok = false;
$type = is_object($v) ? get_class($v) : gettype($v);
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => substr($id, strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
}
}
return $ok;
}
public function __destruct()
{
if ($this->deferred) {
$this->commit();
}
}
private function getId($key)
{
CacheItem::validateKey($key);
return $this->namespace.$key;
}
private function generateItems($items, &$keys)
{
$f = $this->createCacheItem;
foreach ($items as $id => $value) {
yield $keys[$id] => $f($keys[$id], $value, true);
unset($keys[$id]);
}
foreach ($keys as $key) {
yield $key => $f($key, null, false);
}
}
}

View 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 Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
/**
* Interface for adapters managing instances of Symfony's {@see CacheItem}.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
interface AdapterInterface extends CacheItemPoolInterface
{
}

View File

@@ -0,0 +1,103 @@
<?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\CacheItem;
use Symfony\Component\Cache\Exception\CacheException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ApcuAdapter extends AbstractAdapter
{
public static function isSupported()
{
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)
{
if (!static::isSupported()) {
throw new CacheException('APCu is not enabled');
}
if ('cli' === PHP_SAPI) {
ini_set('apc.use_request_time', 0);
}
parent::__construct($namespace, $defaultLifetime);
if (null !== $version) {
CacheItem::validateKey($version);
if (!apcu_exists($version.':'.$namespace)) {
$this->clear($namespace);
apcu_add($version.':'.$namespace, null);
}
}
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
return apcu_fetch($ids);
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return apcu_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
return isset($namespace[0]) && class_exists('APCuIterator', false)
? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), APC_ITER_KEY))
: apcu_clear_cache();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
foreach ($ids as $id) {
apcu_delete($id);
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
try {
return array_keys(apcu_store($values, null, $lifetime));
} catch (\Error $e) {
} catch (\Exception $e) {
}
if (1 === count($values)) {
// Workaround https://github.com/krakjoe/apcu/issues/170
apcu_delete(key($values));
}
throw $e;
}
}

View File

@@ -0,0 +1,193 @@
<?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 Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
private $storeSerialized;
private $values = array();
private $expiries = array();
private $createCacheItem;
/**
* @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->storeSerialized = $storeSerialized;
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
$item->defaultLifetime = $defaultLifetime;
return $item;
},
$this,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
if (!$isHit = $this->hasItem($key)) {
$value = null;
} elseif ($this->storeSerialized) {
$value = unserialize($this->values[$key]);
} else {
$value = $this->values[$key];
}
$f = $this->createCacheItem;
return $f($key, $value, $isHit);
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
foreach ($keys as $key) {
CacheItem::validateKey($key);
}
return $this->generateItems($keys, time());
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
CacheItem::validateKey($key);
return isset($this->expiries[$key]) && ($this->expiries[$key] >= time() || !$this->deleteItem($key));
}
/**
* {@inheritdoc}
*/
public function clear()
{
$this->values = $this->expiries = array();
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
CacheItem::validateKey($key);
unset($this->values[$key], $this->expiries[$key]);
return true;
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
foreach ($keys as $key) {
$this->deleteItem($key);
}
return true;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
if (!$item instanceof CacheItem) {
return false;
}
$item = (array) $item;
$key = $item[CacheItem::CAST_PREFIX.'key'];
$value = $item[CacheItem::CAST_PREFIX.'value'];
$expiry = $item[CacheItem::CAST_PREFIX.'expiry'];
if (null !== $expiry && $expiry <= time()) {
$this->deleteItem($key);
return true;
}
if ($this->storeSerialized) {
try {
$value = 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;
}
}
$this->values[$key] = $value;
$this->expiries[$key] = null !== $expiry ? $expiry : PHP_INT_MAX;
return true;
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
return $this->save($item);
}
/**
* {@inheritdoc}
*/
public function commit()
{
return true;
}
private function generateItems(array $keys, $now)
{
$f = $this->createCacheItem;
foreach ($keys as $key) {
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
$value = null;
} elseif ($this->storeSerialized) {
$value = unserialize($this->values[$key]);
} else {
$value = $this->values[$key];
}
yield $key => $f($key, $value, $isHit);
}
}
}

View File

@@ -0,0 +1,226 @@
<?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 Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* Chains several adapters together.
*
* Cached items are fetched from the first adapter having them in its data store.
* They are saved and deleted in all adapters at once.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ChainAdapter implements AdapterInterface
{
private $adapters = array();
private $saveUp;
/**
* @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items
* @param int $maxLifetime The max lifetime of items propagated from lower adapters to upper ones
*/
public function __construct(array $adapters, $maxLifetime = 0)
{
if (!$adapters) {
throw new InvalidArgumentException('At least one adapter must be specified.');
}
foreach ($adapters as $adapter) {
if (!$adapter instanceof CacheItemPoolInterface) {
throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', get_class($adapter), CacheItemPoolInterface::class));
}
if ($adapter instanceof AdapterInterface) {
$this->adapters[] = $adapter;
} else {
$this->adapters[] = new ProxyAdapter($adapter);
}
}
$this->saveUp = \Closure::bind(
function ($adapter, $item) use ($maxLifetime) {
$origDefaultLifetime = $item->defaultLifetime;
if (0 < $maxLifetime && ($origDefaultLifetime <= 0 || $maxLifetime < $origDefaultLifetime)) {
$item->defaultLifetime = $maxLifetime;
}
$adapter->save($item);
$item->defaultLifetime = $origDefaultLifetime;
},
$this,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$saveUp = $this->saveUp;
foreach ($this->adapters as $i => $adapter) {
$item = $adapter->getItem($key);
if ($item->isHit()) {
while (0 <= --$i) {
$saveUp($this->adapters[$i], $item);
}
return $item;
}
}
return $item;
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
return $this->generateItems($this->adapters[0]->getItems($keys), 0);
}
private function generateItems($items, $adapterIndex)
{
$missing = array();
$nextAdapterIndex = $adapterIndex + 1;
$nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null;
foreach ($items as $k => $item) {
if (!$nextAdapter || $item->isHit()) {
yield $k => $item;
} else {
$missing[] = $k;
}
}
if ($missing) {
$saveUp = $this->saveUp;
$adapter = $this->adapters[$adapterIndex];
$items = $this->generateItems($nextAdapter->getItems($missing), $nextAdapterIndex);
foreach ($items as $k => $item) {
if ($item->isHit()) {
$saveUp($adapter, $item);
}
yield $k => $item;
}
}
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
foreach ($this->adapters as $adapter) {
if ($adapter->hasItem($key)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function clear()
{
$cleared = true;
foreach ($this->adapters as $adapter) {
$cleared = $adapter->clear() && $cleared;
}
return $cleared;
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
$deleted = true;
foreach ($this->adapters as $adapter) {
$deleted = $adapter->deleteItem($key) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
$deleted = true;
foreach ($this->adapters as $adapter) {
$deleted = $adapter->deleteItems($keys) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
$saved = true;
foreach ($this->adapters as $adapter) {
$saved = $adapter->save($item) && $saved;
}
return $saved;
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
$saved = true;
foreach ($this->adapters as $adapter) {
$saved = $adapter->saveDeferred($item) && $saved;
}
return $saved;
}
/**
* {@inheritdoc}
*/
public function commit()
{
$committed = true;
foreach ($this->adapters as $adapter) {
$committed = $adapter->commit() && $committed;
}
return $committed;
}
}

View File

@@ -0,0 +1,78 @@
<?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;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DoctrineAdapter extends AbstractAdapter
{
private $provider;
public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0)
{
parent::__construct('', $defaultLifetime);
$this->provider = $provider;
$provider->setNamespace($namespace);
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
return $this->provider->fetchMultiple($ids);
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return $this->provider->contains($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$namespace = $this->provider->getNamespace();
return isset($namespace[0])
? $this->provider->deleteAll()
: $this->provider->flushAll();
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$ok = true;
foreach ($ids as $id) {
$ok = $this->provider->delete($id) && $ok;
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
return $this->provider->saveMultiple($values, $lifetime);
}
}

View File

@@ -0,0 +1,158 @@
<?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\InvalidArgumentException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class FilesystemAdapter extends AbstractAdapter
{
private $directory;
public function __construct($namespace = '', $defaultLifetime = 0, $directory = null)
{
parent::__construct('', $defaultLifetime);
if (!isset($directory[0])) {
$directory = sys_get_temp_dir().'/symfony-cache';
}
if (isset($namespace[0])) {
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('FilesystemAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
}
$directory .= '/'.$namespace;
}
if (!file_exists($dir = $directory.'/.')) {
@mkdir($directory, 0777, true);
}
if (false === $dir = realpath($dir)) {
throw new InvalidArgumentException(sprintf('Cache directory does not exist (%s)', $directory));
}
if (!is_writable($dir .= DIRECTORY_SEPARATOR)) {
throw new InvalidArgumentException(sprintf('Cache directory is not writable (%s)', $directory));
}
// On Windows the whole path is limited to 258 chars
if ('\\' === DIRECTORY_SEPARATOR && strlen($dir) > 234) {
throw new InvalidArgumentException(sprintf('Cache directory too long (%s)', $directory));
}
$this->directory = $dir;
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$values = array();
$now = time();
foreach ($ids as $id) {
$file = $this->getFile($id);
if (!$h = @fopen($file, 'rb')) {
continue;
}
if ($now >= (int) $expiresAt = fgets($h)) {
fclose($h);
if (isset($expiresAt[0])) {
@unlink($file);
}
} else {
$i = rawurldecode(rtrim(fgets($h)));
$value = stream_get_contents($h);
fclose($h);
if ($i === $id) {
$values[$id] = unserialize($value);
}
}
}
return $values;
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
$file = $this->getFile($id);
return file_exists($file) && (@filemtime($file) > time() || $this->doFetch(array($id)));
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
$ok = true;
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
$ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok;
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
$ok = true;
foreach ($ids as $id) {
$file = $this->getFile($id);
$ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok;
}
return $ok;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
$ok = true;
$expiresAt = $lifetime ? time() + $lifetime : PHP_INT_MAX;
$tmp = $this->directory.uniqid('', true);
foreach ($values as $id => $value) {
$file = $this->getFile($id, true);
$value = $expiresAt."\n".rawurlencode($id)."\n".serialize($value);
if (false !== @file_put_contents($tmp, $value)) {
@touch($tmp, $expiresAt);
$ok = @rename($tmp, $file) && $ok;
} else {
$ok = false;
}
}
return $ok;
}
private function getFile($id, $mkdir = false)
{
$hash = str_replace('/', '-', base64_encode(md5($id, true)));
$dir = $this->directory.$hash[0].DIRECTORY_SEPARATOR.$hash[1].DIRECTORY_SEPARATOR;
if ($mkdir && !file_exists($dir)) {
@mkdir($dir, 0777, true);
}
return $dir.substr($hash, 2, -2);
}
}

View File

@@ -0,0 +1,168 @@
<?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 Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ProxyAdapter implements AdapterInterface
{
private $pool;
private $namespace;
private $namespaceLen;
private $createCacheItem;
public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0)
{
$this->pool = $pool;
$this->namespace = '' === $namespace ? '' : $this->getId($namespace);
$this->namespaceLen = strlen($namespace);
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = $isHit;
$item->defaultLifetime = $defaultLifetime;
return $item;
},
$this,
CacheItem::class
);
}
/**
* {@inheritdoc}
*/
public function getItem($key)
{
$f = $this->createCacheItem;
$item = $this->pool->getItem($this->getId($key));
return $f($key, $item->get(), $item->isHit());
}
/**
* {@inheritdoc}
*/
public function getItems(array $keys = array())
{
if ($this->namespaceLen) {
foreach ($keys as $i => $key) {
$keys[$i] = $this->getId($key);
}
}
return $this->generateItems($this->pool->getItems($keys));
}
/**
* {@inheritdoc}
*/
public function hasItem($key)
{
return $this->pool->hasItem($this->getId($key));
}
/**
* {@inheritdoc}
*/
public function clear()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*/
public function deleteItem($key)
{
return $this->pool->deleteItem($this->getId($key));
}
/**
* {@inheritdoc}
*/
public function deleteItems(array $keys)
{
if ($this->namespaceLen) {
foreach ($keys as $i => $key) {
$keys[$i] = $this->getId($key);
}
}
return $this->pool->deleteItems($keys);
}
/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item)
{
return $this->doSave($item, __FUNCTION__);
}
/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item)
{
return $this->doSave($item, __FUNCTION__);
}
/**
* {@inheritdoc}
*/
public function commit()
{
return $this->pool->commit();
}
private function doSave(CacheItemInterface $item, $method)
{
if (!$item instanceof CacheItem) {
return false;
}
$item = (array) $item;
$expiry = $item[CacheItem::CAST_PREFIX.'expiry'];
$poolItem = $this->pool->getItem($this->namespace.$item[CacheItem::CAST_PREFIX.'key']);
$poolItem->set($item[CacheItem::CAST_PREFIX.'value']);
$poolItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null);
return $this->pool->$method($poolItem);
}
private function generateItems($items)
{
$f = $this->createCacheItem;
foreach ($items as $key => $item) {
if ($this->namespaceLen) {
$key = substr($key, $this->namespaceLen);
}
yield $key => $f($key, $item->get(), $item->isHit());
}
}
private function getId($key)
{
CacheItem::validateKey($key);
return $this->namespace.$key;
}
}

View File

@@ -0,0 +1,294 @@
<?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 Predis\Connection\Factory;
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Aggregate\RedisCluster;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Aurimas Niekis <aurimas@niekis.lt>
* @author Nicolas Grekas <p@tchwork.com>
*/
class RedisAdapter extends AbstractAdapter
{
private static $defaultConnectionOptions = array(
'class' => null,
'persistent' => 0,
'timeout' => 0,
'read_timeout' => 0,
'retry_interval' => 0,
);
private $redis;
/**
* @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient
*/
public function __construct($redisClient, $namespace = '', $defaultLifetime = 0)
{
parent::__construct($namespace, $defaultLifetime);
if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) {
throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0]));
}
if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client) {
throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($redisClient) ? get_class($redisClient) : gettype($redisClient)));
}
$this->redis = $redisClient;
}
/**
* Creates a Redis connection using a DSN configuration.
*
* Example DSN:
* - redis://localhost
* - redis://example.com:1234
* - redis://secret@example.com/13
* - redis:///var/run/redis.sock
* - redis://secret@/var/run/redis.sock/13
*
* @param string $dsn
* @param array $options See self::$defaultConnectionOptions
*
* @throws InvalidArgumentException When the DSN is invalid.
*
* @return \Redis|\Predis\Client According to the "class" option.
*/
public static function createConnection($dsn, array $options = array())
{
if (0 !== strpos($dsn, 'redis://')) {
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis://"', $dsn));
}
$params = preg_replace_callback('#^redis://(?:([^@]*)@)?#', function ($m) use (&$auth) {
if (isset($m[1])) {
$auth = $m[1];
}
return 'file://';
}, $dsn);
if (false === $params = parse_url($params)) {
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
}
if (!isset($params['host']) && !isset($params['path'])) {
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
}
if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) {
$params['dbindex'] = $m[1];
$params['path'] = substr($params['path'], 0, -strlen($m[0]));
}
$params += array(
'host' => isset($params['host']) ? $params['host'] : $params['path'],
'port' => isset($params['host']) ? 6379 : null,
'dbindex' => 0,
);
if (isset($params['query'])) {
parse_str($params['query'], $query);
$params += $query;
}
$params += $options + self::$defaultConnectionOptions;
$class = null === $params['class'] ? (extension_loaded('redis') ? \Redis::class : \Predis\Client::class) : $params['class'];
if (is_a($class, \Redis::class, true)) {
$connect = empty($params['persistent']) ? 'connect' : 'pconnect';
$redis = new $class();
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], null, $params['retry_interval']);
if (@!$redis->isConnected()) {
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
}
if ((null !== $auth && !$redis->auth($auth))
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
) {
$e = preg_replace('/^ERR /', '', $redis->getLastError());
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
}
} elseif (is_a($class, \Predis\Client::class, true)) {
$params['scheme'] = isset($params['host']) ? 'tcp' : 'unix';
$params['database'] = $params['dbindex'] ?: null;
$params['password'] = $auth;
$redis = new $class((new Factory())->create($params));
} elseif (class_exists($class, false)) {
throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis" or "Predis\Client"', $class));
} else {
throw new InvalidArgumentException(sprintf('Class "%s" does not exist', $class));
}
return $redis;
}
/**
* {@inheritdoc}
*/
protected function doFetch(array $ids)
{
$result = array();
if ($ids) {
$values = $this->redis->mGet($ids);
$index = 0;
foreach ($ids as $id) {
if ($value = $values[$index++]) {
$result[$id] = unserialize($value);
}
}
}
return $result;
}
/**
* {@inheritdoc}
*/
protected function doHave($id)
{
return (bool) $this->redis->exists($id);
}
/**
* {@inheritdoc}
*/
protected function doClear($namespace)
{
// When using a native Redis cluster, clearing the cache cannot work and always returns false.
// Clearing the cache should then be done by any other means (e.g. by restarting the cluster).
$hosts = array($this->redis);
$evalArgs = array(array($namespace), 0);
if ($this->redis instanceof \Predis\Client) {
$evalArgs = array(0, $namespace);
$connection = $this->redis->getConnection();
if ($connection instanceof PredisCluster) {
$hosts = array();
foreach ($connection as $c) {
$hosts[] = new \Predis\Client($c);
}
} elseif ($connection instanceof RedisCluster) {
return false;
}
} elseif ($this->redis instanceof \RedisArray) {
foreach ($this->redis->_hosts() as $host) {
$hosts[] = $this->redis->_instance($host);
}
} elseif ($this->redis instanceof \RedisCluster) {
return false;
}
foreach ($hosts as $host) {
if (!isset($namespace[0])) {
$host->flushDb();
} else {
// As documented in Redis documentation (http://redis.io/commands/keys) using KEYS
// can hang your server when it is executed against large databases (millions of items).
// Whenever you hit this scale, it is advised to deploy one Redis database per cache pool
// instead of using namespaces, so that FLUSHDB is used instead.
$host->eval("local keys=redis.call('KEYS',ARGV[1]..'*') for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end", $evalArgs[0], $evalArgs[1]);
}
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doDelete(array $ids)
{
if ($ids) {
$this->redis->del($ids);
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave(array $values, $lifetime)
{
$serialized = array();
$failed = array();
foreach ($values as $id => $value) {
try {
$serialized[$id] = serialize($value);
} catch (\Exception $e) {
$failed[] = $id;
}
}
if (!$serialized) {
return $failed;
}
if (0 >= $lifetime) {
$this->redis->mSet($serialized);
return $failed;
}
$this->pipeline(function ($pipe) use (&$serialized, $lifetime) {
foreach ($serialized as $id => $value) {
$pipe('setEx', $id, array($lifetime, $value));
}
});
return $failed;
}
private function execute($command, $id, array $args, $redis = null)
{
array_unshift($args, $id);
call_user_func_array(array($redis ?: $this->redis, $command), $args);
}
private function pipeline(\Closure $callback)
{
$redis = $this->redis;
try {
if ($redis instanceof \Predis\Client) {
$redis->pipeline(function ($pipe) use ($callback) {
$this->redis = $pipe;
$callback(array($this, 'execute'));
});
} elseif ($redis instanceof \RedisArray) {
$connections = array();
$callback(function ($command, $id, $args) use (&$connections) {
if (!isset($connections[$h = $this->redis->_target($id)])) {
$connections[$h] = $this->redis->_instance($h);
$connections[$h]->multi(\Redis::PIPELINE);
}
$this->execute($command, $id, $args, $connections[$h]);
});
foreach ($connections as $c) {
$c->exec();
}
} else {
$pipe = $redis->multi(\Redis::PIPELINE);
try {
$callback(array($this, 'execute'));
} finally {
if ($pipe) {
$redis->exec();
}
}
}
} finally {
$this->redis = $redis;
}
}
}

141
core/vendor/symfony/cache/CacheItem.php vendored Normal file
View File

@@ -0,0 +1,141 @@
<?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;
use Psr\Cache\CacheItemInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
final class CacheItem implements CacheItemInterface
{
/**
* @internal
*/
const CAST_PREFIX = "\0Symfony\Component\Cache\CacheItem\0";
private $key;
private $value;
private $isHit;
private $expiry;
private $defaultLifetime;
/**
* {@inheritdoc}
*/
public function getKey()
{
return $this->key;
}
/**
* {@inheritdoc}
*/
public function get()
{
return $this->value;
}
/**
* {@inheritdoc}
*/
public function isHit()
{
return $this->isHit;
}
/**
* {@inheritdoc}
*/
public function set($value)
{
$this->value = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function expiresAt($expiration)
{
if (null === $expiration) {
$this->expiry = $this->defaultLifetime > 0 ? time() + $this->defaultLifetime : null;
} elseif ($expiration instanceof \DateTimeInterface) {
$this->expiry = (int) $expiration->format('U');
} else {
throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given', is_object($expiration) ? get_class($expiration) : gettype($expiration)));
}
return $this;
}
/**
* {@inheritdoc}
*/
public function expiresAfter($time)
{
if (null === $time) {
$this->expiry = $this->defaultLifetime > 0 ? time() + $this->defaultLifetime : null;
} elseif ($time instanceof \DateInterval) {
$this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U');
} elseif (is_int($time)) {
$this->expiry = $time + time();
} else {
throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', is_object($time) ? get_class($time) : gettype($time)));
}
return $this;
}
/**
* Validates a cache key according to PSR-6.
*
* @param string $key The key to validate.
*
* @throws InvalidArgumentException When $key is not valid.
*/
public static function validateKey($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($key[0])) {
throw new InvalidArgumentException('Cache key length must be greater than zero');
}
if (isset($key[strcspn($key, '{}()/\@:')])) {
throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:', $key));
}
}
/**
* Internal logging helper.
*
* @internal
*/
public static function log(LoggerInterface $logger = null, $message, $context = array())
{
if ($logger) {
$logger->warning($message, $context);
} else {
$replace = array();
foreach ($context as $k => $v) {
if (is_scalar($v)) {
$replace['{'.$k.'}'] = $v;
}
}
@trigger_error(strtr($message, $replace), E_USER_WARNING);
}
}
}

View File

@@ -0,0 +1,83 @@
<?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;
use Doctrine\Common\Cache\CacheProvider;
use Psr\Cache\CacheItemPoolInterface;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DoctrineProvider extends CacheProvider
{
private $pool;
public function __construct(CacheItemPoolInterface $pool)
{
$this->pool = $pool;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$item = $this->pool->getItem(rawurlencode($id));
return $item->isHit() ? $item->get() : false;
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return $this->pool->hasItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$item = $this->pool->getItem(rawurlencode($id));
if (0 < $lifeTime) {
$item->expiresAfter($lifeTime);
}
return $this->pool->save($item->set($data));
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->pool->deleteItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$this->pool->clear();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
}
}

View File

@@ -0,0 +1,18 @@
<?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\Exception;
use Psr\Cache\CacheException as CacheExceptionInterface;
class CacheException extends \Exception implements CacheExceptionInterface
{
}

View File

@@ -0,0 +1,18 @@
<?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\Exception;
use Psr\Cache\InvalidArgumentException as InvalidArgumentExceptionInterface;
class InvalidArgumentException extends \InvalidArgumentException implements InvalidArgumentExceptionInterface
{
}

19
core/vendor/symfony/cache/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

9
core/vendor/symfony/cache/README.md vendored Normal file
View File

@@ -0,0 +1,9 @@
Symfony PSR-6 implementation for caching
========================================
This component provides a strict [PSR-6](http://www.php-fig.org/psr/psr-6/)
implementation for adding cache to your applications. It is designed to have a
low overhead so that caching is fastest. It ships with a few caching adapters
for the most widespread and suited to caching backends. It also provides a
`doctrine/cache` proxy adapter to cover more advanced caching needs and a proxy
adapter for greater interoperability between PSR-6 implementations.

View File

@@ -0,0 +1,46 @@
<?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\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Symfony\Component\Cache\Adapter\RedisAdapter;
abstract class AbstractRedisAdapterTest extends CachePoolTest
{
protected static $redis;
public function createCachePool()
{
if (defined('HHVM_VERSION')) {
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
}
return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__));
}
public static function setupBeforeClass()
{
if (!extension_loaded('redis')) {
self::markTestSkipped('Extension redis required.');
}
if (!@((new \Redis())->connect('127.0.0.1'))) {
$e = error_get_last();
self::markTestSkipped($e['message']);
}
}
public static function tearDownAfterClass()
{
self::$redis->flushDB();
self::$redis = null;
}
}

View File

@@ -0,0 +1,71 @@
<?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\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
class ApcuAdapterTest extends CachePoolTest
{
public function createCachePool()
{
if (defined('HHVM_VERSION')) {
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
}
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 ApcuAdapter(str_replace('\\', '.', __CLASS__));
}
public function testUnserializable()
{
$pool = $this->createCachePool();
$item = $pool->getItem('foo');
$item->set(function () {});
$this->assertFalse($pool->save($item));
$item = $pool->getItem('foo');
$this->assertFalse($item->isHit());
}
public function testVersion()
{
$namespace = str_replace('\\', '.', __CLASS__);
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertTrue($pool1->save($item->set('bar')));
$item = $pool1->getItem('foo');
$this->assertTrue($item->isHit());
$this->assertSame('bar', $item->get());
$pool2 = new ApcuAdapter($namespace, 0, 'p2');
$item = $pool2->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
$item = $pool1->getItem('foo');
$this->assertFalse($item->isHit());
$this->assertNull($item->get());
}
}

View File

@@ -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\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
/**
* @group time-sensitive
*/
class ArrayAdapterTest extends CachePoolTest
{
protected $skippedTests = array(
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
);
public function createCachePool()
{
return new ArrayAdapter();
}
}

View File

@@ -0,0 +1,51 @@
<?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\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ChainAdapterTest extends CachePoolTest
{
public function createCachePool()
{
if (defined('HHVM_VERSION')) {
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
}
return new ChainAdapter(array(new ArrayAdapter(), new ExternalAdapter(), new FilesystemAdapter()));
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage At least one adapter must be specified.
*/
public function testEmptyAdaptersException()
{
new ChainAdapter(array());
}
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage The class "stdClass" does not implement
*/
public function testInvalidAdapterException()
{
new ChainAdapter(array(new \stdClass()));
}
}

View 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\Tests\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Doctrine\Common\Cache\ArrayCache;
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
/**
* @group time-sensitive
*/
class DoctrineAdapterTest extends CachePoolTest
{
protected $skippedTests = array(
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
);
public function createCachePool()
{
return new DoctrineAdapter(new ArrayCache());
}
}

View File

@@ -0,0 +1,57 @@
<?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\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
/**
* @group time-sensitive
*/
class FilesystemAdapterTest extends CachePoolTest
{
public function createCachePool()
{
if (defined('HHVM_VERSION')) {
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Fails on HHVM';
}
return new FilesystemAdapter('sf-cache');
}
public static function tearDownAfterClass()
{
self::rmdir(sys_get_temp_dir().'/symfony-cache');
}
public static function rmdir($dir)
{
if (!file_exists($dir)) {
return;
}
if (!$dir || 0 !== strpos(dirname($dir), sys_get_temp_dir())) {
throw new \Exception(__METHOD__."() operates only on subdirs of system's temp dir");
}
$children = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($children as $child) {
if ($child->isDir()) {
rmdir($child);
} else {
unlink($child);
}
}
rmdir($dir);
}
}

View 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\Adapter;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
/**
* @group time-sensitive
*/
class NamespacedProxyAdapterTest extends ProxyAdapterTest
{
public function createCachePool()
{
return new ProxyAdapter(new ArrayAdapter(), 'foo');
}
}

View File

@@ -0,0 +1,49 @@
<?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\Adapter;
use Predis\Connection\StreamConnection;
use Symfony\Component\Cache\Adapter\RedisAdapter;
class PredisAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
self::$redis = new \Predis\Client();
}
public function testCreateConnection()
{
$redis = RedisAdapter::createConnection('redis://localhost/1', array('class' => \Predis\Client::class, 'timeout' => 3));
$this->assertInstanceOf(\Predis\Client::class, $redis);
$connection = $redis->getConnection();
$this->assertInstanceOf(StreamConnection::class, $connection);
$params = array(
'scheme' => 'tcp',
'host' => 'localhost',
'path' => '',
'dbindex' => '1',
'port' => 6379,
'class' => 'Predis\Client',
'timeout' => 3,
'persistent' => 0,
'read_timeout' => 0,
'retry_interval' => 0,
'database' => '1',
'password' => null,
);
$this->assertSame($params, $connection->getParameters()->toArray());
}
}

View 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\Tests\Adapter;
use Cache\IntegrationTests\CachePoolTest;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
/**
* @group time-sensitive
*/
class ProxyAdapterTest extends CachePoolTest
{
protected $skippedTests = array(
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
);
public function createCachePool()
{
return new ProxyAdapter(new ArrayAdapter());
}
}

View File

@@ -0,0 +1,81 @@
<?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\Adapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
class RedisAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
self::$redis = new \Redis();
self::$redis->connect('127.0.0.1');
}
public function testCreateConnection()
{
$redis = RedisAdapter::createConnection('redis://localhost');
$this->assertInstanceOf(\Redis::class, $redis);
$this->assertTrue($redis->isConnected());
$this->assertSame(0, $redis->getDbNum());
$redis = RedisAdapter::createConnection('redis://localhost/2');
$this->assertSame(2, $redis->getDbNum());
$redis = RedisAdapter::createConnection('redis://localhost', array('timeout' => 3));
$this->assertEquals(3, $redis->getTimeout());
$redis = RedisAdapter::createConnection('redis://localhost?timeout=4');
$this->assertEquals(4, $redis->getTimeout());
$redis = RedisAdapter::createConnection('redis://localhost', 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)
{
RedisAdapter::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)
{
RedisAdapter::createConnection($dsn);
}
public function provideInvalidCreateConnection()
{
return array(
array('foo://localhost'),
array('redis://'),
);
}
}

View 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\Tests\Adapter;
class RedisArrayAdapterTest extends AbstractRedisAdapterTest
{
public static function setupBeforeClass()
{
parent::setupBeforeClass();
if (!class_exists('RedisArray')) {
self::markTestSkipped('The RedisArray class is required.');
}
self::$redis = new \RedisArray(array('localhost'), array('lazy_connect' => true));
}
}

View File

@@ -0,0 +1,53 @@
<?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;
use Symfony\Component\Cache\CacheItem;
class CacheItemTest extends \PHPUnit_Framework_TestCase
{
public function testValidKey()
{
$this->assertNull(CacheItem::validateKey('foo'));
}
/**
* @dataProvider provideInvalidKey
* @expectedException Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Cache key
*/
public function testInvalidKey($key)
{
CacheItem::validateKey($key);
}
public function provideInvalidKey()
{
return array(
array(''),
array('{'),
array('}'),
array('('),
array(')'),
array('/'),
array('\\'),
array('@'),
array(':'),
array(true),
array(null),
array(1),
array(1.1),
array(array()),
array(new \Exception('foo')),
);
}
}

View 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;
use Doctrine\Common\Cache\CacheProvider;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\DoctrineProvider;
class DoctrineProviderTest extends \PHPUnit_Framework_TestCase
{
public function testProvider()
{
$pool = new ArrayAdapter();
$cache = new DoctrineProvider($pool);
$this->assertInstanceOf(CacheProvider::class, $cache);
$key = '{}()/\@:';
$this->assertTrue($cache->delete($key));
$this->assertFalse($cache->contains($key));
$this->assertTrue($cache->save($key, 'bar'));
$this->assertTrue($cache->contains($key));
$this->assertSame('bar', $cache->fetch($key));
$this->assertTrue($cache->delete($key));
$this->assertFalse($cache->fetch($key));
$this->assertTrue($cache->save($key, 'bar'));
$cache->flushAll();
$this->assertFalse($cache->fetch($key));
$this->assertFalse($cache->contains($key));
}
}

View File

@@ -0,0 +1,76 @@
<?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\Fixtures;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
/**
* Adapter not implementing the {@see \Symfony\Component\Cache\Adapter\AdapterInterface}.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ExternalAdapter implements CacheItemPoolInterface
{
private $cache;
public function __construct()
{
$this->cache = new ArrayAdapter();
}
public function getItem($key)
{
return $this->cache->getItem($key);
}
public function getItems(array $keys = array())
{
return $this->cache->getItems($keys);
}
public function hasItem($key)
{
return $this->cache->hasItem($key);
}
public function clear()
{
return $this->cache->clear();
}
public function deleteItem($key)
{
return $this->cache->deleteItem($key);
}
public function deleteItems(array $keys)
{
return $this->cache->deleteItems($keys);
}
public function save(CacheItemInterface $item)
{
return $this->cache->save($item);
}
public function saveDeferred(CacheItemInterface $item)
{
return $this->cache->saveDeferred($item);
}
public function commit()
{
return $this->cache->commit();
}
}

46
core/vendor/symfony/cache/composer.json vendored Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "symfony/cache",
"type": "library",
"description": "Symfony implementation of PSR-6",
"keywords": ["caching", "psr6"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"provide": {
"psr/cache-implementation": "1.0"
},
"require": {
"php": ">=5.5.9",
"psr/cache": "~1.0",
"psr/log": "~1.0"
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/cache": "~1.6",
"predis/predis": "~1.0"
},
"suggest": {
"symfony/polyfill-apcu": "For using ApcuAdapter on HHVM"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Cache\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
}
}

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony Cache Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments>
<array>
<element><string>Cache\IntegrationTests</string></element>
<element><string>Doctrine\Common\Cache</string></element>
</array>
</arguments>
</listener>
</listeners>
</phpunit>