default services conflit ?

This commit is contained in:
armansansd
2022-04-27 11:30:43 +02:00
parent 28190a5749
commit 8bb1064a3b
8132 changed files with 900138 additions and 426 deletions

19
old.vendor/doctrine/cache/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2006-2015 Doctrine Project
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.

13
old.vendor/doctrine/cache/README.md vendored Normal file
View File

@@ -0,0 +1,13 @@
# Doctrine Cache
[![Build Status](https://github.com/doctrine/cache/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/cache/actions)
[![Code Coverage](https://codecov.io/gh/doctrine/cache/branch/1.10.x/graph/badge.svg)](https://codecov.io/gh/doctrine/cache/branch/1.10.x)
[![Latest Stable Version](https://img.shields.io/packagist/v/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache)
[![Total Downloads](https://img.shields.io/packagist/dt/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache)
Cache component extracted from the Doctrine Common project. [Documentation](https://www.doctrine-project.org/projects/doctrine-cache/en/current/index.html)
This library is deprecated and will no longer receive bug fixes from the
Doctrine Project. Please use a different cache library, preferably PSR-6 or
PSR-16 instead.

View File

@@ -0,0 +1,15 @@
# Upgrade to 1.11
doctrine/cache will no longer be maintained and all cache implementations have
been marked as deprecated. These implementations will be removed in 2.0, which
will only contain interfaces to provide a lightweight package for backward
compatibility.
There are two new classes to use in the `Doctrine\Common\Cache\Psr6` namespace:
* The `CacheAdapter` class allows using any Doctrine Cache as PSR-6 cache. This
is useful to provide a forward compatibility layer in libraries that accept
Doctrine cache implementations and switch to PSR-6.
* The `DoctrineProvider` class allows using any PSR-6 cache as Doctrine cache.
This implementation is designed for libraries that leak the cache and want to
switch to allowing PSR-6 implementations. This class is design to be used
during the transition phase of sunsetting doctrine/cache support.

View File

@@ -0,0 +1,16 @@
# Upgrade to 1.4
## Minor BC Break: `Doctrine\Common\Cache\FileCache#$extension` is now `private`.
If you need to override the value of `Doctrine\Common\Cache\FileCache#$extension`, then use the
second parameter of `Doctrine\Common\Cache\FileCache#__construct()` instead of overriding
the property in your own implementation.
## Minor BC Break: file based caches paths changed
`Doctrine\Common\Cache\FileCache`, `Doctrine\Common\Cache\PhpFileCache` and
`Doctrine\Common\Cache\FilesystemCache` are using a different cache paths structure.
If you rely on warmed up caches for deployments, consider that caches generated
with `doctrine/cache` `<1.4` are not compatible with the new directory structure,
and will be ignored.

51
old.vendor/doctrine/cache/composer.json vendored Normal file
View File

@@ -0,0 +1,51 @@
{
"name": "doctrine/cache",
"type": "library",
"description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
"keywords": [
"php",
"cache",
"caching",
"abstraction",
"redis",
"memcached",
"couchdb",
"xcache",
"apcu"
],
"homepage": "https://www.doctrine-project.org/projects/cache.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": "~7.1 || ^8.0"
},
"require-dev": {
"alcaeus/mongo-php-adapter": "^1.1",
"mongodb/mongodb": "^1.1",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"predis/predis": "~1.0",
"doctrine/coding-standard": "^8.0",
"psr/cache": "^1.0 || ^2.0 || ^3.0",
"cache/integration-tests": "dev-master",
"symfony/cache": "^4.4 || ^5.2 || ^6.0@dev",
"symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev"
},
"suggest": {
"alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"autoload": {
"psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" }
},
"autoload-dev": {
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine/Tests" }
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Doctrine\Common\Cache;
use function apc_cache_info;
use function apc_clear_cache;
use function apc_delete;
use function apc_exists;
use function apc_fetch;
use function apc_sma_info;
use function apc_store;
use const PHP_VERSION_ID;
/**
* APC cache provider.
*
* @deprecated since version 1.6, use ApcuCache instead
*
* @link www.doctrine-project.org
*/
class ApcCache extends CacheProvider
{
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return apc_fetch($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return apc_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return apc_store($id, $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
// apc_delete returns false if the id does not exist
return apc_delete($id) || ! apc_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return apc_clear_cache() && apc_clear_cache('user');
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
return apc_fetch($keys) ?: [];
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$result = apc_store($keysAndValues, null, $lifetime);
return empty($result);
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$info = apc_cache_info('', true);
$sma = apc_sma_info();
// @TODO - Temporary fix @see https://github.com/krakjoe/apcu/pull/42
if (PHP_VERSION_ID >= 50500) {
$info['num_hits'] = $info['num_hits'] ?? $info['nhits'];
$info['num_misses'] = $info['num_misses'] ?? $info['nmisses'];
$info['start_time'] = $info['start_time'] ?? $info['stime'];
}
return [
Cache::STATS_HITS => $info['num_hits'],
Cache::STATS_MISSES => $info['num_misses'],
Cache::STATS_UPTIME => $info['start_time'],
Cache::STATS_MEMORY_USAGE => $info['mem_size'],
Cache::STATS_MEMORY_AVAILABLE => $sma['avail_mem'],
];
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace Doctrine\Common\Cache;
use function apcu_cache_info;
use function apcu_clear_cache;
use function apcu_delete;
use function apcu_exists;
use function apcu_fetch;
use function apcu_sma_info;
use function apcu_store;
use function count;
/**
* APCu cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class ApcuCache extends CacheProvider
{
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return apcu_fetch($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return apcu_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return apcu_store($id, $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
// apcu_delete returns false if the id does not exist
return apcu_delete($id) || ! apcu_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doDeleteMultiple(array $keys)
{
$result = apcu_delete($keys);
return $result !== false && count($result) !== count($keys);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return apcu_clear_cache();
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
return apcu_fetch($keys) ?: [];
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$result = apcu_store($keysAndValues, null, $lifetime);
return empty($result);
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$info = apcu_cache_info(true);
$sma = apcu_sma_info();
return [
Cache::STATS_HITS => $info['num_hits'],
Cache::STATS_MISSES => $info['num_misses'],
Cache::STATS_UPTIME => $info['start_time'],
Cache::STATS_MEMORY_USAGE => $info['mem_size'],
Cache::STATS_MEMORY_AVAILABLE => $sma['avail_mem'],
];
}
}

View File

@@ -0,0 +1,115 @@
<?php
namespace Doctrine\Common\Cache;
use function time;
/**
* Array cache driver.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class ArrayCache extends CacheProvider
{
/** @psalm-var array<string, array{mixed, int|bool}>> $data each element being a tuple of [$data, $expiration], where the expiration is int|bool */
private $data = [];
/** @var int */
private $hitsCount = 0;
/** @var int */
private $missesCount = 0;
/** @var int */
private $upTime;
/**
* {@inheritdoc}
*/
public function __construct()
{
$this->upTime = time();
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
if (! $this->doContains($id)) {
$this->missesCount += 1;
return false;
}
$this->hitsCount += 1;
return $this->data[$id][0];
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
if (! isset($this->data[$id])) {
return false;
}
$expiration = $this->data[$id][1];
if ($expiration && $expiration < time()) {
$this->doDelete($id);
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$this->data[$id] = [$data, $lifeTime ? time() + $lifeTime : false];
return true;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
unset($this->data[$id]);
return true;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$this->data = [];
return true;
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
return [
Cache::STATS_HITS => $this->hitsCount,
Cache::STATS_MISSES => $this->missesCount,
Cache::STATS_UPTIME => $this->upTime,
Cache::STATS_MEMORY_USAGE => null,
Cache::STATS_MEMORY_AVAILABLE => null,
];
}
}

View File

@@ -0,0 +1,90 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache drivers.
*
* @link www.doctrine-project.org
*/
interface Cache
{
public const STATS_HITS = 'hits';
public const STATS_MISSES = 'misses';
public const STATS_UPTIME = 'uptime';
public const STATS_MEMORY_USAGE = 'memory_usage';
public const STATS_MEMORY_AVAILABLE = 'memory_available';
/**
* Only for backward compatibility (may be removed in next major release)
*
* @deprecated
*/
public const STATS_MEMORY_AVAILIABLE = 'memory_available';
/**
* Fetches an entry from the cache.
*
* @param string $id The id of the cache entry to fetch.
*
* @return mixed The cached data or FALSE, if no cache entry exists for the given id.
*/
public function fetch($id);
/**
* Tests if an entry exists in the cache.
*
* @param string $id The cache id of the entry to check for.
*
* @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise.
*/
public function contains($id);
/**
* Puts data into the cache.
*
* If a cache entry with the given id already exists, its data will be replaced.
*
* @param string $id The cache id.
* @param mixed $data The cache entry/data.
* @param int $lifeTime The lifetime in number of seconds for this cache entry.
* If zero (the default), the entry never expires (although it may be deleted from the cache
* to make place for other entries).
*
* @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
*/
public function save($id, $data, $lifeTime = 0);
/**
* Deletes a cache entry.
*
* @param string $id The cache id.
*
* @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
* Deleting a non-existing entry is considered successful.
*/
public function delete($id);
/**
* Retrieves cached information from the data store.
*
* The server's statistics array has the following values:
*
* - <b>hits</b>
* Number of keys that have been requested and found present.
*
* - <b>misses</b>
* Number of items that have been requested and not found.
*
* - <b>uptime</b>
* Time that the server is running.
*
* - <b>memory_usage</b>
* Memory used by this server to store items.
*
* - <b>memory_available</b>
* Memory allowed to use for storage.
*
* @return mixed[]|null An associative array with server's statistics if available, NULL otherwise.
*/
public function getStats();
}

View File

@@ -0,0 +1,325 @@
<?php
namespace Doctrine\Common\Cache;
use function array_combine;
use function array_key_exists;
use function array_map;
use function sprintf;
/**
* Base class for cache provider implementations.
*/
abstract class CacheProvider implements Cache, FlushableCache, ClearableCache, MultiOperationCache
{
public const DOCTRINE_NAMESPACE_CACHEKEY = 'DoctrineNamespaceCacheKey[%s]';
/**
* The namespace to prefix all cache ids with.
*
* @var string
*/
private $namespace = '';
/**
* The namespace version.
*
* @var int|null
*/
private $namespaceVersion;
/**
* Sets the namespace to prefix all cache ids with.
*
* @param string $namespace
*
* @return void
*/
public function setNamespace($namespace)
{
$this->namespace = (string) $namespace;
$this->namespaceVersion = null;
}
/**
* Retrieves the namespace that prefixes all cache ids.
*
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* {@inheritdoc}
*/
public function fetch($id)
{
return $this->doFetch($this->getNamespacedId($id));
}
/**
* {@inheritdoc}
*/
public function fetchMultiple(array $keys)
{
if (empty($keys)) {
return [];
}
// note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys
$namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys));
$items = $this->doFetchMultiple($namespacedKeys);
$foundItems = [];
// no internal array function supports this sort of mapping: needs to be iterative
// this filters and combines keys in one pass
foreach ($namespacedKeys as $requestedKey => $namespacedKey) {
if (! isset($items[$namespacedKey]) && ! array_key_exists($namespacedKey, $items)) {
continue;
}
$foundItems[$requestedKey] = $items[$namespacedKey];
}
return $foundItems;
}
/**
* {@inheritdoc}
*/
public function saveMultiple(array $keysAndValues, $lifetime = 0)
{
$namespacedKeysAndValues = [];
foreach ($keysAndValues as $key => $value) {
$namespacedKeysAndValues[$this->getNamespacedId($key)] = $value;
}
return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime);
}
/**
* {@inheritdoc}
*/
public function contains($id)
{
return $this->doContains($this->getNamespacedId($id));
}
/**
* {@inheritdoc}
*/
public function save($id, $data, $lifeTime = 0)
{
return $this->doSave($this->getNamespacedId($id), $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
public function deleteMultiple(array $keys)
{
return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys));
}
/**
* {@inheritdoc}
*/
public function delete($id)
{
return $this->doDelete($this->getNamespacedId($id));
}
/**
* {@inheritdoc}
*/
public function getStats()
{
return $this->doGetStats();
}
/**
* {@inheritDoc}
*/
public function flushAll()
{
return $this->doFlush();
}
/**
* {@inheritDoc}
*/
public function deleteAll()
{
$namespaceCacheKey = $this->getNamespaceCacheKey();
$namespaceVersion = $this->getNamespaceVersion() + 1;
if ($this->doSave($namespaceCacheKey, $namespaceVersion)) {
$this->namespaceVersion = $namespaceVersion;
return true;
}
return false;
}
/**
* Prefixes the passed id with the configured namespace value.
*
* @param string $id The id to namespace.
*
* @return string The namespaced id.
*/
private function getNamespacedId(string $id): string
{
$namespaceVersion = $this->getNamespaceVersion();
return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion);
}
/**
* Returns the namespace cache key.
*/
private function getNamespaceCacheKey(): string
{
return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace);
}
/**
* Returns the namespace version.
*/
private function getNamespaceVersion(): int
{
if ($this->namespaceVersion !== null) {
return $this->namespaceVersion;
}
$namespaceCacheKey = $this->getNamespaceCacheKey();
$this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1;
return $this->namespaceVersion;
}
/**
* Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it.
*
* @param string[] $keys Array of keys to retrieve from cache
*
* @return mixed[] Array of values retrieved for the given keys.
*/
protected function doFetchMultiple(array $keys)
{
$returnValues = [];
foreach ($keys as $key) {
$item = $this->doFetch($key);
if ($item === false && ! $this->doContains($key)) {
continue;
}
$returnValues[$key] = $item;
}
return $returnValues;
}
/**
* Fetches an entry from the cache.
*
* @param string $id The id of the cache entry to fetch.
*
* @return mixed|false The cached data or FALSE, if no cache entry exists for the given id.
*/
abstract protected function doFetch($id);
/**
* Tests if an entry exists in the cache.
*
* @param string $id The cache id of the entry to check for.
*
* @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise.
*/
abstract protected function doContains($id);
/**
* Default implementation of doSaveMultiple. Each driver that supports multi-put should override it.
*
* @param mixed[] $keysAndValues Array of keys and values to save in cache
* @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these
* cache entries (0 => infinite lifeTime).
*
* @return bool TRUE if the operation was successful, FALSE if it wasn't.
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$success = true;
foreach ($keysAndValues as $key => $value) {
if ($this->doSave($key, $value, $lifetime)) {
continue;
}
$success = false;
}
return $success;
}
/**
* Puts data into the cache.
*
* @param string $id The cache id.
* @param string $data The cache entry/data.
* @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this
* cache entry (0 => infinite lifeTime).
*
* @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise.
*/
abstract protected function doSave($id, $data, $lifeTime = 0);
/**
* Default implementation of doDeleteMultiple. Each driver that supports multi-delete should override it.
*
* @param string[] $keys Array of keys to delete from cache
*
* @return bool TRUE if the operation was successful, FALSE if it wasn't
*/
protected function doDeleteMultiple(array $keys)
{
$success = true;
foreach ($keys as $key) {
if ($this->doDelete($key)) {
continue;
}
$success = false;
}
return $success;
}
/**
* Deletes a cache entry.
*
* @param string $id The cache id.
*
* @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise.
*/
abstract protected function doDelete($id);
/**
* Flushes all cache entries.
*
* @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
*/
abstract protected function doFlush();
/**
* Retrieves cached information from the data store.
*
* @return mixed[]|null An associative array with server's statistics if available, NULL otherwise.
*/
abstract protected function doGetStats();
}

View File

@@ -0,0 +1,198 @@
<?php
namespace Doctrine\Common\Cache;
use Traversable;
use function array_values;
use function count;
use function iterator_to_array;
/**
* Cache provider that allows to easily chain multiple cache providers
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class ChainCache extends CacheProvider
{
/** @var CacheProvider[] */
private $cacheProviders = [];
/** @var int */
private $defaultLifeTimeForDownstreamCacheProviders = 0;
/**
* @param CacheProvider[] $cacheProviders
*/
public function __construct($cacheProviders = [])
{
$this->cacheProviders = $cacheProviders instanceof Traversable
? iterator_to_array($cacheProviders, false)
: array_values($cacheProviders);
}
public function setDefaultLifeTimeForDownstreamCacheProviders(int $defaultLifeTimeForDownstreamCacheProviders): void
{
$this->defaultLifeTimeForDownstreamCacheProviders = $defaultLifeTimeForDownstreamCacheProviders;
}
/**
* {@inheritDoc}
*/
public function setNamespace($namespace)
{
parent::setNamespace($namespace);
foreach ($this->cacheProviders as $cacheProvider) {
$cacheProvider->setNamespace($namespace);
}
}
/**
* {@inheritDoc}
*/
protected function doFetch($id)
{
foreach ($this->cacheProviders as $key => $cacheProvider) {
if ($cacheProvider->doContains($id)) {
$value = $cacheProvider->doFetch($id);
// We populate all the previous cache layers (that are assumed to be faster)
for ($subKey = $key - 1; $subKey >= 0; $subKey--) {
$this->cacheProviders[$subKey]->doSave($id, $value, $this->defaultLifeTimeForDownstreamCacheProviders);
}
return $value;
}
}
return false;
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
/** @var CacheProvider[] $traversedProviders */
$traversedProviders = [];
$keysCount = count($keys);
$fetchedValues = [];
foreach ($this->cacheProviders as $key => $cacheProvider) {
$fetchedValues = $cacheProvider->doFetchMultiple($keys);
// We populate all the previous cache layers (that are assumed to be faster)
if (count($fetchedValues) === $keysCount) {
foreach ($traversedProviders as $previousCacheProvider) {
$previousCacheProvider->doSaveMultiple($fetchedValues, $this->defaultLifeTimeForDownstreamCacheProviders);
}
return $fetchedValues;
}
$traversedProviders[] = $cacheProvider;
}
return $fetchedValues;
}
/**
* {@inheritDoc}
*/
protected function doContains($id)
{
foreach ($this->cacheProviders as $cacheProvider) {
if ($cacheProvider->doContains($id)) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$stored = true;
foreach ($this->cacheProviders as $cacheProvider) {
$stored = $cacheProvider->doSave($id, $data, $lifeTime) && $stored;
}
return $stored;
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$stored = true;
foreach ($this->cacheProviders as $cacheProvider) {
$stored = $cacheProvider->doSaveMultiple($keysAndValues, $lifetime) && $stored;
}
return $stored;
}
/**
* {@inheritDoc}
*/
protected function doDelete($id)
{
$deleted = true;
foreach ($this->cacheProviders as $cacheProvider) {
$deleted = $cacheProvider->doDelete($id) && $deleted;
}
return $deleted;
}
/**
* {@inheritdoc}
*/
protected function doDeleteMultiple(array $keys)
{
$deleted = true;
foreach ($this->cacheProviders as $cacheProvider) {
$deleted = $cacheProvider->doDeleteMultiple($keys) && $deleted;
}
return $deleted;
}
/**
* {@inheritDoc}
*/
protected function doFlush()
{
$flushed = true;
foreach ($this->cacheProviders as $cacheProvider) {
$flushed = $cacheProvider->doFlush() && $flushed;
}
return $flushed;
}
/**
* {@inheritDoc}
*/
protected function doGetStats()
{
// We return all the stats from all adapters
$stats = [];
foreach ($this->cacheProviders as $cacheProvider) {
$stats[] = $cacheProvider->doGetStats();
}
return $stats;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache that can be flushed.
*
* Intended to be used for partial clearing of a cache namespace. For a more
* global "flushing", see {@see FlushableCache}.
*
* @link www.doctrine-project.org
*/
interface ClearableCache
{
/**
* Deletes all cache entries in the current cache namespace.
*
* @return bool TRUE if the cache entries were successfully deleted, FALSE otherwise.
*/
public function deleteAll();
}

View File

@@ -0,0 +1,200 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Cache;
use Couchbase\Bucket;
use Couchbase\Document;
use Couchbase\Exception;
use RuntimeException;
use function phpversion;
use function serialize;
use function sprintf;
use function substr;
use function time;
use function unserialize;
use function version_compare;
/**
* Couchbase ^2.3.0 cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
final class CouchbaseBucketCache extends CacheProvider
{
private const MINIMUM_VERSION = '2.3.0';
private const KEY_NOT_FOUND = 13;
private const MAX_KEY_LENGTH = 250;
private const THIRTY_DAYS_IN_SECONDS = 2592000;
/** @var Bucket */
private $bucket;
public function __construct(Bucket $bucket)
{
if (version_compare(phpversion('couchbase'), self::MINIMUM_VERSION) < 0) {
// Manager is required to flush cache and pull stats.
throw new RuntimeException(sprintf('ext-couchbase:^%s is required.', self::MINIMUM_VERSION));
}
$this->bucket = $bucket;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$id = $this->normalizeKey($id);
try {
$document = $this->bucket->get($id);
} catch (Exception $e) {
return false;
}
if ($document instanceof Document && $document->value !== false) {
return unserialize($document->value);
}
return false;
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$id = $this->normalizeKey($id);
try {
$document = $this->bucket->get($id);
} catch (Exception $e) {
return false;
}
if ($document instanceof Document) {
return ! $document->error;
}
return false;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$id = $this->normalizeKey($id);
$lifeTime = $this->normalizeExpiry($lifeTime);
try {
$encoded = serialize($data);
$document = $this->bucket->upsert($id, $encoded, [
'expiry' => (int) $lifeTime,
]);
} catch (Exception $e) {
return false;
}
if ($document instanceof Document) {
return ! $document->error;
}
return false;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
$id = $this->normalizeKey($id);
try {
$document = $this->bucket->remove($id);
} catch (Exception $e) {
return $e->getCode() === self::KEY_NOT_FOUND;
}
if ($document instanceof Document) {
return ! $document->error;
}
return false;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$manager = $this->bucket->manager();
// Flush does not return with success or failure, and must be enabled per bucket on the server.
// Store a marker item so that we will know if it was successful.
$this->doSave(__METHOD__, true, 60);
$manager->flush();
if ($this->doContains(__METHOD__)) {
$this->doDelete(__METHOD__);
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$manager = $this->bucket->manager();
$stats = $manager->info();
$nodes = $stats['nodes'];
$node = $nodes[0];
$interestingStats = $node['interestingStats'];
return [
Cache::STATS_HITS => $interestingStats['get_hits'],
Cache::STATS_MISSES => $interestingStats['cmd_get'] - $interestingStats['get_hits'],
Cache::STATS_UPTIME => $node['uptime'],
Cache::STATS_MEMORY_USAGE => $interestingStats['mem_used'],
Cache::STATS_MEMORY_AVAILABLE => $node['memoryFree'],
];
}
private function normalizeKey(string $id): string
{
$normalized = substr($id, 0, self::MAX_KEY_LENGTH);
if ($normalized === false) {
return $id;
}
return $normalized;
}
/**
* Expiry treated as a unix timestamp instead of an offset if expiry is greater than 30 days.
*
* @src https://developer.couchbase.com/documentation/server/4.1/developer-guide/expiry.html
*/
private function normalizeExpiry(int $expiry): int
{
if ($expiry > self::THIRTY_DAYS_IN_SECONDS) {
return time() + $expiry;
}
return $expiry;
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Doctrine\Common\Cache;
use Couchbase;
use function explode;
use function time;
/**
* Couchbase cache provider.
*
* @deprecated Couchbase SDK 1.x is now deprecated. Use \Doctrine\Common\Cache\CouchbaseBucketCache instead.
* https://developer.couchbase.com/documentation/server/current/sdk/php/compatibility-versions-features.html
*
* @link www.doctrine-project.org
*/
class CouchbaseCache extends CacheProvider
{
/** @var Couchbase|null */
private $couchbase;
/**
* Sets the Couchbase instance to use.
*
* @return void
*/
public function setCouchbase(Couchbase $couchbase)
{
$this->couchbase = $couchbase;
}
/**
* Gets the Couchbase instance used by the cache.
*
* @return Couchbase|null
*/
public function getCouchbase()
{
return $this->couchbase;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->couchbase->get($id) ?: false;
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return $this->couchbase->get($id) !== null;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
if ($lifeTime > 30 * 24 * 3600) {
$lifeTime = time() + $lifeTime;
}
return $this->couchbase->set($id, $data, (int) $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->couchbase->delete($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return $this->couchbase->flush();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$stats = $this->couchbase->getStats();
$servers = $this->couchbase->getServers();
$server = explode(':', $servers[0]);
$key = $server[0] . ':11210';
$stats = $stats[$key];
return [
Cache::STATS_HITS => $stats['get_hits'],
Cache::STATS_MISSES => $stats['get_misses'],
Cache::STATS_UPTIME => $stats['uptime'],
Cache::STATS_MEMORY_USAGE => $stats['bytes'],
Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'],
];
}
}

View File

@@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Cache;
use DateTime;
use MongoDB\BSON\Binary;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Collection;
use MongoDB\Database;
use MongoDB\Driver\Exception\Exception;
use MongoDB\Model\BSONDocument;
use function serialize;
use function time;
use function unserialize;
/**
* MongoDB cache provider for ext-mongodb
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class ExtMongoDBCache extends CacheProvider
{
/** @var Database */
private $database;
/** @var Collection */
private $collection;
/** @var bool */
private $expirationIndexCreated = false;
/**
* This provider will default to the write concern and read preference
* options set on the Database instance (or inherited from MongoDB or
* Client). Using an unacknowledged write concern (< 1) may make the return
* values of delete() and save() unreliable. Reading from secondaries may
* make contain() and fetch() unreliable.
*
* @see http://www.php.net/manual/en/mongo.readpreferences.php
* @see http://www.php.net/manual/en/mongo.writeconcerns.php
*/
public function __construct(Collection $collection)
{
// Ensure there is no typemap set - we want to use our own
$this->collection = $collection->withOptions(['typeMap' => null]);
$this->database = new Database($collection->getManager(), $collection->getDatabaseName());
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$document = $this->collection->findOne(['_id' => $id], [MongoDBCache::DATA_FIELD, MongoDBCache::EXPIRATION_FIELD]);
if ($document === null) {
return false;
}
if ($this->isExpired($document)) {
$this->createExpirationIndex();
$this->doDelete($id);
return false;
}
return unserialize($document[MongoDBCache::DATA_FIELD]->getData());
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$document = $this->collection->findOne(['_id' => $id], [MongoDBCache::EXPIRATION_FIELD]);
if ($document === null) {
return false;
}
if ($this->isExpired($document)) {
$this->createExpirationIndex();
$this->doDelete($id);
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
try {
$this->collection->updateOne(
['_id' => $id],
[
'$set' => [
MongoDBCache::EXPIRATION_FIELD => ($lifeTime > 0 ? new UTCDateTime((time() + $lifeTime) * 1000) : null),
MongoDBCache::DATA_FIELD => new Binary(serialize($data), Binary::TYPE_GENERIC),
],
],
['upsert' => true]
);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
try {
$this->collection->deleteOne(['_id' => $id]);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
try {
// Use remove() in lieu of drop() to maintain any collection indexes
$this->collection->deleteMany([]);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$uptime = null;
$memoryUsage = null;
try {
$serverStatus = $this->database->command([
'serverStatus' => 1,
'locks' => 0,
'metrics' => 0,
'recordStats' => 0,
'repl' => 0,
])->toArray()[0];
$uptime = $serverStatus['uptime'] ?? null;
} catch (Exception $e) {
}
try {
$collStats = $this->database->command(['collStats' => $this->collection->getCollectionName()])->toArray()[0];
$memoryUsage = $collStats['size'] ?? null;
} catch (Exception $e) {
}
return [
Cache::STATS_HITS => null,
Cache::STATS_MISSES => null,
Cache::STATS_UPTIME => $uptime,
Cache::STATS_MEMORY_USAGE => $memoryUsage,
Cache::STATS_MEMORY_AVAILABLE => null,
];
}
/**
* Check if the document is expired.
*/
private function isExpired(BSONDocument $document): bool
{
return isset($document[MongoDBCache::EXPIRATION_FIELD]) &&
$document[MongoDBCache::EXPIRATION_FIELD] instanceof UTCDateTime &&
$document[MongoDBCache::EXPIRATION_FIELD]->toDateTime() < new DateTime();
}
private function createExpirationIndex(): void
{
if ($this->expirationIndexCreated) {
return;
}
$this->collection->createIndex([MongoDBCache::EXPIRATION_FIELD => 1], ['background' => true, 'expireAfterSeconds' => 0]);
}
}

View File

@@ -0,0 +1,292 @@
<?php
namespace Doctrine\Common\Cache;
use FilesystemIterator;
use InvalidArgumentException;
use Iterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
use function bin2hex;
use function chmod;
use function defined;
use function disk_free_space;
use function file_exists;
use function file_put_contents;
use function gettype;
use function hash;
use function is_dir;
use function is_int;
use function is_writable;
use function mkdir;
use function pathinfo;
use function realpath;
use function rename;
use function rmdir;
use function sprintf;
use function strlen;
use function strrpos;
use function substr;
use function tempnam;
use function unlink;
use const DIRECTORY_SEPARATOR;
use const PATHINFO_DIRNAME;
/**
* Base file cache driver.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
abstract class FileCache extends CacheProvider
{
/**
* The cache directory.
*
* @var string
*/
protected $directory;
/**
* The cache file extension.
*
* @var string
*/
private $extension;
/** @var int */
private $umask;
/** @var int */
private $directoryStringLength;
/** @var int */
private $extensionStringLength;
/** @var bool */
private $isRunningOnWindows;
/**
* @param string $directory The cache directory.
* @param string $extension The cache file extension.
* @param int $umask
*
* @throws InvalidArgumentException
*/
public function __construct($directory, $extension = '', $umask = 0002)
{
// YES, this needs to be *before* createPathIfNeeded()
if (! is_int($umask)) {
throw new InvalidArgumentException(sprintf(
'The umask parameter is required to be integer, was: %s',
gettype($umask)
));
}
$this->umask = $umask;
if (! $this->createPathIfNeeded($directory)) {
throw new InvalidArgumentException(sprintf(
'The directory "%s" does not exist and could not be created.',
$directory
));
}
if (! is_writable($directory)) {
throw new InvalidArgumentException(sprintf(
'The directory "%s" is not writable.',
$directory
));
}
// YES, this needs to be *after* createPathIfNeeded()
$this->directory = realpath($directory);
$this->extension = (string) $extension;
$this->directoryStringLength = strlen($this->directory);
$this->extensionStringLength = strlen($this->extension);
$this->isRunningOnWindows = defined('PHP_WINDOWS_VERSION_BUILD');
}
/**
* Gets the cache directory.
*
* @return string
*/
public function getDirectory()
{
return $this->directory;
}
/**
* Gets the cache file extension.
*
* @return string
*/
public function getExtension()
{
return $this->extension;
}
/**
* @param string $id
*
* @return string
*/
protected function getFilename($id)
{
$hash = hash('sha256', $id);
// This ensures that the filename is unique and that there are no invalid chars in it.
if (
$id === ''
|| ((strlen($id) * 2 + $this->extensionStringLength) > 255)
|| ($this->isRunningOnWindows && ($this->directoryStringLength + 4 + strlen($id) * 2 + $this->extensionStringLength) > 258)
) {
// Most filesystems have a limit of 255 chars for each path component. On Windows the the whole path is limited
// to 260 chars (including terminating null char). Using long UNC ("\\?\" prefix) does not work with the PHP API.
// And there is a bug in PHP (https://bugs.php.net/bug.php?id=70943) with path lengths of 259.
// So if the id in hex representation would surpass the limit, we use the hash instead. The prefix prevents
// collisions between the hash and bin2hex.
$filename = '_' . $hash;
} else {
$filename = bin2hex($id);
}
return $this->directory
. DIRECTORY_SEPARATOR
. substr($hash, 0, 2)
. DIRECTORY_SEPARATOR
. $filename
. $this->extension;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
$filename = $this->getFilename($id);
return @unlink($filename) || ! file_exists($filename);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
foreach ($this->getIterator() as $name => $file) {
if ($file->isDir()) {
// Remove the intermediate directories which have been created to balance the tree. It only takes effect
// if the directory is empty. If several caches share the same directory but with different file extensions,
// the other ones are not removed.
@rmdir($name);
} elseif ($this->isFilenameEndingWithExtension($name)) {
// If an extension is set, only remove files which end with the given extension.
// If no extension is set, we have no other choice than removing everything.
@unlink($name);
}
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$usage = 0;
foreach ($this->getIterator() as $name => $file) {
if ($file->isDir() || ! $this->isFilenameEndingWithExtension($name)) {
continue;
}
$usage += $file->getSize();
}
$free = disk_free_space($this->directory);
return [
Cache::STATS_HITS => null,
Cache::STATS_MISSES => null,
Cache::STATS_UPTIME => null,
Cache::STATS_MEMORY_USAGE => $usage,
Cache::STATS_MEMORY_AVAILABLE => $free,
];
}
/**
* Create path if needed.
*
* @return bool TRUE on success or if path already exists, FALSE if path cannot be created.
*/
private function createPathIfNeeded(string $path): bool
{
if (! is_dir($path)) {
if (@mkdir($path, 0777 & (~$this->umask), true) === false && ! is_dir($path)) {
return false;
}
}
return true;
}
/**
* Writes a string content to file in an atomic way.
*
* @param string $filename Path to the file where to write the data.
* @param string $content The content to write
*
* @return bool TRUE on success, FALSE if path cannot be created, if path is not writable or an any other error.
*/
protected function writeFile(string $filename, string $content): bool
{
$filepath = pathinfo($filename, PATHINFO_DIRNAME);
if (! $this->createPathIfNeeded($filepath)) {
return false;
}
if (! is_writable($filepath)) {
return false;
}
$tmpFile = tempnam($filepath, 'swap');
@chmod($tmpFile, 0666 & (~$this->umask));
if (file_put_contents($tmpFile, $content) !== false) {
@chmod($tmpFile, 0666 & (~$this->umask));
if (@rename($tmpFile, $filename)) {
return true;
}
@unlink($tmpFile);
}
return false;
}
/**
* @return Iterator<string, SplFileInfo>
*/
private function getIterator(): Iterator
{
return new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($this->directory, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
}
/**
* @param string $name The filename
*/
private function isFilenameEndingWithExtension(string $name): bool
{
return $this->extension === ''
|| strrpos($name, $this->extension) === strlen($name) - $this->extensionStringLength;
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace Doctrine\Common\Cache;
use function fclose;
use function fgets;
use function fopen;
use function is_file;
use function serialize;
use function time;
use function unserialize;
use const PHP_EOL;
/**
* Filesystem cache driver.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class FilesystemCache extends FileCache
{
public const EXTENSION = '.doctrinecache.data';
/**
* {@inheritdoc}
*/
public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
{
parent::__construct($directory, $extension, $umask);
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$data = '';
$lifetime = -1;
$filename = $this->getFilename($id);
if (! is_file($filename)) {
return false;
}
$resource = fopen($filename, 'r');
$line = fgets($resource);
if ($line !== false) {
$lifetime = (int) $line;
}
if ($lifetime !== 0 && $lifetime < time()) {
fclose($resource);
return false;
}
while (($line = fgets($resource)) !== false) {
$data .= $line;
}
fclose($resource);
return unserialize($data);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$lifetime = -1;
$filename = $this->getFilename($id);
if (! is_file($filename)) {
return false;
}
$resource = fopen($filename, 'r');
$line = fgets($resource);
if ($line !== false) {
$lifetime = (int) $line;
}
fclose($resource);
return $lifetime === 0 || $lifetime > time();
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
if ($lifeTime > 0) {
$lifeTime = time() + $lifeTime;
}
$data = serialize($data);
$filename = $this->getFilename($id);
return $this->writeFile($filename, $lifeTime . PHP_EOL . $data);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache that can be flushed.
*
* @link www.doctrine-project.org
*/
interface FlushableCache
{
/**
* Flushes all cache entries, globally.
*
* @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise.
*/
public function flushAll();
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Doctrine\Common\Cache;
use InvalidArgumentException;
use function sprintf;
/**
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
final class InvalidCacheId extends InvalidArgumentException
{
/**
* @param mixed $id
*/
public static function exceedsMaxLength($id, int $maxLength): self
{
return new self(sprintf('Cache id "%s" exceeds maximum length %d', $id, $maxLength));
}
/**
* @param mixed $id
*/
public static function containsUnauthorizedCharacter($id, string $character): self
{
return new self(sprintf('Cache id "%s" contains unauthorized character "%s"', $id, $character));
}
/**
* @param mixed $id
*/
public static function containsControlCharacter($id): self
{
return new self(sprintf('Cache id "%s" contains at least one control character', $id));
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Doctrine\Common\Cache;
use MongoBinData;
use MongoCollection;
use MongoCursorException;
use MongoDate;
use function serialize;
use function time;
use function trigger_error;
use function unserialize;
use const E_USER_DEPRECATED;
/**
* MongoDB cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class LegacyMongoDBCache extends CacheProvider
{
/** @var MongoCollection */
private $collection;
/** @var bool */
private $expirationIndexCreated = false;
/**
* This provider will default to the write concern and read preference
* options set on the MongoCollection instance (or inherited from MongoDB or
* MongoClient). Using an unacknowledged write concern (< 1) may make the
* return values of delete() and save() unreliable. Reading from secondaries
* may make contain() and fetch() unreliable.
*
* @see http://www.php.net/manual/en/mongo.readpreferences.php
* @see http://www.php.net/manual/en/mongo.writeconcerns.php
*/
public function __construct(MongoCollection $collection)
{
@trigger_error('Using the legacy MongoDB cache provider is deprecated and will be removed in 2.0', E_USER_DEPRECATED);
$this->collection = $collection;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$document = $this->collection->findOne(['_id' => $id], [MongoDBCache::DATA_FIELD, MongoDBCache::EXPIRATION_FIELD]);
if ($document === null) {
return false;
}
if ($this->isExpired($document)) {
$this->createExpirationIndex();
$this->doDelete($id);
return false;
}
return unserialize($document[MongoDBCache::DATA_FIELD]->bin);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$document = $this->collection->findOne(['_id' => $id], [MongoDBCache::EXPIRATION_FIELD]);
if ($document === null) {
return false;
}
if ($this->isExpired($document)) {
$this->createExpirationIndex();
$this->doDelete($id);
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
try {
$result = $this->collection->update(
['_id' => $id],
[
'$set' => [
MongoDBCache::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
MongoDBCache::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
],
],
['upsert' => true, 'multiple' => false]
);
} catch (MongoCursorException $e) {
return false;
}
return ($result['ok'] ?? 1) == 1;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
$result = $this->collection->remove(['_id' => $id]);
return ($result['ok'] ?? 1) == 1;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
// Use remove() in lieu of drop() to maintain any collection indexes
$result = $this->collection->remove();
return ($result['ok'] ?? 1) == 1;
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$serverStatus = $this->collection->db->command([
'serverStatus' => 1,
'locks' => 0,
'metrics' => 0,
'recordStats' => 0,
'repl' => 0,
]);
$collStats = $this->collection->db->command(['collStats' => 1]);
return [
Cache::STATS_HITS => null,
Cache::STATS_MISSES => null,
Cache::STATS_UPTIME => $serverStatus['uptime'] ?? null,
Cache::STATS_MEMORY_USAGE => $collStats['size'] ?? null,
Cache::STATS_MEMORY_AVAILABLE => null,
];
}
/**
* Check if the document is expired.
*
* @param mixed[] $document
*/
private function isExpired(array $document): bool
{
return isset($document[MongoDBCache::EXPIRATION_FIELD]) &&
$document[MongoDBCache::EXPIRATION_FIELD] instanceof MongoDate &&
$document[MongoDBCache::EXPIRATION_FIELD]->sec < time();
}
private function createExpirationIndex(): void
{
if ($this->expirationIndexCreated) {
return;
}
$this->expirationIndexCreated = true;
$this->collection->createIndex([MongoDBCache::EXPIRATION_FIELD => 1], ['background' => true, 'expireAfterSeconds' => 0]);
}
}

View File

@@ -0,0 +1,105 @@
<?php
namespace Doctrine\Common\Cache;
use Memcache;
use function time;
/**
* Memcache cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class MemcacheCache extends CacheProvider
{
/** @var Memcache|null */
private $memcache;
/**
* Sets the memcache instance to use.
*
* @return void
*/
public function setMemcache(Memcache $memcache)
{
$this->memcache = $memcache;
}
/**
* Gets the memcache instance used by the cache.
*
* @return Memcache|null
*/
public function getMemcache()
{
return $this->memcache;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->memcache->get($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$flags = null;
$this->memcache->get($id, $flags);
//if memcache has changed the value of "flags", it means the value exists
return $flags !== null;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
if ($lifeTime > 30 * 24 * 3600) {
$lifeTime = time() + $lifeTime;
}
return $this->memcache->set($id, $data, 0, (int) $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
// Memcache::delete() returns false if entry does not exist
return $this->memcache->delete($id) || ! $this->doContains($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return $this->memcache->flush();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$stats = $this->memcache->getStats();
return [
Cache::STATS_HITS => $stats['get_hits'],
Cache::STATS_MISSES => $stats['get_misses'],
Cache::STATS_UPTIME => $stats['uptime'],
Cache::STATS_MEMORY_USAGE => $stats['bytes'],
Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'],
];
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace Doctrine\Common\Cache;
use Memcached;
use function array_keys;
use function preg_match;
use function strlen;
use function strpos;
use function time;
/**
* Memcached cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class MemcachedCache extends CacheProvider
{
public const CACHE_ID_MAX_LENGTH = 250;
/** @var Memcached|null */
private $memcached;
/**
* Sets the memcache instance to use.
*
* @return void
*/
public function setMemcached(Memcached $memcached)
{
$this->memcached = $memcached;
}
/**
* Gets the memcached instance used by the cache.
*
* @return Memcached|null
*/
public function getMemcached()
{
return $this->memcached;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->memcached->get($id);
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
return $this->memcached->getMulti($keys) ?: [];
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
foreach (array_keys($keysAndValues) as $id) {
$this->validateCacheId($id);
}
if ($lifetime > 30 * 24 * 3600) {
$lifetime = time() + $lifetime;
}
return $this->memcached->setMulti($keysAndValues, $lifetime);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$this->memcached->get($id);
return $this->memcached->getResultCode() === Memcached::RES_SUCCESS;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$this->validateCacheId($id);
if ($lifeTime > 30 * 24 * 3600) {
$lifeTime = time() + $lifeTime;
}
return $this->memcached->set($id, $data, (int) $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDeleteMultiple(array $keys)
{
return $this->memcached->deleteMulti($keys)
|| $this->memcached->getResultCode() === Memcached::RES_NOTFOUND;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->memcached->delete($id)
|| $this->memcached->getResultCode() === Memcached::RES_NOTFOUND;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return $this->memcached->flush();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$stats = $this->memcached->getStats();
$servers = $this->memcached->getServerList();
$key = $servers[0]['host'] . ':' . $servers[0]['port'];
$stats = $stats[$key];
return [
Cache::STATS_HITS => $stats['get_hits'],
Cache::STATS_MISSES => $stats['get_misses'],
Cache::STATS_UPTIME => $stats['uptime'],
Cache::STATS_MEMORY_USAGE => $stats['bytes'],
Cache::STATS_MEMORY_AVAILABLE => $stats['limit_maxbytes'],
];
}
/**
* Validate the cache id
*
* @see https://github.com/memcached/memcached/blob/1.5.12/doc/protocol.txt#L41-L49
*
* @param string $id
*
* @return void
*
* @throws InvalidCacheId
*/
private function validateCacheId($id)
{
if (strlen($id) > self::CACHE_ID_MAX_LENGTH) {
throw InvalidCacheId::exceedsMaxLength($id, self::CACHE_ID_MAX_LENGTH);
}
if (strpos($id, ' ') !== false) {
throw InvalidCacheId::containsUnauthorizedCharacter($id, ' ');
}
if (preg_match('/[\t\r\n]/', $id) === 1) {
throw InvalidCacheId::containsControlCharacter($id);
}
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace Doctrine\Common\Cache;
use InvalidArgumentException;
use MongoCollection;
use MongoDB\Collection;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* MongoDB cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class MongoDBCache extends CacheProvider
{
/**
* The data field will store the serialized PHP value.
*/
public const DATA_FIELD = 'd';
/**
* The expiration field will store a MongoDate value indicating when the
* cache entry should expire.
*
* With MongoDB 2.2+, entries can be automatically deleted by MongoDB by
* indexing this field with the "expireAfterSeconds" option equal to zero.
* This will direct MongoDB to regularly query for and delete any entries
* whose date is older than the current time. Entries without a date value
* in this field will be ignored.
*
* The cache provider will also check dates on its own, in case expired
* entries are fetched before MongoDB's TTLMonitor pass can expire them.
*
* @see http://docs.mongodb.org/manual/tutorial/expire-data/
*/
public const EXPIRATION_FIELD = 'e';
/** @var CacheProvider */
private $provider;
/**
* This provider will default to the write concern and read preference
* options set on the collection instance (or inherited from MongoDB or
* MongoClient). Using an unacknowledged write concern (< 1) may make the
* return values of delete() and save() unreliable. Reading from secondaries
* may make contain() and fetch() unreliable.
*
* @see http://www.php.net/manual/en/mongo.readpreferences.php
* @see http://www.php.net/manual/en/mongo.writeconcerns.php
*
* @param MongoCollection|Collection $collection
*/
public function __construct($collection)
{
if ($collection instanceof MongoCollection) {
@trigger_error('Using a MongoCollection instance for creating a cache adapter is deprecated and will be removed in 2.0', E_USER_DEPRECATED);
$this->provider = new LegacyMongoDBCache($collection);
} elseif ($collection instanceof Collection) {
$this->provider = new ExtMongoDBCache($collection);
} else {
throw new InvalidArgumentException('Invalid collection given - expected a MongoCollection or MongoDB\Collection instance');
}
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->provider->doFetch($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return $this->provider->doContains($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return $this->provider->doSave($id, $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->provider->doDelete($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return $this->provider->doFlush();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
return $this->provider->doGetStats();
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache drivers that allows to put many items at once.
*
* @deprecated
*
* @link www.doctrine-project.org
*/
interface MultiDeleteCache
{
/**
* Deletes several cache entries.
*
* @param string[] $keys Array of keys to delete from cache
*
* @return bool TRUE if the operation was successful, FALSE if it wasn't.
*/
public function deleteMultiple(array $keys);
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache drivers that allows to get many items at once.
*
* @deprecated
*
* @link www.doctrine-project.org
*/
interface MultiGetCache
{
/**
* Returns an associative array of values for keys is found in cache.
*
* @param string[] $keys Array of keys to retrieve from cache
*
* @return mixed[] Array of retrieved values, indexed by the specified keys.
* Values that couldn't be retrieved are not contained in this array.
*/
public function fetchMultiple(array $keys);
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache drivers that supports multiple items manipulation.
*
* @link www.doctrine-project.org
*/
interface MultiOperationCache extends MultiGetCache, MultiDeleteCache, MultiPutCache
{
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Interface for cache drivers that allows to put many items at once.
*
* @deprecated
*
* @link www.doctrine-project.org
*/
interface MultiPutCache
{
/**
* Returns a boolean value indicating if the operation succeeded.
*
* @param mixed[] $keysAndValues Array of keys and values to save in cache
* @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these
* cache entries (0 => infinite lifeTime).
*
* @return bool TRUE if the operation was successful, FALSE if it wasn't.
*/
public function saveMultiple(array $keysAndValues, $lifetime = 0);
}

View File

@@ -0,0 +1,120 @@
<?php
namespace Doctrine\Common\Cache;
use function is_object;
use function method_exists;
use function restore_error_handler;
use function serialize;
use function set_error_handler;
use function sprintf;
use function time;
use function var_export;
/**
* Php file cache driver.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class PhpFileCache extends FileCache
{
public const EXTENSION = '.doctrinecache.php';
/**
* @var callable
*
* This is cached in a local static variable to avoid instantiating a closure each time we need an empty handler
*/
private static $emptyErrorHandler;
/**
* {@inheritdoc}
*/
public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
{
parent::__construct($directory, $extension, $umask);
self::$emptyErrorHandler = static function () {
};
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$value = $this->includeFileForId($id);
if ($value === null) {
return false;
}
if ($value['lifetime'] !== 0 && $value['lifetime'] < time()) {
return false;
}
return $value['data'];
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$value = $this->includeFileForId($id);
if ($value === null) {
return false;
}
return $value['lifetime'] === 0 || $value['lifetime'] > time();
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
if ($lifeTime > 0) {
$lifeTime = time() + $lifeTime;
}
$filename = $this->getFilename($id);
$value = [
'lifetime' => $lifeTime,
'data' => $data,
];
if (is_object($data) && method_exists($data, '__set_state')) {
$value = var_export($value, true);
$code = sprintf('<?php return %s;', $value);
} else {
$value = var_export(serialize($value), true);
$code = sprintf('<?php return unserialize(%s);', $value);
}
return $this->writeFile($filename, $code);
}
/**
* @return mixed[]|null
*/
private function includeFileForId(string $id): ?array
{
$fileName = $this->getFilename($id);
// note: error suppression is still faster than `file_exists`, `is_file` and `is_readable`
set_error_handler(self::$emptyErrorHandler);
$value = include $fileName;
restore_error_handler();
if (! isset($value['lifetime'])) {
return null;
}
return $value;
}
}

View File

@@ -0,0 +1,147 @@
<?php
namespace Doctrine\Common\Cache;
use Predis\ClientInterface;
use function array_combine;
use function array_filter;
use function array_map;
use function array_values;
use function call_user_func_array;
use function serialize;
use function unserialize;
/**
* Predis cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class PredisCache extends CacheProvider
{
/** @var ClientInterface */
private $client;
public function __construct(ClientInterface $client)
{
$this->client = $client;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$result = $this->client->get($id);
if ($result === null) {
return false;
}
return unserialize($result);
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
$fetchedItems = call_user_func_array([$this->client, 'mget'], array_values($keys));
return array_map('unserialize', array_filter(array_combine($keys, $fetchedItems)));
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
if ($lifetime) {
$success = true;
// Keys have lifetime, use SETEX for each of them
foreach ($keysAndValues as $key => $value) {
$response = (string) $this->client->setex($key, $lifetime, serialize($value));
if ($response == 'OK') {
continue;
}
$success = false;
}
return $success;
}
// No lifetime, use MSET
$response = $this->client->mset(array_map(static function ($value) {
return serialize($value);
}, $keysAndValues));
return (string) $response == 'OK';
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return (bool) $this->client->exists($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$data = serialize($data);
if ($lifeTime > 0) {
$response = $this->client->setex($id, $lifeTime, $data);
} else {
$response = $this->client->set($id, $data);
}
return $response === true || $response == 'OK';
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->client->del($id) >= 0;
}
/**
* {@inheritdoc}
*/
protected function doDeleteMultiple(array $keys)
{
return $this->client->del($keys) >= 0;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$response = $this->client->flushdb();
return $response === true || $response == 'OK';
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$info = $this->client->info();
return [
Cache::STATS_HITS => $info['Stats']['keyspace_hits'],
Cache::STATS_MISSES => $info['Stats']['keyspace_misses'],
Cache::STATS_UPTIME => $info['Server']['uptime_in_seconds'],
Cache::STATS_MEMORY_USAGE => $info['Memory']['used_memory'],
Cache::STATS_MEMORY_AVAILABLE => false,
];
}
}

View File

@@ -0,0 +1,340 @@
<?php
namespace Doctrine\Common\Cache\Psr6;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\ClearableCache;
use Doctrine\Common\Cache\MultiDeleteCache;
use Doctrine\Common\Cache\MultiGetCache;
use Doctrine\Common\Cache\MultiPutCache;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\DoctrineProvider as SymfonyDoctrineProvider;
use function array_key_exists;
use function assert;
use function count;
use function current;
use function get_class;
use function gettype;
use function is_object;
use function is_string;
use function microtime;
use function sprintf;
use function strpbrk;
use const PHP_VERSION_ID;
final class CacheAdapter implements CacheItemPoolInterface
{
private const RESERVED_CHARACTERS = '{}()/\@:';
/** @var Cache */
private $cache;
/** @var array<CacheItem|TypedCacheItem> */
private $deferredItems = [];
public static function wrap(Cache $cache): CacheItemPoolInterface
{
if ($cache instanceof DoctrineProvider && ! $cache->getNamespace()) {
return $cache->getPool();
}
if ($cache instanceof SymfonyDoctrineProvider && ! $cache->getNamespace()) {
$getPool = function () {
// phpcs:ignore Squiz.Scope.StaticThisUsage.Found
return $this->pool;
};
return $getPool->bindTo($cache, SymfonyDoctrineProvider::class)();
}
return new self($cache);
}
private function __construct(Cache $cache)
{
$this->cache = $cache;
}
/** @internal */
public function getCache(): Cache
{
return $this->cache;
}
/**
* {@inheritDoc}
*/
public function getItem($key): CacheItemInterface
{
assert(self::validKey($key));
if (isset($this->deferredItems[$key])) {
$this->commit();
}
$value = $this->cache->fetch($key);
if (PHP_VERSION_ID >= 80000) {
if ($value !== false) {
return new TypedCacheItem($key, $value, true);
}
return new TypedCacheItem($key, null, false);
}
if ($value !== false) {
return new CacheItem($key, $value, true);
}
return new CacheItem($key, null, false);
}
/**
* {@inheritDoc}
*/
public function getItems(array $keys = []): array
{
if ($this->deferredItems) {
$this->commit();
}
assert(self::validKeys($keys));
$values = $this->doFetchMultiple($keys);
$items = [];
if (PHP_VERSION_ID >= 80000) {
foreach ($keys as $key) {
if (array_key_exists($key, $values)) {
$items[$key] = new TypedCacheItem($key, $values[$key], true);
} else {
$items[$key] = new TypedCacheItem($key, null, false);
}
}
return $items;
}
foreach ($keys as $key) {
if (array_key_exists($key, $values)) {
$items[$key] = new CacheItem($key, $values[$key], true);
} else {
$items[$key] = new CacheItem($key, null, false);
}
}
return $items;
}
/**
* {@inheritDoc}
*/
public function hasItem($key): bool
{
assert(self::validKey($key));
if (isset($this->deferredItems[$key])) {
$this->commit();
}
return $this->cache->contains($key);
}
public function clear(): bool
{
$this->deferredItems = [];
if (! $this->cache instanceof ClearableCache) {
return false;
}
return $this->cache->deleteAll();
}
/**
* {@inheritDoc}
*/
public function deleteItem($key): bool
{
assert(self::validKey($key));
unset($this->deferredItems[$key]);
return $this->cache->delete($key);
}
/**
* {@inheritDoc}
*/
public function deleteItems(array $keys): bool
{
foreach ($keys as $key) {
assert(self::validKey($key));
unset($this->deferredItems[$key]);
}
return $this->doDeleteMultiple($keys);
}
public function save(CacheItemInterface $item): bool
{
return $this->saveDeferred($item) && $this->commit();
}
public function saveDeferred(CacheItemInterface $item): bool
{
if (! $item instanceof CacheItem && ! $item instanceof TypedCacheItem) {
return false;
}
$this->deferredItems[$item->getKey()] = $item;
return true;
}
public function commit(): bool
{
if (! $this->deferredItems) {
return true;
}
$now = microtime(true);
$itemsCount = 0;
$byLifetime = [];
$expiredKeys = [];
foreach ($this->deferredItems as $key => $item) {
$lifetime = ($item->getExpiry() ?? $now) - $now;
if ($lifetime < 0) {
$expiredKeys[] = $key;
continue;
}
++$itemsCount;
$byLifetime[(int) $lifetime][$key] = $item->get();
}
$this->deferredItems = [];
switch (count($expiredKeys)) {
case 0:
break;
case 1:
$this->cache->delete(current($expiredKeys));
break;
default:
$this->doDeleteMultiple($expiredKeys);
break;
}
if ($itemsCount === 1) {
return $this->cache->save($key, $item->get(), (int) $lifetime);
}
$success = true;
foreach ($byLifetime as $lifetime => $values) {
$success = $this->doSaveMultiple($values, $lifetime) && $success;
}
return $success;
}
public function __destruct()
{
$this->commit();
}
/**
* @param mixed $key
*/
private static function validKey($key): bool
{
if (! is_string($key)) {
throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
}
if ($key === '') {
throw new InvalidArgument('Cache key length must be greater than zero.');
}
if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) {
throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
}
return true;
}
/**
* @param mixed[] $keys
*/
private static function validKeys(array $keys): bool
{
foreach ($keys as $key) {
self::validKey($key);
}
return true;
}
/**
* @param mixed[] $keys
*/
private function doDeleteMultiple(array $keys): bool
{
if ($this->cache instanceof MultiDeleteCache) {
return $this->cache->deleteMultiple($keys);
}
$success = true;
foreach ($keys as $key) {
$success = $this->cache->delete($key) && $success;
}
return $success;
}
/**
* @param mixed[] $keys
*
* @return mixed[]
*/
private function doFetchMultiple(array $keys): array
{
if ($this->cache instanceof MultiGetCache) {
return $this->cache->fetchMultiple($keys);
}
$values = [];
foreach ($keys as $key) {
$value = $this->cache->fetch($key);
if (! $value) {
continue;
}
$values[$key] = $value;
}
return $values;
}
/**
* @param mixed[] $keysAndValues
*/
private function doSaveMultiple(array $keysAndValues, int $lifetime = 0): bool
{
if ($this->cache instanceof MultiPutCache) {
return $this->cache->saveMultiple($keysAndValues, $lifetime);
}
$success = true;
foreach ($keysAndValues as $key => $value) {
$success = $this->cache->save($key, $value, $lifetime) && $success;
}
return $success;
}
}

View File

@@ -0,0 +1,118 @@
<?php
namespace Doctrine\Common\Cache\Psr6;
use DateInterval;
use DateTime;
use DateTimeInterface;
use Psr\Cache\CacheItemInterface;
use TypeError;
use function get_class;
use function gettype;
use function is_int;
use function is_object;
use function microtime;
use function sprintf;
final class CacheItem implements CacheItemInterface
{
/** @var string */
private $key;
/** @var mixed */
private $value;
/** @var bool */
private $isHit;
/** @var float|null */
private $expiry;
/**
* @internal
*
* @param mixed $data
*/
public function __construct(string $key, $data, bool $isHit)
{
$this->key = $key;
$this->value = $data;
$this->isHit = $isHit;
}
public function getKey(): string
{
return $this->key;
}
/**
* {@inheritDoc}
*
* @return mixed
*/
public function get()
{
return $this->value;
}
public function isHit(): bool
{
return $this->isHit;
}
/**
* {@inheritDoc}
*/
public function set($value): self
{
$this->value = $value;
return $this;
}
/**
* {@inheritDoc}
*/
public function expiresAt($expiration): self
{
if ($expiration === null) {
$this->expiry = null;
} elseif ($expiration instanceof DateTimeInterface) {
$this->expiry = (float) $expiration->format('U.u');
} else {
throw new TypeError(sprintf(
'Expected $expiration to be an instance of DateTimeInterface or null, got %s',
is_object($expiration) ? get_class($expiration) : gettype($expiration)
));
}
return $this;
}
/**
* {@inheritDoc}
*/
public function expiresAfter($time): self
{
if ($time === null) {
$this->expiry = null;
} elseif ($time instanceof DateInterval) {
$this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
} elseif (is_int($time)) {
$this->expiry = $time + microtime(true);
} else {
throw new TypeError(sprintf(
'Expected $time to be either an integer, an instance of DateInterval or null, got %s',
is_object($time) ? get_class($time) : gettype($time)
));
}
return $this;
}
/**
* @internal
*/
public function getExpiry(): ?float
{
return $this->expiry;
}
}

View File

@@ -0,0 +1,125 @@
<?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 Doctrine\Common\Cache\Psr6;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\DoctrineAdapter as SymfonyDoctrineAdapter;
use function rawurlencode;
/**
* This class was copied from the Symfony Framework, see the original copyright
* notice above. The code is distributed subject to the license terms in
* https://github.com/symfony/symfony/blob/ff0cf61278982539c49e467db9ab13cbd342f76d/LICENSE
*/
final class DoctrineProvider extends CacheProvider
{
/** @var CacheItemPoolInterface */
private $pool;
public static function wrap(CacheItemPoolInterface $pool): Cache
{
if ($pool instanceof CacheAdapter) {
return $pool->getCache();
}
if ($pool instanceof SymfonyDoctrineAdapter) {
$getCache = function () {
// phpcs:ignore Squiz.Scope.StaticThisUsage.Found
return $this->provider;
};
return $getCache->bindTo($pool, SymfonyDoctrineAdapter::class)();
}
return new self($pool);
}
private function __construct(CacheItemPoolInterface $pool)
{
$this->pool = $pool;
}
/** @internal */
public function getPool(): CacheItemPoolInterface
{
return $this->pool;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$item = $this->pool->getItem(rawurlencode($id));
return $item->isHit() ? $item->get() : false;
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doContains($id)
{
return $this->pool->hasItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*
* @return bool
*/
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}
*
* @return bool
*/
protected function doDelete($id)
{
return $this->pool->deleteItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doFlush()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*
* @return array|null
*/
protected function doGetStats()
{
return null;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Doctrine\Common\Cache\Psr6;
use InvalidArgumentException;
use Psr\Cache\InvalidArgumentException as PsrInvalidArgumentException;
/**
* @internal
*/
final class InvalidArgument extends InvalidArgumentException implements PsrInvalidArgumentException
{
}

View File

@@ -0,0 +1,99 @@
<?php
namespace Doctrine\Common\Cache\Psr6;
use DateInterval;
use DateTime;
use DateTimeInterface;
use Psr\Cache\CacheItemInterface;
use TypeError;
use function get_debug_type;
use function is_int;
use function microtime;
use function sprintf;
final class TypedCacheItem implements CacheItemInterface
{
private ?float $expiry = null;
/**
* @internal
*/
public function __construct(
private string $key,
private mixed $value,
private bool $isHit,
) {
}
public function getKey(): string
{
return $this->key;
}
public function get(): mixed
{
return $this->value;
}
public function isHit(): bool
{
return $this->isHit;
}
public function set(mixed $value): static
{
$this->value = $value;
return $this;
}
/**
* {@inheritDoc}
*/
public function expiresAt($expiration): static
{
if ($expiration === null) {
$this->expiry = null;
} elseif ($expiration instanceof DateTimeInterface) {
$this->expiry = (float) $expiration->format('U.u');
} else {
throw new TypeError(sprintf(
'Expected $expiration to be an instance of DateTimeInterface or null, got %s',
get_debug_type($expiration)
));
}
return $this;
}
/**
* {@inheritDoc}
*/
public function expiresAfter($time): static
{
if ($time === null) {
$this->expiry = null;
} elseif ($time instanceof DateInterval) {
$this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u');
} elseif (is_int($time)) {
$this->expiry = $time + microtime(true);
} else {
throw new TypeError(sprintf(
'Expected $time to be either an integer, an instance of DateInterval or null, got %s',
get_debug_type($time)
));
}
return $this;
}
/**
* @internal
*/
public function getExpiry(): ?float
{
return $this->expiry;
}
}

View File

@@ -0,0 +1,186 @@
<?php
namespace Doctrine\Common\Cache;
use Redis;
use function array_combine;
use function array_diff_key;
use function array_fill_keys;
use function array_filter;
use function array_keys;
use function count;
use function defined;
use function extension_loaded;
use function is_bool;
/**
* Redis cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class RedisCache extends CacheProvider
{
/** @var Redis|null */
private $redis;
/**
* Sets the redis instance to use.
*
* @return void
*/
public function setRedis(Redis $redis)
{
$redis->setOption(Redis::OPT_SERIALIZER, $this->getSerializerValue());
$this->redis = $redis;
}
/**
* Gets the redis instance used by the cache.
*
* @return Redis|null
*/
public function getRedis()
{
return $this->redis;
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->redis->get($id);
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
$fetchedItems = array_combine($keys, $this->redis->mget($keys));
// Redis mget returns false for keys that do not exist. So we need to filter those out unless it's the real data.
$keysToFilter = array_keys(array_filter($fetchedItems, static function ($item): bool {
return $item === false;
}));
if ($keysToFilter) {
$multi = $this->redis->multi(Redis::PIPELINE);
foreach ($keysToFilter as $key) {
$multi->exists($key);
}
$existItems = array_filter($multi->exec());
$missedItemKeys = array_diff_key($keysToFilter, $existItems);
$fetchedItems = array_diff_key($fetchedItems, array_fill_keys($missedItemKeys, true));
}
return $fetchedItems;
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
if ($lifetime) {
// Keys have lifetime, use SETEX for each of them
$multi = $this->redis->multi(Redis::PIPELINE);
foreach ($keysAndValues as $key => $value) {
$multi->setex($key, $lifetime, $value);
}
$succeeded = array_filter($multi->exec());
return count($succeeded) == count($keysAndValues);
}
// No lifetime, use MSET
return (bool) $this->redis->mset($keysAndValues);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
$exists = $this->redis->exists($id);
if (is_bool($exists)) {
return $exists;
}
return $exists > 0;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
if ($lifeTime > 0) {
return $this->redis->setex($id, $lifeTime, $data);
}
return $this->redis->set($id, $data);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return $this->redis->del($id) >= 0;
}
/**
* {@inheritdoc}
*/
protected function doDeleteMultiple(array $keys)
{
return $this->redis->del($keys) >= 0;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return $this->redis->flushDB();
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$info = $this->redis->info();
return [
Cache::STATS_HITS => $info['keyspace_hits'],
Cache::STATS_MISSES => $info['keyspace_misses'],
Cache::STATS_UPTIME => $info['uptime_in_seconds'],
Cache::STATS_MEMORY_USAGE => $info['used_memory'],
Cache::STATS_MEMORY_AVAILABLE => false,
];
}
/**
* Returns the serializer constant to use. If Redis is compiled with
* igbinary support, that is used. Otherwise the default PHP serializer is
* used.
*
* @return int One of the Redis::SERIALIZER_* constants
*/
protected function getSerializerValue()
{
if (defined('Redis::SERIALIZER_IGBINARY') && extension_loaded('igbinary')) {
return Redis::SERIALIZER_IGBINARY;
}
return Redis::SERIALIZER_PHP;
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace Doctrine\Common\Cache;
use SQLite3;
use SQLite3Result;
use function array_search;
use function implode;
use function serialize;
use function sprintf;
use function time;
use function unserialize;
use const SQLITE3_ASSOC;
use const SQLITE3_BLOB;
use const SQLITE3_TEXT;
/**
* SQLite3 cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class SQLite3Cache extends CacheProvider
{
/**
* The ID field will store the cache key.
*/
public const ID_FIELD = 'k';
/**
* The data field will store the serialized PHP value.
*/
public const DATA_FIELD = 'd';
/**
* The expiration field will store a date value indicating when the
* cache entry should expire.
*/
public const EXPIRATION_FIELD = 'e';
/** @var SQLite3 */
private $sqlite;
/** @var string */
private $table;
/**
* Calling the constructor will ensure that the database file and table
* exist and will create both if they don't.
*
* @param string $table
*/
public function __construct(SQLite3 $sqlite, $table)
{
$this->sqlite = $sqlite;
$this->table = (string) $table;
$this->ensureTableExists();
}
private function ensureTableExists(): void
{
$this->sqlite->exec(
sprintf(
'CREATE TABLE IF NOT EXISTS %s(%s TEXT PRIMARY KEY NOT NULL, %s BLOB, %s INTEGER)',
$this->table,
static::ID_FIELD,
static::DATA_FIELD,
static::EXPIRATION_FIELD
)
);
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$item = $this->findById($id);
if (! $item) {
return false;
}
return unserialize($item[self::DATA_FIELD]);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return $this->findById($id, false) !== null;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$statement = $this->sqlite->prepare(sprintf(
'INSERT OR REPLACE INTO %s (%s) VALUES (:id, :data, :expire)',
$this->table,
implode(',', $this->getFields())
));
$statement->bindValue(':id', $id);
$statement->bindValue(':data', serialize($data), SQLITE3_BLOB);
$statement->bindValue(':expire', $lifeTime > 0 ? time() + $lifeTime : null);
return $statement->execute() instanceof SQLite3Result;
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
[$idField] = $this->getFields();
$statement = $this->sqlite->prepare(sprintf(
'DELETE FROM %s WHERE %s = :id',
$this->table,
$idField
));
$statement->bindValue(':id', $id);
return $statement->execute() instanceof SQLite3Result;
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return $this->sqlite->exec(sprintf('DELETE FROM %s', $this->table));
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
// no-op.
}
/**
* Find a single row by ID.
*
* @param mixed $id
*
* @return mixed[]|null
*/
private function findById($id, bool $includeData = true): ?array
{
[$idField] = $fields = $this->getFields();
if (! $includeData) {
$key = array_search(static::DATA_FIELD, $fields);
unset($fields[$key]);
}
$statement = $this->sqlite->prepare(sprintf(
'SELECT %s FROM %s WHERE %s = :id LIMIT 1',
implode(',', $fields),
$this->table,
$idField
));
$statement->bindValue(':id', $id, SQLITE3_TEXT);
$item = $statement->execute()->fetchArray(SQLITE3_ASSOC);
if ($item === false) {
return null;
}
if ($this->isExpired($item)) {
$this->doDelete($id);
return null;
}
return $item;
}
/**
* Gets an array of the fields in our table.
*
* @psalm-return array{string, string, string}
*/
private function getFields(): array
{
return [static::ID_FIELD, static::DATA_FIELD, static::EXPIRATION_FIELD];
}
/**
* Check if the item is expired.
*
* @param mixed[] $item
*/
private function isExpired(array $item): bool
{
return isset($item[static::EXPIRATION_FIELD]) &&
$item[self::EXPIRATION_FIELD] !== null &&
$item[self::EXPIRATION_FIELD] < time();
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Doctrine\Common\Cache;
/**
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*/
class Version
{
public const VERSION = '1.9.0-DEV';
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Doctrine\Common\Cache;
/**
* Void cache driver. The cache could be of use in tests where you don`t need to cache anything.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class VoidCache extends CacheProvider
{
/**
* {@inheritDoc}
*/
protected function doFetch($id)
{
return false;
}
/**
* {@inheritDoc}
*/
protected function doContains($id)
{
return false;
}
/**
* {@inheritDoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return true;
}
/**
* {@inheritDoc}
*/
protected function doDelete($id)
{
return true;
}
/**
* {@inheritDoc}
*/
protected function doFlush()
{
return true;
}
/**
* {@inheritDoc}
*/
protected function doGetStats()
{
return;
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace Doctrine\Common\Cache;
use function count;
use function is_array;
use function wincache_ucache_clear;
use function wincache_ucache_delete;
use function wincache_ucache_exists;
use function wincache_ucache_get;
use function wincache_ucache_info;
use function wincache_ucache_meminfo;
use function wincache_ucache_set;
/**
* WinCache cache provider.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class WinCacheCache extends CacheProvider
{
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return wincache_ucache_get($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return wincache_ucache_exists($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return wincache_ucache_set($id, $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return wincache_ucache_delete($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
return wincache_ucache_clear();
}
/**
* {@inheritdoc}
*/
protected function doFetchMultiple(array $keys)
{
return wincache_ucache_get($keys);
}
/**
* {@inheritdoc}
*/
protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
{
$result = wincache_ucache_set($keysAndValues, null, $lifetime);
return empty($result);
}
/**
* {@inheritdoc}
*/
protected function doDeleteMultiple(array $keys)
{
$result = wincache_ucache_delete($keys);
return is_array($result) && count($result) !== count($keys);
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$info = wincache_ucache_info();
$meminfo = wincache_ucache_meminfo();
return [
Cache::STATS_HITS => $info['total_hit_count'],
Cache::STATS_MISSES => $info['total_miss_count'],
Cache::STATS_UPTIME => $info['total_cache_uptime'],
Cache::STATS_MEMORY_USAGE => $meminfo['memory_total'],
Cache::STATS_MEMORY_AVAILABLE => $meminfo['memory_free'],
];
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Doctrine\Common\Cache;
use BadMethodCallException;
use function ini_get;
use function serialize;
use function unserialize;
use function xcache_clear_cache;
use function xcache_get;
use function xcache_info;
use function xcache_isset;
use function xcache_set;
use function xcache_unset;
use const XC_TYPE_VAR;
/**
* Xcache cache driver.
*
* @deprecated
*
* @link www.doctrine-project.org
*/
class XcacheCache extends CacheProvider
{
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return $this->doContains($id) ? unserialize(xcache_get($id)) : false;
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return xcache_isset($id);
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return xcache_set($id, serialize($data), (int) $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return xcache_unset($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$this->checkAuthorization();
xcache_clear_cache(XC_TYPE_VAR);
return true;
}
/**
* Checks that xcache.admin.enable_auth is Off.
*
* @return void
*
* @throws BadMethodCallException When xcache.admin.enable_auth is On.
*/
protected function checkAuthorization()
{
if (ini_get('xcache.admin.enable_auth')) {
throw new BadMethodCallException(
'To use all features of \Doctrine\Common\Cache\XcacheCache, '
. 'you must set "xcache.admin.enable_auth" to "Off" in your php.ini.'
);
}
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
$this->checkAuthorization();
$info = xcache_info(XC_TYPE_VAR, 0);
return [
Cache::STATS_HITS => $info['hits'],
Cache::STATS_MISSES => $info['misses'],
Cache::STATS_UPTIME => null,
Cache::STATS_MEMORY_USAGE => $info['size'],
Cache::STATS_MEMORY_AVAILABLE => $info['avail'],
];
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Doctrine\Common\Cache;
use function zend_shm_cache_clear;
use function zend_shm_cache_delete;
use function zend_shm_cache_fetch;
use function zend_shm_cache_store;
/**
* Zend Data Cache cache driver.
*
* @deprecated Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0
*
* @link www.doctrine-project.org
*/
class ZendDataCache extends CacheProvider
{
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
return zend_shm_cache_fetch($id);
}
/**
* {@inheritdoc}
*/
protected function doContains($id)
{
return zend_shm_cache_fetch($id) !== false;
}
/**
* {@inheritdoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return zend_shm_cache_store($id, $data, $lifeTime);
}
/**
* {@inheritdoc}
*/
protected function doDelete($id)
{
return zend_shm_cache_delete($id);
}
/**
* {@inheritdoc}
*/
protected function doFlush()
{
$namespace = $this->getNamespace();
if (empty($namespace)) {
return zend_shm_cache_clear();
}
return zend_shm_cache_clear($namespace);
}
/**
* {@inheritdoc}
*/
protected function doGetStats()
{
return null;
}
}