[Cache] Add argument $prefix to AdapterInterface::clear()
This commit is contained in:
parent
835f6b0373
commit
ad6f6cf900
@ -1,6 +1,11 @@
|
|||||||
UPGRADE FROM 4.3 to 4.4
|
UPGRADE FROM 4.3 to 4.4
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
Cache
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Added argument `$prefix` to `AdapterInterface::clear()`
|
||||||
|
|
||||||
DependencyInjection
|
DependencyInjection
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ Cache
|
|||||||
* Removed `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead.
|
* Removed `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead.
|
||||||
* Removed all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead.
|
* Removed all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead.
|
||||||
* Removed `SimpleCacheAdapter`, use `Psr16Adapter` instead.
|
* Removed `SimpleCacheAdapter`, use `Psr16Adapter` instead.
|
||||||
|
* Added argument `$prefix` to `AdapterInterface::clear()`
|
||||||
|
|
||||||
Config
|
Config
|
||||||
------
|
------
|
||||||
|
@ -34,4 +34,11 @@ interface AdapterInterface extends CacheItemPoolInterface
|
|||||||
* @return \Traversable|CacheItem[]
|
* @return \Traversable|CacheItem[]
|
||||||
*/
|
*/
|
||||||
public function getItems(array $keys = []);
|
public function getItems(array $keys = []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
|
*/
|
||||||
|
public function clear(/*string $prefix = ''*/);
|
||||||
}
|
}
|
||||||
|
@ -192,14 +192,21 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
$cleared = true;
|
$cleared = true;
|
||||||
$i = $this->adapterCount;
|
$i = $this->adapterCount;
|
||||||
|
|
||||||
while ($i--) {
|
while ($i--) {
|
||||||
$cleared = $this->adapters[$i]->clear() && $cleared;
|
if ($this->adapters[$i] instanceof AdapterInterface) {
|
||||||
|
$cleared = $this->adapters[$i]->clear($prefix) && $cleared;
|
||||||
|
} else {
|
||||||
|
$cleared = $this->adapters[$i]->clear() && $cleared;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cleared;
|
return $cleared;
|
||||||
|
@ -75,8 +75,10 @@ class NullAdapter implements AdapterInterface, CacheInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -147,9 +147,17 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
|
|
||||||
|
if ($this->pool instanceof AdapterInterface) {
|
||||||
|
return $this->pool->clear($this->namespace.$prefix);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->pool->clear();
|
return $this->pool->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,10 +213,26 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
$this->deferred = [];
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
|
|
||||||
|
if ('' !== $prefix) {
|
||||||
|
foreach ($this->deferred as $key => $item) {
|
||||||
|
if (0 === strpos($key, $prefix)) {
|
||||||
|
unset($this->deferred[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->deferred = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->pool instanceof AdapterInterface) {
|
||||||
|
return $this->pool->clear($prefix);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->pool->clear();
|
return $this->pool->clear();
|
||||||
}
|
}
|
||||||
|
@ -167,11 +167,18 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
$event = $this->start(__FUNCTION__);
|
$event = $this->start(__FUNCTION__);
|
||||||
try {
|
try {
|
||||||
|
if ($this->pool instanceof AdapterInterface) {
|
||||||
|
return $event->result = $this->pool->clear($prefix);
|
||||||
|
}
|
||||||
|
|
||||||
return $event->result = $this->pool->clear();
|
return $event->result = $this->pool->clear();
|
||||||
} finally {
|
} finally {
|
||||||
$event->end = microtime(true);
|
$event->end = microtime(true);
|
||||||
|
@ -5,6 +5,7 @@ CHANGELOG
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
* added support for connecting to Redis Sentinel clusters
|
* added support for connecting to Redis Sentinel clusters
|
||||||
|
* added argument `$prefix` to `AdapterInterface::clear()`
|
||||||
|
|
||||||
4.3.0
|
4.3.0
|
||||||
-----
|
-----
|
||||||
|
@ -252,6 +252,26 @@ abstract class AdapterTestCase extends CachePoolTest
|
|||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
$this->assertFalse($this->isPruned($cache, 'foo'));
|
||||||
$this->assertTrue($this->isPruned($cache, 'qux'));
|
$this->assertTrue($this->isPruned($cache, 'qux'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testClearPrefix()
|
||||||
|
{
|
||||||
|
if (isset($this->skippedTests[__FUNCTION__])) {
|
||||||
|
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache = $this->createCachePool(0, __FUNCTION__);
|
||||||
|
$cache->clear();
|
||||||
|
|
||||||
|
$item = $cache->getItem('foobar');
|
||||||
|
$cache->save($item->set(1));
|
||||||
|
|
||||||
|
$item = $cache->getItem('barfoo');
|
||||||
|
$cache->save($item->set(2));
|
||||||
|
|
||||||
|
$cache->clear('foo');
|
||||||
|
$this->assertFalse($cache->hasItem('foobar'));
|
||||||
|
$this->assertTrue($cache->hasItem('barfoo'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotUnserializable
|
class NotUnserializable
|
||||||
|
@ -23,6 +23,7 @@ class DoctrineAdapterTest extends AdapterTestCase
|
|||||||
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',
|
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',
|
||||||
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
|
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
|
||||||
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
|
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
|
||||||
|
'testClearPrefix' => 'Doctrine cannot clear by prefix',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
public function createCachePool($defaultLifetime = 0)
|
||||||
|
@ -19,6 +19,7 @@ class MemcachedAdapterTest extends AdapterTestCase
|
|||||||
protected $skippedTests = [
|
protected $skippedTests = [
|
||||||
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
|
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
||||||
|
'testClearPrefix' => 'Memcached cannot clear by prefix',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected static $client;
|
protected static $client;
|
||||||
|
@ -72,7 +72,7 @@ class PhpArrayAdapterTest extends AdapterTestCase
|
|||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0, $testMethod = null)
|
public function createCachePool($defaultLifetime = 0, $testMethod = null)
|
||||||
{
|
{
|
||||||
if ('testGetMetadata' === $testMethod) {
|
if ('testGetMetadata' === $testMethod || 'testClearPrefix' === $testMethod) {
|
||||||
return new PhpArrayAdapter(self::$file, new FilesystemAdapter());
|
return new PhpArrayAdapter(self::$file, new FilesystemAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ class Psr16AdapterTest extends AdapterTestCase
|
|||||||
{
|
{
|
||||||
protected $skippedTests = [
|
protected $skippedTests = [
|
||||||
'testPrune' => 'Psr16adapter just proxies',
|
'testPrune' => 'Psr16adapter just proxies',
|
||||||
|
'testClearPrefix' => 'SimpleCache cannot clear by prefix',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
public function createCachePool($defaultLifetime = 0)
|
||||||
|
@ -23,6 +23,7 @@ class SimpleCacheAdapterTest extends AdapterTestCase
|
|||||||
{
|
{
|
||||||
protected $skippedTests = [
|
protected $skippedTests = [
|
||||||
'testPrune' => 'SimpleCache just proxies',
|
'testPrune' => 'SimpleCache just proxies',
|
||||||
|
'testClearPrefix' => 'SimpleCache cannot clear by prefix',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
public function createCachePool($defaultLifetime = 0)
|
||||||
|
@ -102,9 +102,12 @@ trait AbstractTrait
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
$this->deferred = [];
|
$this->deferred = [];
|
||||||
if ($cleared = $this->versioningIsEnabled) {
|
if ($cleared = $this->versioningIsEnabled) {
|
||||||
$namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
|
$namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
|
||||||
@ -120,7 +123,7 @@ trait AbstractTrait
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $this->doClear($this->namespace) || $cleared;
|
return $this->doClear($this->namespace.$prefix) || $cleared;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]);
|
CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]);
|
||||||
|
|
||||||
|
@ -66,10 +66,22 @@ trait ArrayTrait
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
$this->values = $this->expiries = [];
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
|
|
||||||
|
if ('' !== $prefix) {
|
||||||
|
foreach ($this->values as $key => $value) {
|
||||||
|
if (0 === strpos($key, $prefix)) {
|
||||||
|
unset($this->values[$key], $this->expiries[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->values = $this->expiries = [];
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,10 @@ trait FilesystemCommonTrait
|
|||||||
$ok = true;
|
$ok = true;
|
||||||
|
|
||||||
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
|
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) {
|
||||||
|
if ('' !== $namespace && 0 !== strpos($this->getFileKey($file), $namespace)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$ok = ($file->isDir() || $this->doUnlink($file) || !file_exists($file)) && $ok;
|
$ok = ($file->isDir() || $this->doUnlink($file) || !file_exists($file)) && $ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +118,11 @@ trait FilesystemCommonTrait
|
|||||||
return $dir.substr($hash, 2, 20);
|
return $dir.substr($hash, 2, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getFileKey(string $file): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
@ -108,4 +108,17 @@ trait FilesystemTrait
|
|||||||
|
|
||||||
return $failed;
|
return $failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getFileKey(string $file): string
|
||||||
|
{
|
||||||
|
if (!$h = @fopen($file, 'rb')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
fgets($h); // expiry
|
||||||
|
$encodedKey = fgets($h);
|
||||||
|
fclose($h);
|
||||||
|
|
||||||
|
return rawurldecode(rtrim($encodedKey));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Cache\Traits;
|
namespace Symfony\Component\Cache\Traits;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||||
use Symfony\Component\Cache\CacheItem;
|
use Symfony\Component\Cache\CacheItem;
|
||||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\VarExporter\VarExporter;
|
use Symfony\Component\VarExporter\VarExporter;
|
||||||
@ -121,13 +122,20 @@ EOF;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
*/
|
*/
|
||||||
public function clear()
|
public function clear(/*string $prefix = ''*/)
|
||||||
{
|
{
|
||||||
|
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||||
$this->keys = $this->values = [];
|
$this->keys = $this->values = [];
|
||||||
|
|
||||||
$cleared = @unlink($this->file) || !file_exists($this->file);
|
$cleared = @unlink($this->file) || !file_exists($this->file);
|
||||||
|
|
||||||
|
if ($this->pool instanceof AdapterInterface) {
|
||||||
|
return $this->pool->clear($prefix) && $cleared;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->pool->clear() && $cleared;
|
return $this->pool->clear() && $cleared;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,17 +211,19 @@ trait PhpFilesTrait
|
|||||||
$value = var_export($value, true);
|
$value = var_export($value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$encodedKey = rawurlencode($key);
|
||||||
|
|
||||||
if (!$isStaticValue) {
|
if (!$isStaticValue) {
|
||||||
// We cannot use a closure here because of https://bugs.php.net/76982
|
// We cannot use a closure here because of https://bugs.php.net/76982
|
||||||
$value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);
|
$value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);
|
||||||
$value = "<?php\n\nnamespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};\n";
|
$value = "namespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};";
|
||||||
} else {
|
} else {
|
||||||
$value = "<?php return [{$expiry}, {$value}];\n";
|
$value = "return [{$expiry}, {$value}];";
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = $this->files[$key] = $this->getFile($key, true);
|
$file = $this->files[$key] = $this->getFile($key, true);
|
||||||
// Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
|
// Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
|
||||||
$ok = $this->write($file, $value, self::$startTime - 10) && $ok;
|
$ok = $this->write($file, "<?php //{$encodedKey}\n\n{$value}\n", self::$startTime - 10) && $ok;
|
||||||
|
|
||||||
if ($allowCompile) {
|
if ($allowCompile) {
|
||||||
@opcache_invalidate($file, true);
|
@opcache_invalidate($file, true);
|
||||||
@ -266,6 +268,18 @@ trait PhpFilesTrait
|
|||||||
|
|
||||||
return @unlink($file);
|
return @unlink($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getFileKey(string $file): string
|
||||||
|
{
|
||||||
|
if (!$h = @fopen($file, 'rb')) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$encodedKey = substr(fgets($h), 8);
|
||||||
|
fclose($h);
|
||||||
|
|
||||||
|
return rawurldecode(rtrim($encodedKey));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user