diff --git a/VERSION b/VERSION index dd1b5b7..db4d9b4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2410.160124 +0.2410.182054 diff --git a/composer.json b/composer.json index 020e212..53212e3 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,9 @@ "Index\\": "src" }, "files": [ + "src/Cache/ArrayCache/_ndx.php", + "src/Cache/Memcached/_ndx.php", + "src/Cache/Valkey/_ndx.php", "src/Db/MariaDb/_ndx.php", "src/Db/NullDb/_ndx.php", "src/Db/Sqlite/_ndx.php" diff --git a/composer.lock b/composer.lock index aa54373..dd66e50 100644 --- a/composer.lock +++ b/composer.lock @@ -943,16 +943,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.6", + "version": "1.12.7", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae" + "reference": "dc2b9976bd8b0f84ec9b0e50cc35378551de7af0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc4d2f145a88ea7141ae698effd64d9df46527ae", - "reference": "dc4d2f145a88ea7141ae698effd64d9df46527ae", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dc2b9976bd8b0f84ec9b0e50cc35378551de7af0", + "reference": "dc2b9976bd8b0f84ec9b0e50cc35378551de7af0", "shasum": "" }, "require": { @@ -997,7 +997,7 @@ "type": "github" } ], - "time": "2024-10-06T15:03:59+00:00" + "time": "2024-10-18T11:12:07+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1594,16 +1594,16 @@ }, { "name": "sebastian/comparator", - "version": "6.1.0", + "version": "6.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d" + "reference": "5ef523a49ae7a302b87b2102b72b1eda8918d686" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa37b9e2ca618cb051d71b60120952ee8ca8b03d", - "reference": "fa37b9e2ca618cb051d71b60120952ee8ca8b03d", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5ef523a49ae7a302b87b2102b72b1eda8918d686", + "reference": "5ef523a49ae7a302b87b2102b72b1eda8918d686", "shasum": "" }, "require": { @@ -1659,7 +1659,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.1.0" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.1.1" }, "funding": [ { @@ -1667,7 +1667,7 @@ "type": "github" } ], - "time": "2024-09-11T15:42:56+00:00" + "time": "2024-10-18T15:00:48+00:00" }, { "name": "sebastian/complexity", diff --git a/src/Cache/ArrayCache/_ndx.php b/src/Cache/ArrayCache/_ndx.php new file mode 100644 index 0000000..b97ef34 --- /dev/null +++ b/src/Cache/ArrayCache/_ndx.php @@ -0,0 +1,11 @@ + */ + private static array $schemes = []; + + /** @var array */ + private static array $backends = []; + + /** + * @throws RuntimeException Will always throw because this is a static class exclusively. + */ + public function __construct() { + throw new RuntimeException('This is a static class, you cannot create an instance of it.'); + } + + /** + * Registers a cache backend with a protocol scheme. + * + * @param string $scheme URL scheme. + * @param string $className Fully qualified class name of the backend. + * @throws InvalidArgumentException If $scheme is already registered. + */ + public static function register(string $scheme, string $className): void { + $scheme = strtolower($scheme); + if(array_key_exists($scheme, self::$schemes)) + throw new InvalidArgumentException('$scheme has already been registered'); + + self::$schemes[$scheme] = $className; + } + + /** + * Creates a cache provider from a DSN URI. + * + * @param string $uri DSN URI. + * @throws RuntimeException If the requested cache backend is not available. + * @return CacheProvider Connection instance. + */ + public static function create(string $uri): CacheProvider { + $parsed = self::parseUri($uri); + + $backend = self::backend($parsed['scheme']); + if(!$backend->isAvailable()) + throw new RuntimeException('requested cache backend is not available'); + + return $backend->createProvider($backend->parseDsn($parsed)); + } + + /** + * Parses a DSN URI into a provider info class. + * + * @param string $uri DSN URI. + * @return CacheProviderInfo Provider info instance. + */ + public static function parse(string $uri): CacheProviderInfo { + $parsed = self::parseUri($uri); + return self::backend($parsed['scheme'])->parseDsn($parsed); + } + + /** + * Creates a cache provider information class from a scheme. + * + * @param string $scheme Cache protocol scheme. + * @throws InvalidArgumentException If $scheme is not a registered protocol scheme. + * @throws RuntimeException If the implementation class is not available or doesn't implement CacheBackend. + * @return CacheBackend Cache backend information instance. + */ + public static function backend(string $scheme): CacheBackend { + $scheme = strtolower($scheme); + if(!array_key_exists($scheme, self::$schemes)) + throw new InvalidArgumentException('$scheme is not a registered scheme'); + + $className = self::$schemes[$scheme]; + if(array_key_exists($className, self::$backends)) + return self::$backends[$className]; + + if(!class_exists($className)) + throw new RuntimeException('implementation class for the given $scheme does not exist'); + + $backend = new $className; + if(!($backend instanceof CacheBackend)) + throw new RuntimeException('implementation class for the given $scheme does not implement CacheBackend'); + + self::$backends[$className] = $backend; + return $backend; + } + + /** @return array{scheme: string, host?: string, port?: int, user?: string, pass?: string, path?: string, query?: string, fragment?: string} */ + private static function parseUri(string $uri): array { + $uri = parse_url($uri); + if($uri === false) + throw new InvalidArgumentException('$uri is not a valid uri'); + if(empty($uri['scheme'])) + throw new InvalidArgumentException('$uri must contain a non-empty scheme component'); + return $uri; + } +} diff --git a/src/Cache/CacheTools.php b/src/Cache/CacheTools.php deleted file mode 100644 index 1c2f472..0000000 --- a/src/Cache/CacheTools.php +++ /dev/null @@ -1,112 +0,0 @@ - ArrayCache\ArrayCacheBackend::class, - 'null' => ArrayCache\ArrayCacheBackend::class, - 'memcached' => Memcached\MemcachedBackend::class, - 'memcache' => Memcached\MemcachedBackend::class, - 'valkey' => Valkey\ValkeyBackend::class, - 'redis' => Valkey\ValkeyBackend::class, - 'keydb' => Valkey\ValkeyBackend::class, - ]; - - /** @return array */ - private static function parseDsnUri(string $dsn): array { - $uri = parse_url($dsn); - if($uri === false) - throw new InvalidArgumentException('$dsn is not a valid uri.'); - return $uri; - } - - /** @param array $uri */ - private static function resolveBackend(array $uri): CacheBackend { - static $backends = null; - if(!is_array($backends)) - $backends = []; - - $scheme = $uri['scheme']; - $backend = $backends[$scheme] ?? null; - - if(!($backend instanceof CacheBackend)) { - if(!array_key_exists($scheme, self::CACHE_PROTOS)) - throw new RuntimeException('No implementation is available for the specified scheme.'); - - $backend = new (self::CACHE_PROTOS[$scheme]); - if(!$backend->isAvailable()) - throw new RuntimeException('Requested cache backend is not available, likely due to missing dependencies.'); - - $backends[$scheme] = $backend; - } - - return $backend; - } - - /** - * Retrieves cache provider based on DSN URL. - * - * Format of the DSN URLs are described in the documentation of the CacheTools class as a whole. - * - * @param string $dsn URL to create cache provider from. - * @throws InvalidArgumentException if $dsn is not a valid URL. - * @throws RuntimeException if no cache provider can be made using the URL. - * @return CacheBackend Cache backend instance. - */ - public static function backend(string $dsn): CacheBackend { - return self::resolveBackend(self::parseDsnUri($dsn)); - } - - /** - * Parses a DSN URL. - * - * Format of the DSN URLs are described in the documentation of the CacheTools class as a whole. - * - * @param string $dsn URL to create cache provider from. - * @throws InvalidArgumentException if $dsn is not a valid URL. - * @throws RuntimeException if no cache provider can be made using the URL. - * @return CacheProviderInfo Cache provider info. - */ - public static function parse(string $dsn): CacheProviderInfo { - $uri = self::parseDsnUri($dsn); - return self::resolveBackend($uri)->parseDsn($uri); - } - - /** - * Uses a DSN URL to create a cache provider instance. - * - * Format of the DSN URLs are described in the documentation of the CacheTools class as a whole. - * - * @param string $dsn URL to create cache provider from. - * @throws InvalidArgumentException if $dsn is not a valid URL. - * @throws RuntimeException if no cache provider can be made using the URL. - * @return CacheProvider A cache provider. - */ - public static function create(string $dsn): CacheProvider { - $uri = self::parseDsnUri($dsn); - $backend = self::resolveBackend($uri); - return $backend->createProvider($backend->parseDsn($uri)); - } -} diff --git a/src/Cache/Memcached/_ndx.php b/src/Cache/Memcached/_ndx.php new file mode 100644 index 0000000..9a4471b --- /dev/null +++ b/src/Cache/Memcached/_ndx.php @@ -0,0 +1,11 @@ +assertInstanceOf(ArrayCacheProvider::class, $arrayCache); } diff --git a/tests/DbBackendsTest.php b/tests/DbBackendsTest.php index d6f4e77..bd742a7 100644 --- a/tests/DbBackendsTest.php +++ b/tests/DbBackendsTest.php @@ -1,5 +1,5 @@