From 05c51146cdd62ac45a53bd036b060333e40f0f85 Mon Sep 17 00:00:00 2001 From: anggerpradana Date: Wed, 11 Mar 2026 11:37:57 +0700 Subject: [PATCH 1/2] refactor/cache-excaptions --- src/System/Cache/CacheManager.php | 4 ++- .../Cache/Exceptions/CacheException.php | 4 +-- .../InvalidCacheArgumentException.php | 9 +++++ .../UnsupportedCacheDriverException.php | 9 +++++ src/System/Cache/Storage/ApcuStorage.php | 6 ++-- src/System/Cache/Storage/MemcachedStorage.php | 7 ++-- src/System/Cache/Storage/PdoStorage.php | 8 +++-- tests/Cache/CacheManagerTest.php | 17 ++++++++++ tests/Cache/Storage/ApcuStorageTest.php | 33 +++++++++++++++++++ tests/Cache/Storage/MemcachedStorageTest.php | 33 +++++++++++++++++++ tests/Cache/Storage/PdoStorageTest.php | 18 +++++++++- 11 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 src/System/Cache/Exceptions/InvalidCacheArgumentException.php create mode 100644 src/System/Cache/Exceptions/UnsupportedCacheDriverException.php diff --git a/src/System/Cache/CacheManager.php b/src/System/Cache/CacheManager.php index 3617643e..e07233ed 100644 --- a/src/System/Cache/CacheManager.php +++ b/src/System/Cache/CacheManager.php @@ -6,6 +6,8 @@ use System\Cache\Storage\ArrayStorage; +use System\Cache\Exceptions\UnsupportedCacheDriverException; + class CacheManager implements CacheInterface { /** @var array */ @@ -44,7 +46,7 @@ private function resolve(string $driver_name): CacheInterface } if (null === $driver) { - throw new \Exception("Can use driver {$driver_name}."); + throw new UnsupportedCacheDriverException("Can use driver {$driver_name}."); } return $this->driver[$driver_name] = $driver; diff --git a/src/System/Cache/Exceptions/CacheException.php b/src/System/Cache/Exceptions/CacheException.php index 1fe1895e..9b60d13c 100644 --- a/src/System/Cache/Exceptions/CacheException.php +++ b/src/System/Cache/Exceptions/CacheException.php @@ -4,6 +4,6 @@ namespace System\Cache\Exceptions; -class CacheException extends \Exception +interface CacheException extends \Throwable { -} +} \ No newline at end of file diff --git a/src/System/Cache/Exceptions/InvalidCacheArgumentException.php b/src/System/Cache/Exceptions/InvalidCacheArgumentException.php new file mode 100644 index 00000000..f3a833b7 --- /dev/null +++ b/src/System/Cache/Exceptions/InvalidCacheArgumentException.php @@ -0,0 +1,9 @@ +has($key) && false === is_int($this->get($key))) { - throw new \InvalidArgumentException('Value increment must be integer.'); + throw new InvalidCacheArgumentException('Value increment must be integer.'); } $result = \apcu_inc($this->prefix . $key, $value, $success); diff --git a/src/System/Cache/Storage/MemcachedStorage.php b/src/System/Cache/Storage/MemcachedStorage.php index 795ef780..ec9eb311 100644 --- a/src/System/Cache/Storage/MemcachedStorage.php +++ b/src/System/Cache/Storage/MemcachedStorage.php @@ -6,6 +6,8 @@ use System\Cache\CacheInterface; use System\Cache\Exceptions\CacheException; +use System\Cache\Exceptions\InvalidCacheArgumentException; +use System\Cache\Exceptions\UnsupportedCacheDriverException; class MemcachedStorage implements CacheInterface { @@ -22,7 +24,7 @@ public function __construct( $class = '\Memcached'; if (false === class_exists($class) || false === ($memcached instanceof $class)) { - throw new \InvalidArgumentException('The memcached must be an instance of \Memcached.'); + throw new InvalidCacheArgumentException('The memcached must be an instance of \Memcached.'); } $this->memcached = $memcached; @@ -171,6 +173,7 @@ public function remember(string $key, int|\DateInterval|null $ttl, \Closure $cal return $value; } + /** * @template T * @@ -185,7 +188,7 @@ private function call(callable $operation): mixed try { return $operation(); } catch (\MemcachedException $e) { - throw new CacheException($e->getMessage(), (int) $e->getCode(), $e); + throw new UnsupportedCacheDriverException($e->getMessage(), (int) $e->getCode(), $e); } } diff --git a/src/System/Cache/Storage/PdoStorage.php b/src/System/Cache/Storage/PdoStorage.php index 1fd2a817..70dfd7a7 100644 --- a/src/System/Cache/Storage/PdoStorage.php +++ b/src/System/Cache/Storage/PdoStorage.php @@ -5,6 +5,8 @@ namespace System\Cache\Storage; use System\Cache\CacheInterface; +use System\Cache\Exceptions\InvalidCacheArgumentException; +use System\Cache\Exceptions\UnsupportedCacheDriverException; class PdoStorage implements CacheInterface { @@ -19,11 +21,11 @@ public function __construct( /** @var class-string $class */ $class = '\PDO'; if (false === extension_loaded('pdo') || false === class_exists($class)) { - throw new \RuntimeException('The PDO extension is required to use PdoStorage.'); + throw new UnsupportedCacheDriverException('The PDO extension is required to use PdoStorage.'); } if (false === ($this->pdo instanceof $class)) { - throw new \InvalidArgumentException('The pdo must be an instance of \PDO.'); + throw new InvalidCacheArgumentException('The pdo must be an instance of \PDO.'); } } @@ -158,7 +160,7 @@ public function increment(string $key, int $value): int $expiration = (int) $row['expiration']; if (false === is_int($current)) { - throw new \InvalidArgumentException('Value increment must be integer.'); + throw new InvalidCacheArgumentException('Value increment must be integer.'); } $new = $current + $value; diff --git a/tests/Cache/CacheManagerTest.php b/tests/Cache/CacheManagerTest.php index e2a1af4e..79710b0b 100644 --- a/tests/Cache/CacheManagerTest.php +++ b/tests/Cache/CacheManagerTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use System\Cache\CacheInterface; use System\Cache\CacheManager; +use System\Cache\Exceptions\UnsupportedCacheDriverException; use System\Cache\Storage\ArrayStorage; class CacheManagerTest extends TestCase @@ -30,4 +31,20 @@ public function testDriver(): void $this->assertTrue($cache->driver('array2')->set('key1', 'value1')); $this->assertEquals('value1', $cache->driver('array2')->get('key1')); } + + /** + * @test + * + * @testdox It throws UnsupportedCacheDriverException if driver cannot be resolved + * + * @covers \System\Cache\CacheManager::resolve + */ + public function itThrowsUnsupportedCacheDriverExceptionWhenDriverCannotBeResolved(): void + { + $cache = new CacheManager(); + $cache->setDriver('invalid', fn () => null); + + $this->expectException(UnsupportedCacheDriverException::class); + $cache->driver('invalid'); + } } diff --git a/tests/Cache/Storage/ApcuStorageTest.php b/tests/Cache/Storage/ApcuStorageTest.php index c36c29e0..340a7643 100644 --- a/tests/Cache/Storage/ApcuStorageTest.php +++ b/tests/Cache/Storage/ApcuStorageTest.php @@ -5,6 +5,8 @@ namespace System\Text\Cache\Storage; use PHPUnit\Framework\TestCase; +use System\Cache\Exceptions\InvalidCacheArgumentException; +use System\Cache\Exceptions\UnsupportedCacheDriverException; use System\Cache\Storage\ApcuStorage; /** @@ -233,4 +235,35 @@ public function itCanRemember(): void $value = $this->storage->remember('key1', 1, fn (): string => 'value2'); $this->assertEquals('value1', $value); } + + /** + * @test + * + * @testdox It throws UnsupportedCacheDriverException if APCu is not supported + * + * @covers \System\Cache\Storage\ApcuStorage::__construct + */ + public function itThrowsUnsupportedCacheDriverExceptionWhenApcuIsNotSupported(): void + { + if (ApcuStorage::isSupported()) { + $this->markTestSkipped('APCu extension is loaded or enabled for CLI.'); + } + + $this->expectException(UnsupportedCacheDriverException::class); + new ApcuStorage('test_'); + } + + /** + * @test + * + * @testdox It throws InvalidCacheArgumentException if increment value is not integer + * + * @covers \System\Cache\Storage\ApcuStorage::increment + */ + public function itThrowsInvalidCacheArgumentExceptionWhenIncrementValueIsNotInteger(): void + { + $this->storage->set('key', 'not an integer'); + $this->expectException(InvalidCacheArgumentException::class); + $this->storage->increment('key', 1); + } } diff --git a/tests/Cache/Storage/MemcachedStorageTest.php b/tests/Cache/Storage/MemcachedStorageTest.php index 6a09ba54..2f8f0515 100644 --- a/tests/Cache/Storage/MemcachedStorageTest.php +++ b/tests/Cache/Storage/MemcachedStorageTest.php @@ -5,6 +5,8 @@ namespace System\Test\Cache\Storage; use PHPUnit\Framework\TestCase; +use System\Cache\Exceptions\InvalidCacheArgumentException; +use System\Cache\Exceptions\UnsupportedCacheDriverException; use System\Cache\Storage\MemcachedConnector; use System\Cache\Storage\MemcachedStorage; @@ -241,4 +243,35 @@ public function itNormalizesInvalidKeys(): void $this->assertTrue($this->storage->set($longKey, 'value2')); $this->assertEquals('value2', $this->storage->get($longKey)); } + + /** + * @test + * + * @testdox It throws InvalidCacheArgumentException if memcached is not an instance of \Memcached + * + * @covers \System\Cache\Storage\MemcachedStorage::__construct + */ + public function itThrowsInvalidCacheArgumentExceptionWhenMemcachedIsNotInstanceOfMemcached(): void + { + $this->expectException(InvalidCacheArgumentException::class); + new MemcachedStorage(new \stdClass()); + } + + /** + * @test + * + * @testdox It throws UnsupportedCacheDriverException if MemcachedException is thrown + * + * @covers \System\Cache\Storage\MemcachedStorage::get + */ + public function itThrowsUnsupportedCacheDriverExceptionWhenMemcachedExceptionIsThrown(): void + { + $memcachedMock = $this->createMock(\Memcached::class); + $memcachedMock->method('get')->willThrowException(new \MemcachedException('Test exception')); + + $storage = new MemcachedStorage($memcachedMock); + + $this->expectException(UnsupportedCacheDriverException::class); + $storage->get('key'); + } } diff --git a/tests/Cache/Storage/PdoStorageTest.php b/tests/Cache/Storage/PdoStorageTest.php index a7ee8d60..0d51b249 100644 --- a/tests/Cache/Storage/PdoStorageTest.php +++ b/tests/Cache/Storage/PdoStorageTest.php @@ -5,6 +5,8 @@ namespace System\Test\Cache\Storage; use PHPUnit\Framework\TestCase; +use System\Cache\Exceptions\InvalidCacheArgumentException; +use System\Cache\Exceptions\UnsupportedCacheDriverException; use System\Cache\Storage\PdoStorage; /** @@ -141,7 +143,7 @@ public function itCanDecrementCacheValue() public function itCanRememberCacheValue() { $this->assertNull($this->storage->get('rem')); - $value = $this->storage->remember('rem', 60, fn () => 'remembered'); + $value = $this->storage->remember('rem', 60, fn() => 'remembered'); $this->assertEquals('remembered', $value); $this->assertEquals('remembered', $this->storage->get('rem')); } @@ -167,4 +169,18 @@ public function itCanHandleMultipleCacheOperations() $this->assertNull($this->storage->get('a')); $this->assertNull($this->storage->get('b')); } + + /** + * @test + * + * @testdox It throws InvalidCacheArgumentException if increment value is not integer + * + * @covers \System\Cache\Storage\PdoStorage::increment + */ + public function itThrowsInvalidCacheArgumentExceptionWhenIncrementValueIsNotInteger(): void + { + $this->storage->set('key', 'not an integer'); + $this->expectException(InvalidCacheArgumentException::class); + $this->storage->increment('key', 1); + } } From b29f9bdd9645908fe06f596ccdcd30ecba180e2b Mon Sep 17 00:00:00 2001 From: SonyPradana Date: Wed, 11 Mar 2026 13:02:46 +0800 Subject: [PATCH 2/2] formatting --- src/System/Cache/CacheManager.php | 3 +-- src/System/Cache/Exceptions/CacheException.php | 2 +- src/System/Cache/Storage/MemcachedStorage.php | 1 - tests/Cache/Storage/PdoStorageTest.php | 3 +-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/System/Cache/CacheManager.php b/src/System/Cache/CacheManager.php index e07233ed..acd9a624 100644 --- a/src/System/Cache/CacheManager.php +++ b/src/System/Cache/CacheManager.php @@ -4,9 +4,8 @@ namespace System\Cache; -use System\Cache\Storage\ArrayStorage; - use System\Cache\Exceptions\UnsupportedCacheDriverException; +use System\Cache\Storage\ArrayStorage; class CacheManager implements CacheInterface { diff --git a/src/System/Cache/Exceptions/CacheException.php b/src/System/Cache/Exceptions/CacheException.php index 9b60d13c..0aac9e01 100644 --- a/src/System/Cache/Exceptions/CacheException.php +++ b/src/System/Cache/Exceptions/CacheException.php @@ -6,4 +6,4 @@ interface CacheException extends \Throwable { -} \ No newline at end of file +} diff --git a/src/System/Cache/Storage/MemcachedStorage.php b/src/System/Cache/Storage/MemcachedStorage.php index ec9eb311..4c51645b 100644 --- a/src/System/Cache/Storage/MemcachedStorage.php +++ b/src/System/Cache/Storage/MemcachedStorage.php @@ -173,7 +173,6 @@ public function remember(string $key, int|\DateInterval|null $ttl, \Closure $cal return $value; } - /** * @template T * diff --git a/tests/Cache/Storage/PdoStorageTest.php b/tests/Cache/Storage/PdoStorageTest.php index 0d51b249..de075499 100644 --- a/tests/Cache/Storage/PdoStorageTest.php +++ b/tests/Cache/Storage/PdoStorageTest.php @@ -6,7 +6,6 @@ use PHPUnit\Framework\TestCase; use System\Cache\Exceptions\InvalidCacheArgumentException; -use System\Cache\Exceptions\UnsupportedCacheDriverException; use System\Cache\Storage\PdoStorage; /** @@ -143,7 +142,7 @@ public function itCanDecrementCacheValue() public function itCanRememberCacheValue() { $this->assertNull($this->storage->get('rem')); - $value = $this->storage->remember('rem', 60, fn() => 'remembered'); + $value = $this->storage->remember('rem', 60, fn () => 'remembered'); $this->assertEquals('remembered', $value); $this->assertEquals('remembered', $this->storage->get('rem')); }