diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4421f5f..b4ac8d9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,16 +22,16 @@ jobs: ports: - 6379:6379 - name: PHP 8.3 + name: PHP 8.5 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.3 + php-version: 8.5 tools: composer coverage: xdebug ini-values: apc.enable_cli=1 @@ -90,7 +90,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca9281d..bdf472d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ --- -image: registry.gitlab.com/aplus-framework/images/base:4 +image: registry.gitlab.com/aplus-framework/images/base:6 include: - template: Security/SAST.gitlab-ci.yml diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index d48ec68..c63ccba 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -10,7 +10,7 @@ use Framework\CodingStandard\Config; use Framework\CodingStandard\Finder; -return (new Config())->setDefaultHeaderComment( +return new Config()->setDefaultHeaderComment( 'Aplus Framework Cache Library', 'Natan Felles ' )->setFinder( diff --git a/composer.json b/composer.json index 20877f2..0b64d96 100644 --- a/composer.json +++ b/composer.json @@ -35,23 +35,23 @@ } ], "require": { - "php": ">=8.3", + "php": ">=8.5", "ext-apcu": "*", "ext-igbinary": "*", "ext-json": "*", "ext-memcached": "*", "ext-msgpack": "*", "ext-redis": "*", - "aplus/debug": "^4.5", - "aplus/log": "^4.0" + "aplus/debug": "^5.0", + "aplus/log": "^5.0" }, "require-dev": { "ext-xdebug": "*", - "aplus/coding-standard": "^2.8", + "aplus/coding-standard": "^3.0", "ergebnis/composer-normalize": "^2.25", "jetbrains/phpstorm-attributes": "^1.0", "phpmd/phpmd": "^2.13", - "phpstan/phpstan": "^1.9", + "phpstan/phpstan": "^2.2", "phpunit/phpunit": "^10.5" }, "minimum-stability": "dev", diff --git a/docker-compose.yml b/docker-compose.yml index 8edab3b..87b7c87 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,6 @@ -version: "3" services: package: - image: registry.gitlab.com/aplus-framework/images/package:4 + image: registry.gitlab.com/aplus-framework/images/package:6 container_name: package-cache working_dir: /package volumes: diff --git a/guide/index.rst b/guide/index.rst index 8a849ae..6de6e27 100644 --- a/guide/index.rst +++ b/guide/index.rst @@ -244,8 +244,8 @@ If it is necessary to define another address, do as in the example below: 'host' => '192.168.1.100', 'port' => 6379, 'timeout' => 0.0, - 'password' => null, - 'database' => null, + 'credentials' => null, + 'db' => null, ]; $cache = new RedisCache($configs); diff --git a/phpmd.xml b/phpmd.xml index 16baad8..dc5a529 100644 --- a/phpmd.xml +++ b/phpmd.xml @@ -2,6 +2,7 @@ + diff --git a/src/ApcuCache.php b/src/ApcuCache.php index 4b51872..5e3350b 100644 --- a/src/ApcuCache.php +++ b/src/ApcuCache.php @@ -29,7 +29,7 @@ protected function initialize() : void public function get(string $key) : mixed { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugGet( $key, @@ -50,7 +50,7 @@ protected function getValue(string $key) : mixed public function set(string $key, mixed $value, ?int $ttl = null) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugSet( $key, @@ -73,7 +73,7 @@ public function set(string $key, mixed $value, ?int $ttl = null) : bool public function delete(string $key) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugDelete( $key, @@ -86,7 +86,7 @@ public function delete(string $key) : bool public function flush() : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugFlush( $start, diff --git a/src/Cache.php b/src/Cache.php index a79da37..d67d5fe 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -187,15 +187,30 @@ public function getDefaultTtl() : int */ public function setDefaultTtl(int $seconds) : static { - if ($seconds < 1) { - throw new InvalidArgumentException( - 'Default TTL must be greater than 0. ' . $seconds . ' given' - ); - } + $this->validateTtl($seconds, true); $this->defaultTtl = $seconds; return $this; } + /** + * Validate TTL. + * + * @since 5 + * + * @param int|null $seconds + * @param bool $isDefault + */ + protected function validateTtl(?int $seconds, bool $isDefault = false) : void + { + if ($seconds < 1) { + $message = 'TTL must be greater than 0. ' . $seconds . ' given'; + if ($isDefault) { + $message = 'Default ' . $message; + } + throw new InvalidArgumentException($message); + } + } + /** * Make the Time To Live value. * @@ -206,7 +221,9 @@ public function setDefaultTtl(int $seconds) : static #[Pure] protected function makeTtl(?int $seconds) : int { - return $seconds ?? $this->getDefaultTtl(); + $seconds ??= $this->getDefaultTtl(); + $this->validateTtl($seconds); + return $seconds; } /** @@ -457,4 +474,16 @@ protected function addDebugFlush(float $start, bool $status) : bool ]); return $status; } + + /** + * Tell if the cache driver is in debug mode. + * + * @since 5 + * + * @return bool + */ + public function isDebugging() : bool + { + return isset($this->debugCollector); + } } diff --git a/src/Debug/CacheCollector.php b/src/Debug/CacheCollector.php index 9d001e5..cfd84d7 100644 --- a/src/Debug/CacheCollector.php +++ b/src/Debug/CacheCollector.php @@ -14,7 +14,7 @@ use Framework\Cache\MemcachedCache; use Framework\Cache\RedisCache; use Framework\Debug\Collector; -use Framework\Debug\Debugger; +use Framework\Debug\Debugger as D; /** * Class CacheCollector. @@ -61,17 +61,17 @@ public function getContents() : string } \ob_start(); ?>

Handler: - getHandler()) ?> + getHandler()) ?>

info['prefix'])) : ?>

Keys Prefix: - info['prefix']) ?> + info['prefix']) ?>

Serializer: - getSerializer()) ?> + getSerializer()) ?>

Commands

getData() as $index => $data): ?> - + - + - + -
+
- + - + @@ -143,7 +143,7 @@ protected function getCommandsTime() : float $total = $data['end'] - $data['start']; $time += $total; } - return Debugger::roundSecondsToMilliseconds($time); + return D::roundSecondsToMilliseconds($time); } protected function getHandler() : string diff --git a/src/FilesCache.php b/src/FilesCache.php index 5157983..31946a7 100644 --- a/src/FilesCache.php +++ b/src/FilesCache.php @@ -25,7 +25,11 @@ class FilesCache extends Cache /** * Files Cache handler configurations. * - * @var array + * @var array{ + * directory: string|null, + * files_permission: int, + * gc: int, + * } */ protected array $configs = [ 'directory' => null, @@ -40,7 +44,11 @@ class FilesCache extends Cache /** * FilesCache constructor. * - * @param array|null $configs Driver specific configurations + * @param array{ + * directory?: string|null, + * files_permission?: int, + * gc?: int, + * }|null $configs Driver specific configurations * @param string|null $prefix Keys prefix * @param Serializer|string $serializer Data serializer * @param Logger|null $logger Logger instance @@ -94,7 +102,7 @@ protected function setBaseDirectory() : void } if (!\is_dir($real)) { throw new RuntimeException( - "Invalid cache directory path: {$real}" + "Cache directory does not exist: {$real}" ); } if (!\is_writable($real)) { @@ -107,7 +115,7 @@ protected function setBaseDirectory() : void public function get(string $key) : mixed { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugGet( $key, @@ -156,7 +164,7 @@ protected function createSubDirectory(string $filepath) : void public function set(string $key, mixed $value, ?int $ttl = null) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugSet( $key, @@ -192,7 +200,7 @@ public function setValue(string $key, mixed $value, ?int $ttl = null) : bool public function delete(string $key) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugDelete( $key, @@ -205,7 +213,7 @@ public function delete(string $key) : bool public function flush() : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugFlush( $start, diff --git a/src/MemcachedCache.php b/src/MemcachedCache.php index 91c4523..c7b315b 100644 --- a/src/MemcachedCache.php +++ b/src/MemcachedCache.php @@ -28,7 +28,14 @@ class MemcachedCache extends Cache /** * Memcached Cache handler configurations. * - * @var array + * @var array{ + * servers: array, + * options: array, + * } */ protected array $configs = [ 'servers' => [ @@ -46,7 +53,14 @@ class MemcachedCache extends Cache /** * MemcachedCache constructor. * - * @param Memcached|array|null $configs Driver specific + * @param Memcached|array{ + * servers?: array, + * options?: array, + * }|null $configs Driver specific * configurations. Set null to not initialize or a custom Memcached object. * @param string|null $prefix Keys prefix * @param Serializer|string $serializer Data serializer @@ -112,7 +126,7 @@ public function getMemcached() : ?Memcached public function get(string $key) : mixed { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugGet( $key, @@ -133,7 +147,7 @@ protected function getValue(string $key) : mixed public function set(string $key, mixed $value, ?int $ttl = null) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugSet( $key, @@ -148,7 +162,7 @@ public function set(string $key, mixed $value, ?int $ttl = null) : bool public function delete(string $key) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugDelete( $key, @@ -161,7 +175,7 @@ public function delete(string $key) : bool public function flush() : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugFlush( $start, diff --git a/src/RedisCache.php b/src/RedisCache.php index bafef71..453c165 100644 --- a/src/RedisCache.php +++ b/src/RedisCache.php @@ -25,20 +25,32 @@ class RedisCache extends Cache /** * Redis Cache handler configurations. * - * @var array + * @var array{ + * host: string, + * port: int, + * timeout: float, + * credentials: array|string|null, + * db: int|null, + * } */ protected array $configs = [ 'host' => '127.0.0.1', 'port' => 6379, 'timeout' => 0.0, - 'password' => null, - 'database' => null, + 'credentials' => null, + 'db' => null, ]; /** * RedisCache constructor. * - * @param Redis|array|null $configs Driver specific + * @param Redis|array{ + * host?: string, + * port?: int, + * timeout?: float, + * credentials?: array|string|null, + * db?: int|null, + * }|null $configs Driver specific * configurations. Set null to not initialize or a custom Redis object. * @param string|null $prefix Keys prefix * @param Serializer|string $serializer Data serializer @@ -71,11 +83,11 @@ protected function connect() : void $this->configs['port'], $this->configs['timeout'] ); - if (isset($this->configs['password'])) { - $this->redis->auth($this->configs['password']); + if (isset($this->configs['credentials'])) { + $this->redis->auth($this->configs['credentials']); } - if (isset($this->configs['database'])) { - $this->redis->select($this->configs['database']); + if (isset($this->configs['db'])) { + $this->redis->select($this->configs['db']); } } @@ -108,7 +120,7 @@ public function getRedis() : ?Redis public function get(string $key) : mixed { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugGet( $key, @@ -130,7 +142,7 @@ protected function getValue(string $key) : mixed public function set(string $key, mixed $value, ?int $ttl = null) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugSet( $key, @@ -153,7 +165,7 @@ public function set(string $key, mixed $value, ?int $ttl = null) : bool public function delete(string $key) : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugDelete( $key, @@ -166,7 +178,7 @@ public function delete(string $key) : bool public function flush() : bool { - if (isset($this->debugCollector)) { + if ($this->isDebugging()) { $start = \microtime(true); return $this->addDebugFlush( $start, diff --git a/tests/FilesCacheTest.php b/tests/FilesCacheTest.php index c0a8b8d..f80cced 100644 --- a/tests/FilesCacheTest.php +++ b/tests/FilesCacheTest.php @@ -81,7 +81,7 @@ public function testInvalidCacheDirectoryPath() : void $this->prefix = 'foo'; $this->expectException(\RuntimeException::class); $this->expectExceptionMessage( - "Invalid cache directory path: {$this->configs['directory']}{$this->prefix}" + "Cache directory does not exist: {$this->configs['directory']}{$this->prefix}" ); new FilesCache($this->configs, $this->prefix, $this->serializer); } diff --git a/tests/MemcachedCacheMultiServerTest.php b/tests/MemcachedCacheMultiServerTest.php index e1aa519..0677b15 100644 --- a/tests/MemcachedCacheMultiServerTest.php +++ b/tests/MemcachedCacheMultiServerTest.php @@ -46,10 +46,10 @@ public function testHostInPool() : void $configs = [ 'servers' => [ [ - 'host' => \getenv('MEMCACHED_HOST'), + 'host' => (string) \getenv('MEMCACHED_HOST'), ], [ - 'host' => \getenv('MEMCACHED_HOST'), + 'host' => (string) \getenv('MEMCACHED_HOST'), ], ], ]; diff --git a/tests/MemcachedCacheTest.php b/tests/MemcachedCacheTest.php index 3bbec2d..c363801 100644 --- a/tests/MemcachedCacheTest.php +++ b/tests/MemcachedCacheTest.php @@ -18,7 +18,7 @@ public function setUp() : void $this->configs = [ 'servers' => [ [ - 'host' => \getenv('MEMCACHED_HOST'), + 'host' => (string) \getenv('MEMCACHED_HOST'), ], ], ]; diff --git a/tests/RedisCacheTest.php b/tests/RedisCacheTest.php index 059e5ae..538c24c 100644 --- a/tests/RedisCacheTest.php +++ b/tests/RedisCacheTest.php @@ -55,7 +55,7 @@ public function testAuth() : void { $this->configs = [ 'host' => \getenv('REDIS_HOST'), - 'password' => 'foo', + 'credentials' => 'foo', ]; $this->expectException(\RedisException::class); $this->setCache(); @@ -65,7 +65,7 @@ public function testSelect() : void { $this->configs = [ 'host' => \getenv('REDIS_HOST'), - 'database' => 0, + 'db' => 0, ]; $this->setCache(); self::assertInstanceOf(RedisCache::class, $this->cache); diff --git a/tests/TestCase.php b/tests/TestCase.php index 00d8420..09917c9 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -242,7 +242,8 @@ public function testDebugRunCommands() : void public function testDebugHandler() : void { - $collector = new class() extends CacheCollector { + $collector = new class() extends CacheCollector + { public function getHandler() : string { return parent::getHandler(); @@ -257,7 +258,8 @@ public function getHandler() : string RedisCache::class => 'redis', }; self::assertSame($handler, $collector->getHandler()); - $cache = new class() extends FilesCache { + $cache = new class() extends FilesCache + { protected Serializer $serializer = Serializer::PHP; public function __construct() @@ -271,4 +273,11 @@ public function __destruct() $cache->setDebugCollector($collector); self::assertStringContainsString('@anonymous', $collector->getHandler()); } + + public function testInvalidTtl() : void + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('TTL must be greater than 0. -2 given'); + $this->cache->set('foo', 'bar', -2); + } }