diff --git a/src/Caching/Cache.php b/src/Caching/Cache.php index 4eb7aa17..cb922258 100644 --- a/src/Caching/Cache.php +++ b/src/Caching/Cache.php @@ -31,9 +31,9 @@ class Cache ITEMS = 'items', CONSTS = 'consts', CALLBACKS = 'callbacks', + NAMESPACES = 'namespaces', ALL = 'all'; - /** @internal */ public const NAMESPACE_SEPARATOR = "\x00"; /** @var IStorage */ @@ -155,7 +155,7 @@ public function bulkLoad(array $keys, callable $fallback = null): array * * @param mixed * @param mixed - * @return mixed value itself + * @return mixed value itself * @throws Nette\InvalidArgumentException */ public function save($key, $data, array $dependencies = null) diff --git a/src/Caching/Storages/FileStorage.php b/src/Caching/Storages/FileStorage.php index 3205a627..b800fd8c 100644 --- a/src/Caching/Storages/FileStorage.php +++ b/src/Caching/Storages/FileStorage.php @@ -153,7 +153,7 @@ public function lock(string $key): void /** * Writes item into the cache. */ - public function write(string $key, $data, array $dp): void + public function write(string $key, $data, array $dp = []): void { $meta = [ self::META_TIME => microtime(), @@ -249,6 +249,7 @@ public function clean(array $conditions): void { $all = !empty($conditions[Cache::ALL]); $collector = empty($conditions); + $namespaces = $conditions[Cache::NAMESPACES] ?? false; // cleaning using file iterator if ($all || $collector) { @@ -284,6 +285,21 @@ public function clean(array $conditions): void $this->journal->clean($conditions); } return; + } elseif ($namespaces) { + if (!is_array($namespaces)) { + $namespaces = [$namespaces]; + } + + foreach ($namespaces as $namespace) { + $dir = $this->dir . '/_' . urlencode($namespace); + if (is_dir($dir)) { + $items = Nette\Utils\Finder::findFiles('*')->from($dir); + foreach ($items as $item) { + $this->delete((string) $item); + } + @rmdir($dir); // may already contain new files + } + } } // cleaning using journal diff --git a/src/Caching/Storages/SQLiteStorage.php b/src/Caching/Storages/SQLiteStorage.php index 73cf538d..9ff42b68 100644 --- a/src/Caching/Storages/SQLiteStorage.php +++ b/src/Caching/Storages/SQLiteStorage.php @@ -142,8 +142,7 @@ public function clean(array $conditions): void { if (!empty($conditions[Cache::ALL])) { $this->pdo->prepare('DELETE FROM cache')->execute(); - - } else { + } elseif (!empty($conditions[Cache::TAGS])) { $sql = 'DELETE FROM cache WHERE expire < ?'; $args = [time()]; @@ -154,6 +153,19 @@ public function clean(array $conditions): void } $this->pdo->prepare($sql)->execute($args); + } elseif (!empty($conditions[Cache::NAMESPACES])) { + if (is_array($conditions[Cache::NAMESPACES])) { + $namespaces = $conditions[Cache::NAMESPACES]; + } else { + $namespaces = [$conditions[Cache::NAMESPACES]]; + } + + + foreach ($namespaces as $namespace) { + $this->pdo + ->prepare('DELETE FROM cache WHERE key LIKE ?') + ->execute([$namespace . Cache::NAMESPACE_SEPARATOR]); + } } } } diff --git a/tests/Bridges.Latte/CacheMacro.createCache.phpt b/tests/Bridges.Latte/CacheMacro.createCache.phpt index 263353d0..d2b29f9e 100644 --- a/tests/Bridges.Latte/CacheMacro.createCache.phpt +++ b/tests/Bridges.Latte/CacheMacro.createCache.phpt @@ -17,7 +17,7 @@ require __DIR__ . '/../bootstrap.php'; test(function () { $parents = []; $dp = [Cache::TAGS => ['rum', 'cola']]; - $outputHelper = CacheMacro::createCache(new DevNullStorage(), 'test', $parents); + $outputHelper = CacheMacro::createCache(new DevNullStorage, 'test', $parents); Assert::type(Nette\Caching\OutputHelper::class, $outputHelper); CacheMacro::endCache($parents, $dp); Assert::same($dp + [Cache::EXPIRATION => '+ 7 days'], $outputHelper->dependencies); @@ -29,7 +29,7 @@ test(function () { $dpFallback = function () use ($dp) { return $dp; }; - $outputHelper = CacheMacro::createCache(new DevNullStorage(), 'test', $parents); + $outputHelper = CacheMacro::createCache(new DevNullStorage, 'test', $parents); CacheMacro::endCache($parents, ['dependencies' => $dpFallback]); Assert::same($dp + [Cache::EXPIRATION => '+ 7 days'], $outputHelper->dependencies); }); @@ -43,7 +43,7 @@ test(function () { $dpFallback = function () use ($dp) { return $dp; }; - $outputHelper = CacheMacro::createCache(new DevNullStorage(), 'test', $parents); + $outputHelper = CacheMacro::createCache(new DevNullStorage, 'test', $parents); CacheMacro::endCache($parents, ['dependencies' => $dpFallback]); Assert::same($dp, $outputHelper->dependencies); }); diff --git a/tests/Caching/Cache.bulkLoad.phpt b/tests/Caching/Cache.bulkLoad.phpt index 782edf5e..37b1f69b 100644 --- a/tests/Caching/Cache.bulkLoad.phpt +++ b/tests/Caching/Cache.bulkLoad.phpt @@ -60,7 +60,7 @@ test(function () { test(function () { Assert::exception(function () { - $cache = new Cache(new BulkReadTestStorage()); + $cache = new Cache(new BulkReadTestStorage); $cache->bulkLoad([[1]]); }, Nette\InvalidArgumentException::class, 'Only scalar keys are allowed in bulkLoad()'); }); diff --git a/tests/Caching/Cache.load.phpt b/tests/Caching/Cache.load.phpt index 7caa2a9e..6437f9c4 100644 --- a/tests/Caching/Cache.load.phpt +++ b/tests/Caching/Cache.load.phpt @@ -16,7 +16,7 @@ require __DIR__ . '/Cache.php'; // load twice with fallback -$storage = new TestStorage(); +$storage = new TestStorage; $cache = new Cache($storage, 'ns'); $value = $cache->load('key', function () { @@ -32,7 +32,7 @@ Assert::equal('value', $data['data']); // load twice with closure fallback, pass dependencies $dependencies = [Cache::TAGS => ['tag']]; -$storage = new TestStorage(); +$storage = new TestStorage; $cache = new Cache($storage, 'ns'); $value = $cache->load('key', function (&$deps) use ($dependencies) { diff --git a/tests/Caching/Cache.save.phpt b/tests/Caching/Cache.save.phpt index 6dbcba8b..06683c03 100644 --- a/tests/Caching/Cache.save.phpt +++ b/tests/Caching/Cache.save.phpt @@ -16,7 +16,7 @@ require __DIR__ . '/Cache.php'; // save value with dependencies -$storage = new testStorage(); +$storage = new testStorage; $cache = new Cache($storage, 'ns'); $dependencies = [Cache::TAGS => ['tag']]; @@ -28,7 +28,7 @@ Assert::equal($dependencies, $res['dependencies']); // save callback return value -$storage = new testStorage(); +$storage = new testStorage; $cache = new Cache($storage, 'ns'); $cache->save('key', function () { @@ -41,7 +41,7 @@ Assert::equal([], $res['dependencies']); // save callback return value with dependencies -$storage = new testStorage(); +$storage = new testStorage; $cache = new Cache($storage, 'ns'); $dependencies = [Cache::TAGS => ['tag']]; @@ -55,7 +55,7 @@ Assert::equal($dependencies, $res['dependencies']); // do not save already expired data -$storage = new testStorage(); +$storage = new testStorage; $cache = new Cache($storage, 'ns'); $dependencies = [Cache::EXPIRATION => new DateTime]; diff --git a/tests/Storages/FileStorage.clean-all.phpt b/tests/Storages/FileStorage.clean-all.phpt index 8ba8d296..99b3cb5c 100644 --- a/tests/Storages/FileStorage.clean-all.phpt +++ b/tests/Storages/FileStorage.clean-all.phpt @@ -10,7 +10,6 @@ use Nette\Caching\Cache; use Nette\Caching\Storages\FileStorage; use Tester\Assert; - require __DIR__ . '/../bootstrap.php'; diff --git a/tests/Storages/FileStorage.clean-namespace.phpt b/tests/Storages/FileStorage.clean-namespace.phpt new file mode 100644 index 00000000..0ff64e9e --- /dev/null +++ b/tests/Storages/FileStorage.clean-namespace.phpt @@ -0,0 +1,109 @@ +save('test1', 'David'); +$cacheA->save('test2', 'Grudl'); + +$cacheB->save('test1', 'Barry'); +$cacheB->save('test2', 'Allen'); + +$cacheC->save('test1', 'Oliver'); +$cacheC->save('test2', 'Queen'); + +$cacheD->save('test1', 'Bruce'); +$cacheD->save('test2', 'Wayne'); + + +/* + * Check if fill wass successfull + */ +Assert::same('David Grudl', implode(' ', [ + $cacheA->load('test1'), + $cacheA->load('test2'), +])); + +Assert::same('Barry Allen', implode(' ', [ + $cacheB->load('test1'), + $cacheB->load('test2'), +])); + +Assert::same('Oliver Queen', implode(' ', [ + $cacheC->load('test1'), + $cacheC->load('test2'), +])); + +Assert::same('Bruce Wayne', implode(' ', [ + $cacheD->load('test1'), + $cacheD->load('test2'), +])); + + +/* + * Clean one namespace + */ +$storage->clean([Cache::NAMESPACES => 'B']); + +Assert::same('David Grudl', implode(' ', [ + $cacheA->load('test1'), + $cacheA->load('test2'), +])); + +// Only these should be null now +Assert::null($cacheB->load('test1')); +Assert::null($cacheB->load('test2')); + +Assert::same('Oliver Queen', implode(' ', [ + $cacheC->load('test1'), + $cacheC->load('test2'), +])); + +Assert::same('Bruce Wayne', implode(' ', [ + $cacheD->load('test1'), + $cacheD->load('test2'), +])); + + +/* + * Test cleaning multiple namespaces + */ +$storage->clean([Cache::NAMESPACES => ['C', 'D']]); + +Assert::same('David Grudl', implode(' ', [ + $cacheA->load('test1'), + $cacheA->load('test2'), +])); + +// All other should be null +Assert::null($cacheB->load('test1')); +Assert::null($cacheB->load('test2')); + +Assert::null($cacheC->load('test1')); +Assert::null($cacheC->load('test2')); + +Assert::null($cacheD->load('test1')); +Assert::null($cacheD->load('test2')); diff --git a/tests/Storages/SQLiteJournal.phpt b/tests/Storages/SQLiteJournal.phpt index a23d3fba..48aee12e 100644 --- a/tests/Storages/SQLiteJournal.phpt +++ b/tests/Storages/SQLiteJournal.phpt @@ -14,6 +14,9 @@ require __DIR__ . '/../bootstrap.php'; require __DIR__ . '/IJournalTestCase.php'; +/** + * @testCase + */ class SQLiteJournalTest extends IJournalTestCase { public function createJournal() diff --git a/tests/Storages/SQLiteStorage.clean-namespace.phpt b/tests/Storages/SQLiteStorage.clean-namespace.phpt new file mode 100644 index 00000000..be2f77a5 --- /dev/null +++ b/tests/Storages/SQLiteStorage.clean-namespace.phpt @@ -0,0 +1,110 @@ +save('test1', 'David'); +$cacheA->save('test2', 'Grudl'); + +$cacheB->save('test1', 'Barry'); +$cacheB->save('test2', 'Allen'); + +$cacheC->save('test1', 'Oliver'); +$cacheC->save('test2', 'Queen'); + +$cacheD->save('test1', 'Bruce'); +$cacheD->save('test2', 'Wayne'); + + +/* + * Check if fill wass successfull + */ +Assert::same('David Grudl', implode(' ', [ + $cacheA->load('test1'), + $cacheA->load('test2'), +])); + +Assert::same('Barry Allen', implode(' ', [ + $cacheB->load('test1'), + $cacheB->load('test2'), +])); + +Assert::same('Oliver Queen', implode(' ', [ + $cacheC->load('test1'), + $cacheC->load('test2'), +])); + +Assert::same('Bruce Wayne', implode(' ', [ + $cacheD->load('test1'), + $cacheD->load('test2'), +])); + + +/* + * Clean one namespace + */ +$storage->clean([Cache::NAMESPACES => 'B']); + +Assert::same('David Grudl', implode(' ', [ + $cacheA->load('test1'), + $cacheA->load('test2'), +])); + +// Only these should be null now +Assert::null($cacheB->load('test1')); +Assert::null($cacheB->load('test2')); + +Assert::same('Oliver Queen', implode(' ', [ + $cacheC->load('test1'), + $cacheC->load('test2'), +])); + +Assert::same('Bruce Wayne', implode(' ', [ + $cacheD->load('test1'), + $cacheD->load('test2'), +])); + + +/* + * Test cleaning multiple namespaces + */ +$storage->clean([Cache::NAMESPACES => ['C', 'D']]); + +Assert::same('David Grudl', implode(' ', [ + $cacheA->load('test1'), + $cacheA->load('test2'), +])); + +// All other should be null +Assert::null($cacheB->load('test1')); +Assert::null($cacheB->load('test2')); + +Assert::null($cacheC->load('test1')); +Assert::null($cacheC->load('test2')); + +Assert::null($cacheD->load('test1')); +Assert::null($cacheD->load('test2')); diff --git a/tests/php-unix.ini b/tests/php-unix.ini index 21af7c42..cab1f444 100644 --- a/tests/php-unix.ini +++ b/tests/php-unix.ini @@ -1,7 +1,30 @@ [PHP] ;extension_dir = "./ext" -extension=memcache.so -extension=memcached.so +extension=bz2.so +extension=ctype.so +extension=curl.so +extension=dom.so +extension=gd.so +extension=gettext.so +extension=iconv.so +extension=intl.so +extension=json.so +extension=mbstring.so +extension=mcrypt.so +extension=mysqli.so +extension=openssl.so +extension=pdo.so +extension=pdo_mysql.so +extension=pdo_sqlite.so +extension=phar.so +extension=soap.so +extension=sockets.so +extension=sqlite3.so +extension=tokenizer.so +extension=xmlreader.so +extension=xmlwriter.so +extension=zip.so +extension=zlib.so [Zend] ;zend_extension="./ext/zend_extension"