diff --git a/src/Cache/Adapter/RedisCacheAdapter.php b/src/Cache/Adapter/RedisCacheAdapter.php index 46e8f09..8f02660 100644 --- a/src/Cache/Adapter/RedisCacheAdapter.php +++ b/src/Cache/Adapter/RedisCacheAdapter.php @@ -6,6 +6,8 @@ use Infocyph\CacheLayer\Cache\Item\RedisCacheItem; use Infocyph\CacheLayer\Exceptions\CacheInvalidArgumentException; +use Infocyph\CacheLayer\Support\RedisConnection; +use InvalidArgumentException; use Psr\Cache\CacheItemInterface; use RuntimeException; @@ -205,23 +207,11 @@ protected function supportsItem(CacheItemInterface $item): bool private function connect(string $dsn): \Redis { - $r = new \Redis(); - $parts = parse_url($dsn); - if (!$parts) { - throw new RuntimeException("Invalid Redis DSN: $dsn"); + try { + return RedisConnection::connect($dsn); + } catch (InvalidArgumentException $exception) { + throw new RuntimeException("Invalid Redis DSN: $dsn", 0, $exception); } - $host = is_string($parts['host'] ?? null) ? $parts['host'] : '127.0.0.1'; - $port = is_int($parts['port'] ?? null) ? $parts['port'] : 6379; - $r->connect($host, $port); - if (is_string($parts['pass'] ?? null) && $parts['pass'] !== '') { - $r->auth($parts['pass']); - } - if (is_string($parts['path'] ?? null) && $parts['path'] !== '/') { - $db = (int) ltrim($parts['path'], '/'); - $r->select($db); - } - - return $r; } private function map(string $key): string diff --git a/src/Cluster/Cursor/SqliteCursorStore.php b/src/Cluster/Cursor/SqliteCursorStore.php index ff596ea..8c54b61 100644 --- a/src/Cluster/Cursor/SqliteCursorStore.php +++ b/src/Cluster/Cursor/SqliteCursorStore.php @@ -37,16 +37,11 @@ public function advance(string $eventId): void public function current(): ?string { - try { - $statement = $this->connection->prepare( - 'SELECT last_event_id FROM cachelayer_cluster_cursors ' - . 'WHERE cluster_name = :cluster AND node_id = :node_id LIMIT 1', - ); - $statement->execute([':cluster' => $this->cluster, ':node_id' => $this->nodeId]); - $cursor = $statement->fetchColumn(); - } catch (PDOException $exception) { - throw new ClusterCacheException('Unable to read the cluster cursor.', 0, $exception); - } + $cursor = $this->read( + 'SELECT last_event_id FROM cachelayer_cluster_cursors ' + . 'WHERE cluster_name = :cluster AND node_id = :node_id LIMIT 1', + 'Unable to read the cluster cursor.', + ); return is_string($cursor) && $cursor !== '' ? $cursor : null; } @@ -58,16 +53,11 @@ public function reset(?string $eventId): void public function updatedAt(): ?int { - try { - $statement = $this->connection->prepare( - 'SELECT updated_at FROM cachelayer_cluster_cursors ' - . 'WHERE cluster_name = :cluster AND node_id = :node_id LIMIT 1', - ); - $statement->execute([':cluster' => $this->cluster, ':node_id' => $this->nodeId]); - $updatedAt = $statement->fetchColumn(); - } catch (PDOException $exception) { - throw new ClusterCacheException('Unable to read the cluster cursor update time.', 0, $exception); - } + $updatedAt = $this->read( + 'SELECT updated_at FROM cachelayer_cluster_cursors ' + . 'WHERE cluster_name = :cluster AND node_id = :node_id LIMIT 1', + 'Unable to read the cluster cursor update time.', + ); return is_int($updatedAt) || (is_string($updatedAt) && ctype_digit($updatedAt)) ? (int) $updatedAt @@ -87,6 +77,18 @@ private function createSchemaIfMissing(): void } } + private function read(string $sql, string $failureMessage): mixed + { + try { + $statement = $this->connection->prepare($sql); + $statement->execute([':cluster' => $this->cluster, ':node_id' => $this->nodeId]); + + return $statement->fetchColumn(); + } catch (PDOException $exception) { + throw new ClusterCacheException($failureMessage, 0, $exception); + } + } + private function write(?string $eventId): void { try { diff --git a/src/Cluster/Transport/EventField.php b/src/Cluster/Transport/EventField.php new file mode 100644 index 0000000..86f5942 --- /dev/null +++ b/src/Cluster/Transport/EventField.php @@ -0,0 +1,28 @@ +connect($host, $port); - if (is_string($parts['pass'] ?? null) && $parts['pass'] !== '') { - $client->auth($parts['pass']); - } - if (is_string($parts['path'] ?? null) && $parts['path'] !== '/') { - $client->select((int) ltrim($parts['path'], '/')); - } - - return $client; } } diff --git a/src/Support/RedisConnection.php b/src/Support/RedisConnection.php new file mode 100644 index 0000000..f2386d7 --- /dev/null +++ b/src/Support/RedisConnection.php @@ -0,0 +1,31 @@ +connect($host, $port); + if (is_string($parts['pass'] ?? null) && $parts['pass'] !== '') { + $connection->auth($parts['pass']); + } + if (is_string($parts['path'] ?? null) && $parts['path'] !== '/') { + $connection->select((int) ltrim($parts['path'], '/')); + } + + return $connection; + } +} diff --git a/tests/Support/RedisConnectionTest.php b/tests/Support/RedisConnectionTest.php new file mode 100644 index 0000000..abc3368 --- /dev/null +++ b/tests/Support/RedisConnectionTest.php @@ -0,0 +1,10 @@ + RedisConnection::connect('redis://')) + ->toThrow(\InvalidArgumentException::class, 'Invalid Redis-compatible DSN.'); +});