[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
|
||||
=======================
|
||||
|
||||
Cache
|
||||
-----
|
||||
|
||||
* Added argument `$prefix` to `AdapterInterface::clear()`
|
||||
|
||||
DependencyInjection
|
||||
-------------------
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ Cache
|
|||
* Removed `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead.
|
||||
* Removed all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead.
|
||||
* Removed `SimpleCacheAdapter`, use `Psr16Adapter` instead.
|
||||
* Added argument `$prefix` to `AdapterInterface::clear()`
|
||||
|
||||
Config
|
||||
------
|
||||
|
|
|
@ -34,4 +34,11 @@ interface AdapterInterface extends CacheItemPoolInterface
|
|||
* @return \Traversable|CacheItem[]
|
||||
*/
|
||||
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}
|
||||
*
|
||||
* @param string $prefix
|
||||
*/
|
||||
public function clear()
|
||||
public function clear(/*string $prefix = ''*/)
|
||||
{
|
||||
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||
$cleared = true;
|
||||
$i = $this->adapterCount;
|
||||
|
||||
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;
|
||||
|
|
|
@ -75,8 +75,10 @@ class NullAdapter implements AdapterInterface, CacheInterface
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $prefix
|
||||
*/
|
||||
public function clear()
|
||||
public function clear(/*string $prefix = ''*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -147,9 +147,17 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
|
|||
|
||||
/**
|
||||
* {@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();
|
||||
}
|
||||
|
||||
|
|
|
@ -213,10 +213,26 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
|
|||
|
||||
/**
|
||||
* {@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();
|
||||
}
|
||||
|
|
|
@ -167,11 +167,18 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
|
|||
|
||||
/**
|
||||
* {@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__);
|
||||
try {
|
||||
if ($this->pool instanceof AdapterInterface) {
|
||||
return $event->result = $this->pool->clear($prefix);
|
||||
}
|
||||
|
||||
return $event->result = $this->pool->clear();
|
||||
} finally {
|
||||
$event->end = microtime(true);
|
||||
|
|
|
@ -5,6 +5,7 @@ CHANGELOG
|
|||
-----
|
||||
|
||||
* added support for connecting to Redis Sentinel clusters
|
||||
* added argument `$prefix` to `AdapterInterface::clear()`
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
|
|
@ -252,6 +252,26 @@ abstract class AdapterTestCase extends CachePoolTest
|
|||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
||||
$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
|
||||
|
|
|
@ -23,6 +23,7 @@ class DoctrineAdapterTest extends AdapterTestCase
|
|||
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',
|
||||
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
|
||||
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
|
||||
'testClearPrefix' => 'Doctrine cannot clear by prefix',
|
||||
];
|
||||
|
||||
public function createCachePool($defaultLifetime = 0)
|
||||
|
|
|
@ -19,6 +19,7 @@ class MemcachedAdapterTest extends AdapterTestCase
|
|||
protected $skippedTests = [
|
||||
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
|
||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
||||
'testClearPrefix' => 'Memcached cannot clear by prefix',
|
||||
];
|
||||
|
||||
protected static $client;
|
||||
|
|
|
@ -72,7 +72,7 @@ class PhpArrayAdapterTest extends AdapterTestCase
|
|||
|
||||
public function createCachePool($defaultLifetime = 0, $testMethod = null)
|
||||
{
|
||||
if ('testGetMetadata' === $testMethod) {
|
||||
if ('testGetMetadata' === $testMethod || 'testClearPrefix' === $testMethod) {
|
||||
return new PhpArrayAdapter(self::$file, new FilesystemAdapter());
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ class Psr16AdapterTest extends AdapterTestCase
|
|||
{
|
||||
protected $skippedTests = [
|
||||
'testPrune' => 'Psr16adapter just proxies',
|
||||
'testClearPrefix' => 'SimpleCache cannot clear by prefix',
|
||||
];
|
||||
|
||||
public function createCachePool($defaultLifetime = 0)
|
||||
|
|
|
@ -23,6 +23,7 @@ class SimpleCacheAdapterTest extends AdapterTestCase
|
|||
{
|
||||
protected $skippedTests = [
|
||||
'testPrune' => 'SimpleCache just proxies',
|
||||
'testClearPrefix' => 'SimpleCache cannot clear by prefix',
|
||||
];
|
||||
|
||||
public function createCachePool($defaultLifetime = 0)
|
||||
|
|
|
@ -102,9 +102,12 @@ trait AbstractTrait
|
|||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $prefix
|
||||
*/
|
||||
public function clear()
|
||||
public function clear(/*string $prefix = ''*/)
|
||||
{
|
||||
$prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
|
||||
$this->deferred = [];
|
||||
if ($cleared = $this->versioningIsEnabled) {
|
||||
$namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
|
||||
|
@ -120,7 +123,7 @@ trait AbstractTrait
|
|||
}
|
||||
|
||||
try {
|
||||
return $this->doClear($this->namespace) || $cleared;
|
||||
return $this->doClear($this->namespace.$prefix) || $cleared;
|
||||
} catch (\Exception $e) {
|
||||
CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]);
|
||||
|
||||
|
|
|
@ -66,10 +66,22 @@ trait ArrayTrait
|
|||
|
||||
/**
|
||||
* {@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;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,10 @@ trait FilesystemCommonTrait
|
|||
$ok = true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -114,6 +118,11 @@ trait FilesystemCommonTrait
|
|||
return $dir.substr($hash, 2, 20);
|
||||
}
|
||||
|
||||
private function getFileKey(string $file): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
|
|
@ -108,4 +108,17 @@ trait FilesystemTrait
|
|||
|
||||
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;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\CacheItem;
|
||||
use Symfony\Component\Cache\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\VarExporter\VarExporter;
|
||||
|
@ -121,13 +122,20 @@ EOF;
|
|||
|
||||
/**
|
||||
* {@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 = [];
|
||||
|
||||
$cleared = @unlink($this->file) || !file_exists($this->file);
|
||||
|
||||
if ($this->pool instanceof AdapterInterface) {
|
||||
return $this->pool->clear($prefix) && $cleared;
|
||||
}
|
||||
|
||||
return $this->pool->clear() && $cleared;
|
||||
}
|
||||
|
||||
|
|
|
@ -211,17 +211,19 @@ trait PhpFilesTrait
|
|||
$value = var_export($value, true);
|
||||
}
|
||||
|
||||
$encodedKey = rawurlencode($key);
|
||||
|
||||
if (!$isStaticValue) {
|
||||
// We cannot use a closure here because of https://bugs.php.net/76982
|
||||
$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 {
|
||||
$value = "<?php return [{$expiry}, {$value}];\n";
|
||||
$value = "return [{$expiry}, {$value}];";
|
||||
}
|
||||
|
||||
$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
|
||||
$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) {
|
||||
@opcache_invalidate($file, true);
|
||||
|
@ -266,6 +268,18 @@ trait PhpFilesTrait
|
|||
|
||||
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