From e4ce1f69efaf81c832085dcd2dce299194898631 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Mon, 16 Feb 2026 13:37:54 +0100 Subject: [PATCH 01/10] composer.json updated --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0a240a8..61d08d9 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ "phpunit/phpunit": "^10.5", "symfony/var-dumper": "~6.4", "friendsofphp/php-cs-fixer": "~3.3", - "cache/integration-tests": "dev-master" + "cache/integration-tests": "dev-master", + "phpstan/phpstan": "^2.1" }, "suggest": { "ext-redis": "^5.3" From ae5049f21e659507c8f90385b058c02c8547fbbf Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Mon, 16 Feb 2026 15:55:17 +0100 Subject: [PATCH 02/10] feature: PHP Stan 1st pass --- src/CacheEntryPool/CacheEntryPool.php | 2 +- src/RedisEnhancedCache.php | 2 +- tests/Integration/CacheIntegrationTest.php | 2 ++ tests/Integration/CacheIntegrationWithPCTest.php | 2 ++ tests/Integration/PoolIntegrationTest.php | 1 + tests/Integration/PoolIntegrationWithPCTest.php | 1 + 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/CacheEntryPool/CacheEntryPool.php b/src/CacheEntryPool/CacheEntryPool.php index 9f6d675..b8fc41f 100644 --- a/src/CacheEntryPool/CacheEntryPool.php +++ b/src/CacheEntryPool/CacheEntryPool.php @@ -83,7 +83,7 @@ public function clear(): bool $this->cache->delete($this->poolName); unset($this->deferredItems); $this->deferredItems = []; - } catch (Exception $e) { + } catch (\Exception $e) { return false; } diff --git a/src/RedisEnhancedCache.php b/src/RedisEnhancedCache.php index b2959b4..2e01d8b 100644 --- a/src/RedisEnhancedCache.php +++ b/src/RedisEnhancedCache.php @@ -362,7 +362,7 @@ public function deleteFromPool(array $keys, string $pool = self::DEFAULT_POOL): try { $redisResponse = call_user_func_array([$this->getRedis(), 'hdel'], $params); - } catch (Exception $e) { + } catch (\Exception $e) { $redisResponse = false; $this->formatException($e); } diff --git a/tests/Integration/CacheIntegrationTest.php b/tests/Integration/CacheIntegrationTest.php index 0b3199f..73a07cd 100644 --- a/tests/Integration/CacheIntegrationTest.php +++ b/tests/Integration/CacheIntegrationTest.php @@ -7,6 +7,8 @@ use Cache\IntegrationTests\SimpleCacheTest; use LLegaz\Cache\RedisCache as SUT; use LLegaz\Cache\Tests\TestState; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\SimpleCache\CacheInterface; use TypeError; diff --git a/tests/Integration/CacheIntegrationWithPCTest.php b/tests/Integration/CacheIntegrationWithPCTest.php index 65bbde2..b8be434 100644 --- a/tests/Integration/CacheIntegrationWithPCTest.php +++ b/tests/Integration/CacheIntegrationWithPCTest.php @@ -7,6 +7,8 @@ use Cache\IntegrationTests\SimpleCacheTest; use LLegaz\Cache\RedisCache as SUT; use LLegaz\Cache\Tests\TestState; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\SimpleCache\CacheInterface; use TypeError; diff --git a/tests/Integration/PoolIntegrationTest.php b/tests/Integration/PoolIntegrationTest.php index 253ee57..027871f 100644 --- a/tests/Integration/PoolIntegrationTest.php +++ b/tests/Integration/PoolIntegrationTest.php @@ -8,6 +8,7 @@ use LLegaz\Cache\Pool\CacheEntryPool as SUT; use LLegaz\Cache\RedisEnhancedCache; use LLegaz\Cache\Tests\TestState; +use PHPUnit\Framework\Attributes\Before; use Psr\Cache\CacheItemPoolInterface; if (!defined('SKIP_INTEGRATION_TESTS')) { diff --git a/tests/Integration/PoolIntegrationWithPCTest.php b/tests/Integration/PoolIntegrationWithPCTest.php index 5a1f1d3..8dee8c1 100644 --- a/tests/Integration/PoolIntegrationWithPCTest.php +++ b/tests/Integration/PoolIntegrationWithPCTest.php @@ -8,6 +8,7 @@ use LLegaz\Cache\Pool\CacheEntryPool as SUT; use LLegaz\Cache\RedisEnhancedCache; use LLegaz\Cache\Tests\TestState; +use PHPUnit\Framework\Attributes\Before; use Psr\Cache\CacheItemPoolInterface; if (!defined('SKIP_INTEGRATION_TESTS')) { From 4ecaed0e67355f3467860c0e126d0e6b086dcda1 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Fri, 3 Apr 2026 13:37:27 +0200 Subject: [PATCH 03/10] stan command added --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 61d08d9..16c4593 100644 --- a/composer.json +++ b/composer.json @@ -47,13 +47,14 @@ } }, "scripts": { + "cs":"@phpcsfixer", "pu":"@phpunit", "puv":"@phpunit-verbose", "pui":"@phpunit-int-suite", "puiv":"@phpunit-int-verbose", "puf":"@phpunit-func-suite", "pufv":"@phpunit-func-verbose", - "cs":"@phpcsfixer", + "stan":"vendor/bin/phpstan analyse -l 6 src tests", "test": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full", "test-only": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full --filter SecurityTest::testSpecialCharactersDoNotCauseInjection", "test-psr16": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full --filter CacheIntegrationTest", From 0f9435d0785b46b76203c631dc34e4f438840d31 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Fri, 3 Apr 2026 14:10:22 +0200 Subject: [PATCH 04/10] phpstan configuraiton file added --- composer.json | 2 +- phpstan.neon.dist | 8 ++++++++ src/CacheEntryPool/CacheEntryPool.php | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 phpstan.neon.dist diff --git a/composer.json b/composer.json index 16c4593..7401810 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "puiv":"@phpunit-int-verbose", "puf":"@phpunit-func-suite", "pufv":"@phpunit-func-verbose", - "stan":"vendor/bin/phpstan analyse -l 6 src tests", + "stan":"vendor/bin/phpstan analyse -c phpstan.neon.dist", "test": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full", "test-only": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full --filter SecurityTest::testSpecialCharactersDoNotCauseInjection", "test-psr16": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full --filter CacheIntegrationTest", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..3deb878 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,8 @@ +parameters: + level: 1 + paths: + - src + - tests + excludePaths: + - src/redisTestCLI.php + - src/redis.php diff --git a/src/CacheEntryPool/CacheEntryPool.php b/src/CacheEntryPool/CacheEntryPool.php index b8fc41f..ea63244 100644 --- a/src/CacheEntryPool/CacheEntryPool.php +++ b/src/CacheEntryPool/CacheEntryPool.php @@ -353,6 +353,7 @@ public function commit(): bool return true; } + $deferred= []; foreach ($this->deferredItems as $key => $item) { if (!$this->isExpired($item)) { $deferred[$key] = $item->get(); From b6ae75b4731249fd706b0ec7509e475428deb6af Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Fri, 3 Apr 2026 14:30:31 +0200 Subject: [PATCH 05/10] PHP Stan 2nd pass --- src/RedisCache.php | 4 +++- src/RedisEnhancedCache.php | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/RedisCache.php b/src/RedisCache.php index e941ebf..73e7370 100644 --- a/src/RedisCache.php +++ b/src/RedisCache.php @@ -236,6 +236,7 @@ public function get(string $key, mixed $default = null): mixed */ private function getWithNonStrKey(mixed $key, mixed $default = null): mixed { + // @phpstan-ignore method.void return $this->get($this->checkKeyValidity($key), $default); } @@ -405,7 +406,7 @@ public function setMultiple(iterable $values, null|int|\DateInterval $ttl = self $this->formatException($t); $redisResponse = false; } finally { - return $redisResponse; + return $redisResponse; // @phpstan-ignore variable.undefined } } @@ -523,6 +524,7 @@ protected function setCorrectValue(string &$value): mixed return self::DOES_NOT_EXIST; } finally { + // @phpstan-ignore variable.undefined if ($tmp !== false || ($tmp === false && $value === 'b:0;')) { $value = $tmp; // if value var wasn't a string affect its original value type to it } diff --git a/src/RedisEnhancedCache.php b/src/RedisEnhancedCache.php index 2e01d8b..5341075 100644 --- a/src/RedisEnhancedCache.php +++ b/src/RedisEnhancedCache.php @@ -5,6 +5,7 @@ namespace LLegaz\Cache; use LLegaz\Cache\Exception\InvalidKeyException; +use LLegaz\Cache\Exception\InvalidArgumentException; /** * ------------------------------------------------------------------------------------------------------------ @@ -161,12 +162,17 @@ public function storeToPool(array $values, string $pool = self::DEFAULT_POOL): b return $this->getRedis()->hmset($pool, $values) == 'OK'; } elseif ($cnt === 1) { $key = array_keys($values)[0]; - $value = isset($key) ? $values[$key] : (isset($values[0]) ? $values[0] : null); + $value =$values[$key]; if (!$this->exist($value)) { /** * @todo test this specific scenario (maybe apply it to hmset ?) + * @todo and maybe refactor that exception handling system inherited from previous project (redis-adapter) + * + * because all values are authorized except this predefined value to sort actual existing values internally... */ - $this->throwUEx('The value: ' . $value . ' isn\'t accepted'); // because all values are authorized except this predefined value to sort actual exisiting values internally... + $e = new InvalidArgumentException('The value: ' . $value . ' isn\'t accepted'); + $this->formatException($e); + $this->throwUEx(); } if ($value) { //hset should returns the number of fields stored for a single key (always one here) From eec9a5444eac0cf0f26a7b52a963a1981d2c27d0 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Fri, 3 Apr 2026 16:50:46 +0200 Subject: [PATCH 06/10] PHP Stan 3rd pass --- phpstan.neon.dist | 2 +- src/CacheEntryPool/CacheEntryPool.php | 16 +++++----------- tests/Unit/SimpleCacheRCTest.php | 1 + tests/Unit/SimpleCacheTest.php | 1 + 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 3deb878..0c46a93 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 1 + level: 2 paths: - src - tests diff --git a/src/CacheEntryPool/CacheEntryPool.php b/src/CacheEntryPool/CacheEntryPool.php index ea63244..40a14c3 100644 --- a/src/CacheEntryPool/CacheEntryPool.php +++ b/src/CacheEntryPool/CacheEntryPool.php @@ -35,10 +35,7 @@ */ class CacheEntryPool implements CacheItemPoolInterface { - /** - * - * @var Psr\SimpleCache\CacheInterface - */ + /** @var RedisEnhancedCache&\Psr\SimpleCache\CacheInterface */ private RedisEnhancedCache $cache; /** @@ -48,15 +45,12 @@ class CacheEntryPool implements CacheItemPoolInterface */ private ?string $poolName = null; - /** - * - * @var array - */ + /** @var array */ private array $deferredItems = []; /** * - * @param Psr\SimpleCache\CacheInterface $cache + * @param RedisEnhancedCache&\Psr\SimpleCache\CacheInterface $cache * @param string|null $pool */ public function __construct(RedisEnhancedCache $cache, ?string $pool = null) @@ -96,7 +90,7 @@ public function clear(): bool * @param string $key * The key to delete. * - * @throws InvalidArgumentException + * @throws \Psr\Cache\InvalidArgumentException * If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException * MUST be thrown. * @@ -139,7 +133,7 @@ public function deleteItems(array $keys): bool * @param string $key * The key for which to return the corresponding Cache Item. * - * @throws InvalidArgumentException + * @throws \Psr\Cache\InvalidArgumentException * If the $key string is not a legal value a \Psr\Cache\InvalidArgumentException * MUST be thrown. * diff --git a/tests/Unit/SimpleCacheRCTest.php b/tests/Unit/SimpleCacheRCTest.php index 131495e..ff4fc08 100644 --- a/tests/Unit/SimpleCacheRCTest.php +++ b/tests/Unit/SimpleCacheRCTest.php @@ -23,6 +23,7 @@ class SimpleCacheRCTest extends RedisAdapterTestBase { protected SUT $cache; + /** @var \PHPUnit\Framework\MockObject\MockObject&RedisClientInterface */ protected RedisClientInterface $redisClient; public static function setUpBeforeClass(): void diff --git a/tests/Unit/SimpleCacheTest.php b/tests/Unit/SimpleCacheTest.php index e68eebc..eeac2e1 100644 --- a/tests/Unit/SimpleCacheTest.php +++ b/tests/Unit/SimpleCacheTest.php @@ -28,6 +28,7 @@ class SimpleCacheTest extends RedisAdapterTestBase { protected SUT $cache; + /** @var \PHPUnit\Framework\MockObject\MockObject&RedisClientInterface */ protected RedisClientInterface $predisClient; public static function setUpBeforeClass(): void From 6401fe6c0b0ae554fafe208c4ad705ef880526d9 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Fri, 3 Apr 2026 18:38:49 +0200 Subject: [PATCH 07/10] PHP Stan 3rd pass 2 --- src/CacheEntryPool/CacheEntryPool.php | 2 +- src/RedisCache.php | 2 +- src/RedisEnhancedCache.php | 10 ++++------ tests/Integration/CacheIntegrationTest.php | 2 +- tests/Unit/SimpleCacheRCTest.php | 3 +-- tests/Unit/SimpleCacheTest.php | 3 +-- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/CacheEntryPool/CacheEntryPool.php b/src/CacheEntryPool/CacheEntryPool.php index 40a14c3..bdb1e6a 100644 --- a/src/CacheEntryPool/CacheEntryPool.php +++ b/src/CacheEntryPool/CacheEntryPool.php @@ -347,7 +347,7 @@ public function commit(): bool return true; } - $deferred= []; + $deferred = []; foreach ($this->deferredItems as $key => $item) { if (!$this->isExpired($item)) { $deferred[$key] = $item->get(); diff --git a/src/RedisCache.php b/src/RedisCache.php index 73e7370..695b9dc 100644 --- a/src/RedisCache.php +++ b/src/RedisCache.php @@ -524,7 +524,7 @@ protected function setCorrectValue(string &$value): mixed return self::DOES_NOT_EXIST; } finally { - // @phpstan-ignore variable.undefined + // @phpstan-ignore variable.undefined if ($tmp !== false || ($tmp === false && $value === 'b:0;')) { $value = $tmp; // if value var wasn't a string affect its original value type to it } diff --git a/src/RedisEnhancedCache.php b/src/RedisEnhancedCache.php index 5341075..2c3150e 100644 --- a/src/RedisEnhancedCache.php +++ b/src/RedisEnhancedCache.php @@ -4,8 +4,8 @@ namespace LLegaz\Cache; -use LLegaz\Cache\Exception\InvalidKeyException; use LLegaz\Cache\Exception\InvalidArgumentException; +use LLegaz\Cache\Exception\InvalidKeyException; /** * ------------------------------------------------------------------------------------------------------------ @@ -162,12 +162,12 @@ public function storeToPool(array $values, string $pool = self::DEFAULT_POOL): b return $this->getRedis()->hmset($pool, $values) == 'OK'; } elseif ($cnt === 1) { $key = array_keys($values)[0]; - $value =$values[$key]; + $value = $values[$key]; if (!$this->exist($value)) { /** * @todo test this specific scenario (maybe apply it to hmset ?) * @todo and maybe refactor that exception handling system inherited from previous project (redis-adapter) - * + * * because all values are authorized except this predefined value to sort actual existing values internally... */ $e = new InvalidArgumentException('The value: ' . $value . ' isn\'t accepted'); @@ -244,10 +244,8 @@ public function fetchFromPool(mixed $key, string $pool = self::DEFAULT_POOL): mi $data[$key] = self::DOES_NOT_EXIST; } } - if (count($data)) { - return $data; - } + return $data; } break; diff --git a/tests/Integration/CacheIntegrationTest.php b/tests/Integration/CacheIntegrationTest.php index 73a07cd..ea70d80 100644 --- a/tests/Integration/CacheIntegrationTest.php +++ b/tests/Integration/CacheIntegrationTest.php @@ -124,7 +124,7 @@ public static function invalidTEKeysSingle() /** * Type Error keys (psr/cache version 3) * - * @return type + * @return array */ public static function invalidTEKeys() { diff --git a/tests/Unit/SimpleCacheRCTest.php b/tests/Unit/SimpleCacheRCTest.php index ff4fc08..413a516 100644 --- a/tests/Unit/SimpleCacheRCTest.php +++ b/tests/Unit/SimpleCacheRCTest.php @@ -379,11 +379,10 @@ public function testSetWithTtl() /** * - * @return type + * @return RedisClientInterface */ protected function getSelfClient(): RedisClientInterface { return $this->redisClient; } - } diff --git a/tests/Unit/SimpleCacheTest.php b/tests/Unit/SimpleCacheTest.php index eeac2e1..11a54e5 100644 --- a/tests/Unit/SimpleCacheTest.php +++ b/tests/Unit/SimpleCacheTest.php @@ -361,11 +361,10 @@ public function testSetMultipleWithTtl() /** * - * @return type + * @return RedisClientInterface */ protected function getSelfClient(): RedisClientInterface { return $this->predisClient; } - } From ac8354c3f9a6dc1efd0caf4efa685a0ee6cbb721 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Fri, 3 Apr 2026 18:55:34 +0200 Subject: [PATCH 08/10] obscure refactor in between my phpstan init --- src/RedisEnhancedCache.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/RedisEnhancedCache.php b/src/RedisEnhancedCache.php index 2c3150e..ca5bd19 100644 --- a/src/RedisEnhancedCache.php +++ b/src/RedisEnhancedCache.php @@ -229,7 +229,11 @@ public function fetchFromPool(mixed $key, string $pool = self::DEFAULT_POOL): mi break; case 'array': - if (count($key)) { + if (count($key) === 1) { + // redirect to string's or integer's case + return $this->fetchFromPool(reset($key), $pool); + } + if (count($key) > 1) { $this->checkKeysValidity($key); $this->begin(); $data = array_combine( From 82abe3fdefb659e01c97456b216730daa5fefe9b Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Tue, 28 Apr 2026 01:02:45 +0200 Subject: [PATCH 09/10] LICENSE updated --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 36e08f5..ce44058 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017-2025 Laurent LEGAZ +Copyright (c) 2017-2026 Laurent LEGAZ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From b229cca05d42989127cffd6ba48b0f64cf66d705 Mon Sep 17 00:00:00 2001 From: Laurent Legaz Date: Tue, 28 Apr 2026 01:54:22 +0200 Subject: [PATCH 10/10] CI workflow updated, stan added --- .github/workflows/CI.yml | 6 +++++- .gitignore | 3 ++- composer.json | 4 +++- phpstan.neon.dist | 5 +---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bfe0e6c..55d4bc2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -71,8 +71,12 @@ jobs: # Step 7 - name: Check code style (PSR-12) - run: composer cs + run: composer cs:check # Step 8: Run entire tests suite - name: Run all tests run: composer test + + # Step 9: Static code analysis + - name: Run static code analysis + run: composer stan-dist \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1190cfc..1c155fa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ composer.lock /.phpunit.cache .phpunit.result.cache /.php-cs-fixer.cache +phpstan.neon /src/redis.php /src/redisTestCLI.php -/vendor +/vendor \ No newline at end of file diff --git a/composer.json b/composer.json index 7401810..1c44c80 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,9 @@ "puiv":"@phpunit-int-verbose", "puf":"@phpunit-func-suite", "pufv":"@phpunit-func-verbose", - "stan":"vendor/bin/phpstan analyse -c phpstan.neon.dist", + "cs:check": "@phpcsfixer --dry-run --format=txt --verbose --diff --ansi --allow-unsupported-php-version=yes", + "stan":"vendor/bin/phpstan analyse -c phpstan.neon", + "stan-dist":"vendor/bin/phpstan analyse -c phpstan.neon.dist", "test": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full", "test-only": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full --filter SecurityTest::testSpecialCharactersDoNotCauseInjection", "test-psr16": "./vendor/bin/phpunit --display-deprecations --display-notices --display-warnings --colors=always --configuration ./phpunit.xml --bootstrap .phpunit_full --filter CacheIntegrationTest", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0c46a93..63aadba 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,8 +1,5 @@ parameters: - level: 2 + level: 6 paths: - src - tests - excludePaths: - - src/redisTestCLI.php - - src/redis.php