From d7948a72af7c892a145f3f8f1858cad6838b8315 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Tue, 12 Dec 2023 15:19:07 -0600 Subject: [PATCH 1/6] Fix TTL --- .github/workflows/phpunit.yml | 4 +--- composer.json | 2 +- src/Psr16/ArrayCacheEngine.php | 4 ++-- src/Psr16/BaseCacheEngine.php | 19 +++++++++++++++++-- src/Psr16/FileSystemCacheEngine.php | 4 ++-- src/Psr16/MemcachedEngine.php | 7 +++++-- src/Psr16/RedisCacheEngine.php | 4 +++- 7 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index d722c2c..7982498 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -16,12 +16,10 @@ jobs: strategy: matrix: php-version: + - "8.2" - "8.1" - "8.0" - "7.4" - - "7.3" - - "7.2" - - "7.1" # Service containers to run services: diff --git a/composer.json b/composer.json index 94bdbdb..6cb0ad0 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ } }, "require": { - "php": ">=7.0", + "php": ">=7.4", "psr/cache": "^1.0", "psr/log": "^1.1", "psr/simple-cache": "^1.0" diff --git a/src/Psr16/ArrayCacheEngine.php b/src/Psr16/ArrayCacheEngine.php index 39ee28b..d82d768 100644 --- a/src/Psr16/ArrayCacheEngine.php +++ b/src/Psr16/ArrayCacheEngine.php @@ -2,6 +2,7 @@ namespace ByJG\Cache\Psr16; +use DateInterval; use Psr\Log\NullLogger; class ArrayCacheEngine extends BaseCacheEngine @@ -67,13 +68,12 @@ public function get($key, $default = null) * * @param string $key The key of the item to store. * @param mixed $value The value of the item to store, must be serializable. - * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * @param null|int|DateInterval $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * * @return bool True on success and false on failure. * - * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function set($key, $value, $ttl = null) diff --git a/src/Psr16/BaseCacheEngine.php b/src/Psr16/BaseCacheEngine.php index e052f30..d8e4d81 100644 --- a/src/Psr16/BaseCacheEngine.php +++ b/src/Psr16/BaseCacheEngine.php @@ -4,6 +4,8 @@ use ByJG\Cache\CacheAvailabilityInterface; use ByJG\Cache\Exception\InvalidArgumentException; +use DateInterval; +use DateTime; use Psr\SimpleCache\CacheInterface; abstract class BaseCacheEngine implements CacheInterface, CacheAvailabilityInterface @@ -59,12 +61,25 @@ protected function addToNow($ttl) return strtotime("+$ttl second"); } - if ($ttl instanceof \DateInterval) { - $now = new \DateTime(); + if ($ttl instanceof DateInterval) { + $now = new DateTime(); $now->add($ttl); return $now->getTimestamp(); } return null; } + + protected function convertToSeconds($ttl) + { + if (empty($ttl) || is_numeric($ttl)) { + return $ttl; + } + + if ($ttl instanceof DateInterval) { + return $ttl->days*86400 + $ttl->h*3600 + $ttl->i*60 + $ttl->s; + } + + throw new InvalidArgumentException('Invalid TTL'); + } } diff --git a/src/Psr16/FileSystemCacheEngine.php b/src/Psr16/FileSystemCacheEngine.php index 72ef3dc..0ed96f0 100644 --- a/src/Psr16/FileSystemCacheEngine.php +++ b/src/Psr16/FileSystemCacheEngine.php @@ -3,6 +3,7 @@ namespace ByJG\Cache\Psr16; use ByJG\Cache\CacheLockInterface; +use DateInterval; use Exception; use Psr\Log\NullLogger; @@ -69,13 +70,12 @@ public function get($key, $default = null) * * @param string $key The key of the item to store. * @param mixed $value The value of the item to store, must be serializable. - * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * @param null|int|DateInterval $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * * @return bool True on success and false on failure. * - * @throws \Psr\SimpleCache\InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function set($key, $value, $ttl = null) diff --git a/src/Psr16/MemcachedEngine.php b/src/Psr16/MemcachedEngine.php index 1bddb1f..ee324ea 100644 --- a/src/Psr16/MemcachedEngine.php +++ b/src/Psr16/MemcachedEngine.php @@ -3,6 +3,7 @@ namespace ByJG\Cache\Psr16; use ByJG\Cache\Exception\StorageErrorException; +use DateInterval; use Memcached; use Psr\Log\NullLogger; @@ -78,8 +79,8 @@ public function get($key, $default = null) /** * @param string $key The object Key - * @param object $value The object to be cached - * @param int $ttl The time to live in seconds of this objects + * @param mixed $value The object to be cached + * @param DateInterval|int|null $ttl The time to live in seconds of this objects * @return bool If the object is successfully posted * @throws StorageErrorException */ @@ -87,6 +88,8 @@ public function set($key, $value, $ttl = null) { $this->lazyLoadMemCachedServers(); + $ttl = $this->convertToSeconds($ttl); + $this->memCached->set($this->fixKey($key), serialize($value), is_null($ttl) ? 0 : $ttl); $this->logger->info("[Memcached] Set '$key' result " . $this->memCached->getResultCode()); if ($this->memCached->getResultCode() !== Memcached::RES_SUCCESS) { diff --git a/src/Psr16/RedisCacheEngine.php b/src/Psr16/RedisCacheEngine.php index 62a973a..ac917e8 100644 --- a/src/Psr16/RedisCacheEngine.php +++ b/src/Psr16/RedisCacheEngine.php @@ -79,6 +79,8 @@ public function set($key, $value, $ttl = null) { $this->lazyLoadRedisServer(); + $ttl = $this->convertToSeconds($ttl); + $this->redis->set($this->fixKey($key), serialize($value), $ttl); $this->logger->info("[Redis Cache] Set '$key' result "); @@ -98,7 +100,7 @@ public function clear() { $keys = $this->redis->keys('cache:*'); foreach ((array)$keys as $key) { - if (preg_match('/^cache\:(?.*)/', $key, $matches)) { + if (preg_match('/^cache:(?.*)/', $key, $matches)) { $this->delete($matches['key']); } } From 529a37262c45f1fa88021dfd5edd7e468250c288 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Mon, 18 Dec 2023 01:22:33 -0600 Subject: [PATCH 2/6] Add PSR-11 as key store. --- README.md | 22 ++++++++++++++ composer.json | 3 +- src/Psr16/ArrayCacheEngine.php | 6 ++++ src/Psr16/BaseCacheEngine.php | 23 +++++++++++++++ src/Psr16/FileSystemCacheEngine.php | 2 ++ src/Psr16/MemcachedEngine.php | 1 + src/Psr16/NoCacheEngine.php | 4 +++ src/Psr16/RedisCacheEngine.php | 1 + src/Psr16/SessionCacheEngine.php | 1 + src/Psr16/ShmopCacheEngine.php | 1 + tests/BaseCacheTest.php | 3 ++ tests/BasicContainer.php | 32 ++++++++++++++++++++ tests/CachePSR16Test.php | 45 +++++++++++++++++++++++++++++ 13 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 tests/BasicContainer.php diff --git a/README.md b/README.md index 48bfedd..297225a 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,28 @@ You can add a PSR Log compatible to the constructor in order to get Log of the o See log examples [here](docs/setup-log-handler.md) +## Use a PSR-11 container to retrieve the cache keys + +You can use a PSR-11 compatible to retrieve the cache keys. Once is defined, only the keys defined +in the PSR-11 will be used to cache. + +```php +withKeysFromContainer(new SomePsr11Implementation()); +``` + +After the PSR-11 container is defined, when I run: + +```php +$value = $fileCache->get('my-key'); +``` + +The key `my-key` will be retrieved from the PSR-11 container and +the value retrieved will be used as the cache key. +If it does not exist in the PSR-11 container, an exception will be thrown. + + ## Install Just type: diff --git a/composer.json b/composer.json index 6cb0ad0..4b10ed7 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ "php": ">=7.4", "psr/cache": "^1.0", "psr/log": "^1.1", - "psr/simple-cache": "^1.0" + "psr/simple-cache": "^1.0", + "psr/container": "^2.0" }, "require-dev": { "phpunit/phpunit": "5.7.*|7.4.*|^9.5" diff --git a/src/Psr16/ArrayCacheEngine.php b/src/Psr16/ArrayCacheEngine.php index d82d768..b86c8fb 100644 --- a/src/Psr16/ArrayCacheEngine.php +++ b/src/Psr16/ArrayCacheEngine.php @@ -34,6 +34,7 @@ public function __construct($logger = null) */ public function has($key) { + $key = $this->getKeyFromContainer($key); if (isset($this->cache[$key])) { if (isset($this->cache["$key.ttl"]) && time() >= $this->cache["$key.ttl"]) { $this->delete($key); @@ -55,6 +56,7 @@ public function has($key) public function get($key, $default = null) { if ($this->has($key)) { + $key = $this->getKeyFromContainer($key); $this->logger->info("[Array cache] Get '$key' from L1 Cache"); return $this->cache[$key]; } else { @@ -78,6 +80,8 @@ public function get($key, $default = null) */ public function set($key, $value, $ttl = null) { + $key = $this->getKeyFromContainer($key); + $this->logger->info("[Array cache] Set '$key' in L1 Cache"); $this->cache[$key] = $value; @@ -101,6 +105,8 @@ public function clear() */ public function delete($key) { + $key = $this->getKeyFromContainer($key); + unset($this->cache[$key]); unset($this->cache["$key.ttl"]); return true; diff --git a/src/Psr16/BaseCacheEngine.php b/src/Psr16/BaseCacheEngine.php index d8e4d81..f558e99 100644 --- a/src/Psr16/BaseCacheEngine.php +++ b/src/Psr16/BaseCacheEngine.php @@ -6,10 +6,13 @@ use ByJG\Cache\Exception\InvalidArgumentException; use DateInterval; use DateTime; +use Psr\Container\ContainerInterface; use Psr\SimpleCache\CacheInterface; abstract class BaseCacheEngine implements CacheInterface, CacheAvailabilityInterface { + protected ?ContainerInterface $container; + /** * @param $keys * @param null $default @@ -82,4 +85,24 @@ protected function convertToSeconds($ttl) throw new InvalidArgumentException('Invalid TTL'); } + + + protected function getKeyFromContainer($key) + { + if (empty($this->container)) { + return $key; + } + + if (!$this->container->has($key)) { + throw new InvalidArgumentException("Key '$key' not found in container"); + } + + return $this->container->get($key); + } + + public function withKeysFromContainer(?ContainerInterface $container) + { + $this->container = $container; + return $this; + } } diff --git a/src/Psr16/FileSystemCacheEngine.php b/src/Psr16/FileSystemCacheEngine.php index 0ed96f0..819ab11 100644 --- a/src/Psr16/FileSystemCacheEngine.php +++ b/src/Psr16/FileSystemCacheEngine.php @@ -165,6 +165,8 @@ public function isAvailable() protected function fixKey($key) { + $key = $this->getKeyFromContainer($key); + return $this->path . '/' . $this->prefix . '-' . preg_replace("/[\/\\\]/", "#", $key) diff --git a/src/Psr16/MemcachedEngine.php b/src/Psr16/MemcachedEngine.php index ee324ea..af9eb6f 100644 --- a/src/Psr16/MemcachedEngine.php +++ b/src/Psr16/MemcachedEngine.php @@ -36,6 +36,7 @@ public function __construct($servers = null, $logger = null) } protected function fixKey($key) { + $key = $this->getKeyFromContainer($key); return "cache-" . $key; } diff --git a/src/Psr16/NoCacheEngine.php b/src/Psr16/NoCacheEngine.php index d9d5c20..f4af906 100644 --- a/src/Psr16/NoCacheEngine.php +++ b/src/Psr16/NoCacheEngine.php @@ -13,6 +13,7 @@ class NoCacheEngine extends BaseCacheEngine implements CacheLockInterface */ public function get($key, $default = null) { + $key = $this->getKeyFromContainer($key); return $default; } @@ -24,6 +25,7 @@ public function get($key, $default = null) */ public function set($key, $value, $ttl = 0) { + $key = $this->getKeyFromContainer($key); return true; } @@ -33,6 +35,7 @@ public function set($key, $value, $ttl = 0) */ public function delete($key) { + $key = $this->getKeyFromContainer($key); return true; } @@ -83,6 +86,7 @@ public function clear() */ public function has($key) { + $key = $this->getKeyFromContainer($key); return false; } } diff --git a/src/Psr16/RedisCacheEngine.php b/src/Psr16/RedisCacheEngine.php index ac917e8..ff896a8 100644 --- a/src/Psr16/RedisCacheEngine.php +++ b/src/Psr16/RedisCacheEngine.php @@ -51,6 +51,7 @@ protected function lazyLoadRedisServer() } protected function fixKey($key) { + $key = $this->getKeyFromContainer($key); return "cache:$key"; } diff --git a/src/Psr16/SessionCacheEngine.php b/src/Psr16/SessionCacheEngine.php index 0ad0e06..9c5fa01 100644 --- a/src/Psr16/SessionCacheEngine.php +++ b/src/Psr16/SessionCacheEngine.php @@ -27,6 +27,7 @@ protected function checkSession() protected function keyName($key) { + $key = $this->getKeyFromContainer($key); return $this->prefix . '-' . $key; } diff --git a/src/Psr16/ShmopCacheEngine.php b/src/Psr16/ShmopCacheEngine.php index 3e9f0ff..5fd1528 100644 --- a/src/Psr16/ShmopCacheEngine.php +++ b/src/Psr16/ShmopCacheEngine.php @@ -46,6 +46,7 @@ public function __construct($config = [], $logger = null) protected function getFilenameToken($key) { + $key = $this->getKeyFromContainer($key); return sys_get_temp_dir() . '/shmop-' . sha1($key) . '.cache'; } diff --git a/tests/BaseCacheTest.php b/tests/BaseCacheTest.php index 2c45035..a0099be 100644 --- a/tests/BaseCacheTest.php +++ b/tests/BaseCacheTest.php @@ -15,6 +15,9 @@ abstract class BaseCacheTest extends TestCase protected function tearDown(): void { + if (empty($this->cacheEngine)) { + return; + } $this->cacheEngine->clear(); $this->cacheEngine = null; } diff --git a/tests/BasicContainer.php b/tests/BasicContainer.php new file mode 100644 index 0000000..f357695 --- /dev/null +++ b/tests/BasicContainer.php @@ -0,0 +1,32 @@ +markTestIncomplete('Object is not fully functional'); } } + + /** + * @dataProvider CachePoolProvider + */ + public function testCacheContainerKeyNonExistent(BaseCacheEngine $cacheEngine) + { + if ($cacheEngine->isAvailable()) { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage("Key 'abc' not found in container"); + + $cacheEngine->withKeysFromContainer(new BasicContainer()); + $cacheEngine->set("abc", "30"); + } else { + $this->markTestIncomplete('Object is not fully functional'); + } + } + + /** + * @dataProvider CachePoolProvider + */ + public function testCacheContainerKey(BaseCacheEngine $cacheEngine) + { + if ($cacheEngine->isAvailable() && !($cacheEngine instanceof NoCacheEngine)) { + $cacheEngine->clear(); + + // This first part will get the "test-key" from the container. + // The real key is container["test-key"] = "container-key" + $cacheEngine->withKeysFromContainer(new BasicContainer()); + $this->assertFalse($cacheEngine->has("test-key")); + $cacheEngine->set("test-key", "something"); + $this->assertTrue($cacheEngine->has("test-key")); + $this->assertEquals("something", $cacheEngine->get("test-key")); + + // This part, we will disable the container and try to get the original key from test. + $cacheEngine->withKeysFromContainer(null); + $this->assertTrue($cacheEngine->has("container-key")); + $this->assertEquals("something", $cacheEngine->get("container-key")); + } else { + $this->markTestIncomplete('Object is not fully functional'); + } + } + } From 544ec8868fa3e152ee4573a4552a4f82d0ae5bcd Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Sat, 30 Dec 2023 13:31:32 -0600 Subject: [PATCH 3/6] Add Dependencies --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 297225a..1cb721c 100644 --- a/README.md +++ b/README.md @@ -134,5 +134,14 @@ vendor/bin/phpunit --stderr **Note:** the parameter `--stderr` after `phpunit` is to permit run the tests on SessionCacheEngine. +## Dependencies + +```mermaid +flowchart TD + CacheEngine --> psr/cache + CacheEngine --> psr/log + CacheEngine --> psr/simple-cache + CacheEngine --> psr/container +``` ---- [Open source ByJG](http://opensource.byjg.com) From 615e83fdc8339d28aff231b9c49c1fe4aeaeefe4 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Sat, 30 Dec 2023 13:53:11 -0600 Subject: [PATCH 4/6] Add Dependencies --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1cb721c..b3d988b 100644 --- a/README.md +++ b/README.md @@ -138,10 +138,10 @@ vendor/bin/phpunit --stderr ```mermaid flowchart TD - CacheEngine --> psr/cache - CacheEngine --> psr/log - CacheEngine --> psr/simple-cache - CacheEngine --> psr/container + byjg/cache-engine --> psr/cache + byjg/cache-engine --> psr/log + byjg/cache-engine --> psr/simple-cache + byjg/cache-engine --> psr/container ``` ---- [Open source ByJG](http://opensource.byjg.com) From c2927ffc633303639f9a0a11c7d774c2ba685231 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Wed, 3 Jan 2024 20:36:03 -0600 Subject: [PATCH 5/6] Update README + GH Actions --- .github/workflows/phpunit.yml | 16 ++++++++-------- README.md | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 7982498..22bba59 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -34,16 +34,16 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: composer install - run: ./vendor/bin/phpunit --stderr Documentation: - runs-on: 'ubuntu-latest' - needs: Build if: github.ref == 'refs/heads/master' - env: - DOC_GITHUB_TOKEN: '${{ secrets.DOC_TOKEN }}' - steps: - - uses: actions/checkout@v3 - - run: curl https://opensource.byjg.com/add-doc.sh | bash /dev/stdin php cache-engine-php \ No newline at end of file + needs: Build + uses: byjg/byjg.github.io/.github/workflows/add-doc.yaml@master + with: + folder: php + project: ${{ github.event.repository.name }} + secrets: inherit + diff --git a/README.md b/README.md index b3d988b..9f73319 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Cache Engine -[![Build Status](https://github.com/byjg/cache-engine-php/actions/workflows/phpunit.yml/badge.svg?branch=master)](https://github.com/byjg/cache-engine-php/actions/workflows/phpunit.yml) +[![Build Status](https://github.com/byjg/php-cache-engine/actions/workflows/phpunit.yml/badge.svg?branch=master)](https://github.com/byjg/php-cache-engine/actions/workflows/phpunit.yml) [![Opensource ByJG](https://img.shields.io/badge/opensource-byjg-success.svg)](http://opensource.byjg.com) -[![GitHub source](https://img.shields.io/badge/Github-source-informational?logo=github)](https://github.com/byjg/cache-engine-php/) -[![GitHub license](https://img.shields.io/github/license/byjg/cache-engine-php.svg)](https://opensource.byjg.com/opensource/licensing.html) -[![GitHub release](https://img.shields.io/github/release/byjg/cache-engine-php.svg)](https://github.com/byjg/cache-engine-php/releases/) +[![GitHub source](https://img.shields.io/badge/Github-source-informational?logo=github)](https://github.com/byjg/php-cache-engine/) +[![GitHub license](https://img.shields.io/github/license/byjg/php-cache-engine.svg)](https://opensource.byjg.com/opensource/licensing.html) +[![GitHub release](https://img.shields.io/github/release/byjg/php-cache-engine.svg)](https://github.com/byjg/php-cache-engine/releases/) A multi-purpose cache engine PSR-6 and PSR-16 implementation with several drivers. From ee5d1f9e188dd027eb782b607d6041615a1e0531 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Wed, 3 Jan 2024 20:41:04 -0600 Subject: [PATCH 6/6] Update README + GH Actions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f73319..779fd14 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ If it does not exist in the PSR-11 container, an exception will be thrown. Just type: ``` -composer require "byjg/cache-engine=4.9.*" +composer require "byjg/cache-engine" ```