Skip to content

Commit c8b7ec1

Browse files
committed
Remove unnecessary client() indirection from Redis operations
Operations now call methods directly on RedisConnection instead of going through client(). RedisConnection's __call method proxies to the underlying Redis/RedisCluster client, so the extra indirection was unnecessary. Also updates SafeScan to accept RedisConnection instead of raw Redis client, making it consistent with other operations and enabling proper OPT_PREFIX handling through the connection. Test infrastructure updated to set expectations on connection mocks rather than separate client mocks.
1 parent 9cb1f75 commit c8b7ec1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1119
-1253
lines changed

src/cache/src/Redis/Operations/Add.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function execute(string $key, mixed $value, int $seconds): bool
4040
// - EX: Set expiration in seconds
4141
// - NX: Only set if key does Not eXist
4242
// Returns OK if set, null/false if key already exists
43-
$result = $conn->client()->set(
43+
$result = $conn->set(
4444
$this->context->prefix() . $key,
4545
$this->serialization->serialize($conn, $value),
4646
['EX' => max(1, $seconds), 'NX']

src/cache/src/Redis/Operations/AllTag/Add.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,12 @@ public function execute(string $key, mixed $value, int $seconds, array $tagIds):
5454
private function executePipeline(string $key, mixed $value, int $seconds, array $tagIds): bool
5555
{
5656
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $seconds, $tagIds) {
57-
$client = $conn->client();
5857
$prefix = $this->context->prefix();
5958
$score = now()->addSeconds($seconds)->getTimestamp();
6059

6160
// Pipeline the ZADD operations for tag tracking
6261
if (! empty($tagIds)) {
63-
$pipeline = $client->pipeline();
62+
$pipeline = $conn->pipeline();
6463

6564
foreach ($tagIds as $tagId) {
6665
$pipeline->zadd($prefix . $tagId, $score, $key);
@@ -70,7 +69,7 @@ private function executePipeline(string $key, mixed $value, int $seconds, array
7069
}
7170

7271
// SET key value EX seconds NX - atomic "add if not exists"
73-
$result = $client->set(
72+
$result = $conn->set(
7473
$prefix . $key,
7574
$this->serialization->serialize($conn, $value),
7675
['EX' => max(1, $seconds), 'NX']
@@ -89,17 +88,16 @@ private function executePipeline(string $key, mixed $value, int $seconds, array
8988
private function executeCluster(string $key, mixed $value, int $seconds, array $tagIds): bool
9089
{
9190
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $seconds, $tagIds) {
92-
$client = $conn->client();
9391
$prefix = $this->context->prefix();
9492
$score = now()->addSeconds($seconds)->getTimestamp();
9593

9694
// ZADD to each tag's sorted set (sequential - cross-slot)
9795
foreach ($tagIds as $tagId) {
98-
$client->zadd($prefix . $tagId, $score, $key);
96+
$conn->zadd($prefix . $tagId, $score, $key);
9997
}
10098

10199
// SET key value EX seconds NX - atomic "add if not exists"
102-
$result = $client->set(
100+
$result = $conn->set(
103101
$prefix . $key,
104102
$this->serialization->serialize($conn, $value),
105103
['EX' => max(1, $seconds), 'NX']

src/cache/src/Redis/Operations/AllTag/AddEntry.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,8 @@ public function execute(string $key, int $ttl, array $tagIds, ?string $updateWhe
6363
private function executePipeline(string $key, int $score, array $tagIds, ?string $updateWhen): void
6464
{
6565
$this->context->withConnection(function (RedisConnection $conn) use ($key, $score, $tagIds, $updateWhen) {
66-
$client = $conn->client();
6766
$prefix = $this->context->prefix();
68-
$pipeline = $client->pipeline();
67+
$pipeline = $conn->pipeline();
6968

7069
foreach ($tagIds as $tagId) {
7170
$prefixedTagKey = $prefix . $tagId;
@@ -92,7 +91,6 @@ private function executePipeline(string $key, int $score, array $tagIds, ?string
9291
private function executeCluster(string $key, int $score, array $tagIds, ?string $updateWhen): void
9392
{
9493
$this->context->withConnection(function (RedisConnection $conn) use ($key, $score, $tagIds, $updateWhen) {
95-
$client = $conn->client();
9694
$prefix = $this->context->prefix();
9795

9896
foreach ($tagIds as $tagId) {
@@ -101,10 +99,10 @@ private function executeCluster(string $key, int $score, array $tagIds, ?string
10199
if ($updateWhen) {
102100
// ZADD with flag (NX, XX, GT, LT)
103101
// RedisCluster requires options as array, not string
104-
$client->zadd($prefixedTagKey, [$updateWhen], $score, $key);
102+
$conn->zadd($prefixedTagKey, [$updateWhen], $score, $key);
105103
} else {
106104
// Standard ZADD
107-
$client->zadd($prefixedTagKey, $score, $key);
105+
$conn->zadd($prefixedTagKey, $score, $key);
108106
}
109107
}
110108
});

src/cache/src/Redis/Operations/AllTag/Decrement.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,9 @@ public function execute(string $key, int $value, array $tagIds): int|false
5151
private function executePipeline(string $key, int $value, array $tagIds): int|false
5252
{
5353
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $tagIds) {
54-
$client = $conn->client();
5554
$prefix = $this->context->prefix();
5655

57-
$pipeline = $client->pipeline();
56+
$pipeline = $conn->pipeline();
5857

5958
// ZADD NX to each tag's sorted set (only add if not exists)
6059
foreach ($tagIds as $tagId) {
@@ -81,16 +80,15 @@ private function executePipeline(string $key, int $value, array $tagIds): int|fa
8180
private function executeCluster(string $key, int $value, array $tagIds): int|false
8281
{
8382
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $tagIds) {
84-
$client = $conn->client();
8583
$prefix = $this->context->prefix();
8684

8785
// ZADD NX to each tag's sorted set (sequential - cross-slot)
8886
foreach ($tagIds as $tagId) {
89-
$client->zadd($prefix . $tagId, ['NX'], self::FOREVER_SCORE, $key);
87+
$conn->zadd($prefix . $tagId, ['NX'], self::FOREVER_SCORE, $key);
9088
}
9189

9290
// DECRBY for the value
93-
return $client->decrBy($prefix . $key, $value);
91+
return $conn->decrBy($prefix . $key, $value);
9492
});
9593
}
9694
}

src/cache/src/Redis/Operations/AllTag/Flush.php

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
use Hypervel\Cache\Redis\Support\StoreContext;
88
use Hypervel\Redis\RedisConnection;
9-
use Redis;
10-
use RedisCluster;
119

1210
/**
1311
* Flushes all cache entries associated with all tags.
@@ -54,17 +52,15 @@ public function execute(array $tagIds, array $tagNames): void
5452
private function flushValues(array $tagIds): void
5553
{
5654
$prefix = $this->context->prefix();
55+
$isCluster = $this->context->isCluster();
5756

5857
// Collect all entries and prepare chunks
5958
// (materialize the LazyCollection to get prefixed keys)
6059
$entries = $this->getEntries->execute($tagIds)
6160
->map(fn (string $key) => $prefix . $key);
6261

6362
// Use a single connection for all chunk deletions
64-
$this->context->withConnection(function (RedisConnection $conn) use ($entries) {
65-
$client = $conn->client();
66-
$isCluster = $client instanceof RedisCluster;
67-
63+
$this->context->withConnection(function (RedisConnection $conn) use ($entries, $isCluster) {
6864
foreach ($entries->chunk(self::CHUNK_SIZE) as $chunk) {
6965
$keys = $chunk->all();
7066

@@ -74,10 +70,10 @@ private function flushValues(array $tagIds): void
7470

7571
if ($isCluster) {
7672
// Cluster mode: sequential DEL (keys may be in different slots)
77-
$client->del(...$keys);
73+
$conn->del(...$keys);
7874
} else {
7975
// Standard mode: pipeline for batching
80-
$this->deleteChunkPipelined($client, $keys);
76+
$this->deleteChunkPipelined($conn, $keys);
8177
}
8278
}
8379
});
@@ -86,12 +82,12 @@ private function flushValues(array $tagIds): void
8682
/**
8783
* Delete a chunk of keys using pipeline.
8884
*
89-
* @param object|Redis $client The Redis client (or mock in tests)
85+
* @param RedisConnection $conn The Redis connection
9086
* @param array<string> $keys Keys to delete
9187
*/
92-
private function deleteChunkPipelined(mixed $client, array $keys): void
88+
private function deleteChunkPipelined(RedisConnection $conn, array $keys): void
9389
{
94-
$pipeline = $client->pipeline();
90+
$pipeline = $conn->pipeline();
9591
$pipeline->del(...$keys);
9692
$pipeline->exec();
9793
}

src/cache/src/Redis/Operations/AllTag/FlushStale.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,10 @@ public function execute(array $tagIds): void
5656
private function executePipeline(array $tagIds): void
5757
{
5858
$this->context->withConnection(function (RedisConnection $conn) use ($tagIds) {
59-
$client = $conn->client();
6059
$prefix = $this->context->prefix();
6160
$timestamp = (string) now()->getTimestamp();
6261

63-
$pipeline = $client->pipeline();
62+
$pipeline = $conn->pipeline();
6463

6564
foreach ($tagIds as $tagId) {
6665
$pipeline->zRemRangeByScore(
@@ -86,11 +85,10 @@ private function executePipeline(array $tagIds): void
8685
private function executeCluster(array $tagIds): void
8786
{
8887
$this->context->withConnection(function (RedisConnection $conn) use ($tagIds) {
89-
$client = $conn->client();
9088
$prefix = $this->context->prefix();
9189
$timestamp = (string) now()->getTimestamp();
9290

93-
$multi = $client->multi();
91+
$multi = $conn->multi();
9492

9593
foreach ($tagIds as $tagId) {
9694
$multi->zRemRangeByScore(

src/cache/src/Redis/Operations/AllTag/Forever.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,10 @@ public function execute(string $key, mixed $value, array $tagIds): bool
5050
private function executePipeline(string $key, mixed $value, array $tagIds): bool
5151
{
5252
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $tagIds) {
53-
$client = $conn->client();
5453
$prefix = $this->context->prefix();
5554
$serialized = $this->serialization->serialize($conn, $value);
5655

57-
$pipeline = $client->pipeline();
56+
$pipeline = $conn->pipeline();
5857

5958
// ZADD to each tag's sorted set with score -1 (forever)
6059
foreach ($tagIds as $tagId) {
@@ -77,17 +76,16 @@ private function executePipeline(string $key, mixed $value, array $tagIds): bool
7776
private function executeCluster(string $key, mixed $value, array $tagIds): bool
7877
{
7978
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $tagIds) {
80-
$client = $conn->client();
8179
$prefix = $this->context->prefix();
8280
$serialized = $this->serialization->serialize($conn, $value);
8381

8482
// ZADD to each tag's sorted set (sequential - cross-slot)
8583
foreach ($tagIds as $tagId) {
86-
$client->zadd($prefix . $tagId, self::FOREVER_SCORE, $key);
84+
$conn->zadd($prefix . $tagId, self::FOREVER_SCORE, $key);
8785
}
8886

8987
// SET for the cache value (no expiration)
90-
return (bool) $client->set($prefix . $key, $serialized);
88+
return (bool) $conn->set($prefix . $key, $serialized);
9189
});
9290
}
9391
}

src/cache/src/Redis/Operations/AllTag/Increment.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,9 @@ public function execute(string $key, int $value, array $tagIds): int|false
5151
private function executePipeline(string $key, int $value, array $tagIds): int|false
5252
{
5353
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $tagIds) {
54-
$client = $conn->client();
5554
$prefix = $this->context->prefix();
5655

57-
$pipeline = $client->pipeline();
56+
$pipeline = $conn->pipeline();
5857

5958
// ZADD NX to each tag's sorted set (only add if not exists)
6059
foreach ($tagIds as $tagId) {
@@ -81,16 +80,15 @@ private function executePipeline(string $key, int $value, array $tagIds): int|fa
8180
private function executeCluster(string $key, int $value, array $tagIds): int|false
8281
{
8382
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $tagIds) {
84-
$client = $conn->client();
8583
$prefix = $this->context->prefix();
8684

8785
// ZADD NX to each tag's sorted set (sequential - cross-slot)
8886
foreach ($tagIds as $tagId) {
89-
$client->zadd($prefix . $tagId, ['NX'], self::FOREVER_SCORE, $key);
87+
$conn->zadd($prefix . $tagId, ['NX'], self::FOREVER_SCORE, $key);
9088
}
9189

9290
// INCRBY for the value
93-
return $client->incrBy($prefix . $key, $value);
91+
return $conn->incrBy($prefix . $key, $value);
9492
});
9593
}
9694
}

src/cache/src/Redis/Operations/AllTag/Prune.php

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Hypervel\Redis\Operations\SafeScan;
99
use Hypervel\Redis\RedisConnection;
1010
use Redis;
11-
use RedisCluster;
1211

1312
/**
1413
* Prune stale and orphaned entries from all tag sorted sets.
@@ -48,10 +47,7 @@ public function __construct(
4847
*/
4948
public function execute(int $scanCount = self::DEFAULT_SCAN_COUNT): array
5049
{
51-
$isCluster = $this->context->isCluster();
52-
53-
return $this->context->withConnection(function (RedisConnection $conn) use ($scanCount, $isCluster) {
54-
$client = $conn->client();
50+
return $this->context->withConnection(function (RedisConnection $conn) use ($scanCount) {
5551
$pattern = $this->context->tagScanPattern();
5652
$optPrefix = $this->context->optPrefix();
5753
$prefix = $this->context->prefix();
@@ -66,23 +62,23 @@ public function execute(int $scanCount = self::DEFAULT_SCAN_COUNT): array
6662
];
6763

6864
// Use SafeScan to handle OPT_PREFIX correctly
69-
$safeScan = new SafeScan($client, $optPrefix);
65+
$safeScan = new SafeScan($conn, $optPrefix);
7066

7167
foreach ($safeScan->execute($pattern, $scanCount) as $tagKey) {
7268
++$stats['tags_scanned'];
7369

7470
// Step 1: Remove TTL-expired entries (stale by time)
75-
$staleRemoved = $client->zRemRangeByScore($tagKey, '0', (string) $now);
71+
$staleRemoved = $conn->zRemRangeByScore($tagKey, '0', (string) $now);
7672
$stats['stale_entries_removed'] += is_int($staleRemoved) ? $staleRemoved : 0;
7773

7874
// Step 2: Remove orphaned entries (cache key doesn't exist)
79-
$orphanResult = $this->removeOrphanedEntries($client, $tagKey, $prefix, $scanCount, $isCluster);
75+
$orphanResult = $this->removeOrphanedEntries($conn, $tagKey, $prefix, $scanCount);
8076
$stats['entries_checked'] += $orphanResult['checked'];
8177
$stats['orphans_removed'] += $orphanResult['removed'];
8278

8379
// Step 3: Delete if empty
84-
if ($client->zCard($tagKey) === 0) {
85-
$client->del($tagKey);
80+
if ($conn->zCard($tagKey) === 0) {
81+
$conn->del($tagKey);
8682
++$stats['empty_sets_deleted'];
8783
}
8884

@@ -100,18 +96,17 @@ public function execute(int $scanCount = self::DEFAULT_SCAN_COUNT): array
10096
* @param string $tagKey The tag sorted set key (without OPT_PREFIX, phpredis auto-adds it)
10197
* @param string $prefix The cache prefix (e.g., "cache:")
10298
* @param int $scanCount Number of members per ZSCAN iteration
103-
* @param bool $isCluster Whether we're connected to a Redis Cluster
10499
* @return array{checked: int, removed: int}
105100
*/
106101
private function removeOrphanedEntries(
107-
Redis|RedisCluster $client,
102+
RedisConnection $conn,
108103
string $tagKey,
109104
string $prefix,
110105
int $scanCount,
111-
bool $isCluster,
112106
): array {
113107
$checked = 0;
114108
$removed = 0;
109+
$isCluster = $conn->isCluster();
115110

116111
// phpredis 6.1.0+ uses null as initial cursor, older versions use 0
117112
$iterator = match (true) {
@@ -121,7 +116,7 @@ private function removeOrphanedEntries(
121116

122117
do {
123118
// ZSCAN returns [member => score, ...] array
124-
$members = $client->zScan($tagKey, $iterator, '*', $scanCount);
119+
$members = $conn->zScan($tagKey, $iterator, '*', $scanCount);
125120

126121
if ($members === false || ! is_array($members) || empty($members)) {
127122
break;
@@ -133,7 +128,7 @@ private function removeOrphanedEntries(
133128
// Check which keys exist:
134129
// - Standard Redis: pipeline() batches commands with less overhead
135130
// - Cluster: multi() handles cross-slot commands (pipeline not supported)
136-
$batch = $isCluster ? $client->multi() : $client->pipeline();
131+
$batch = $isCluster ? $conn->multi() : $conn->pipeline();
137132

138133
foreach ($memberKeys as $key) {
139134
$batch->exists($prefix . $key);
@@ -153,7 +148,7 @@ private function removeOrphanedEntries(
153148

154149
// Remove orphaned members from the sorted set
155150
if (! empty($orphanedMembers)) {
156-
$client->zRem($tagKey, ...$orphanedMembers);
151+
$conn->zRem($tagKey, ...$orphanedMembers);
157152
$removed += count($orphanedMembers);
158153
}
159154
} while ($iterator > 0);

src/cache/src/Redis/Operations/AllTag/Put.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,11 @@ public function execute(string $key, mixed $value, int $seconds, array $tagIds):
5252
private function executePipeline(string $key, mixed $value, int $seconds, array $tagIds): bool
5353
{
5454
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $seconds, $tagIds) {
55-
$client = $conn->client();
5655
$prefix = $this->context->prefix();
5756
$score = now()->addSeconds($seconds)->getTimestamp();
5857
$serialized = $this->serialization->serialize($conn, $value);
5958

60-
$pipeline = $client->pipeline();
59+
$pipeline = $conn->pipeline();
6160

6261
// ZADD to each tag's sorted set
6362
foreach ($tagIds as $tagId) {
@@ -83,18 +82,17 @@ private function executePipeline(string $key, mixed $value, int $seconds, array
8382
private function executeCluster(string $key, mixed $value, int $seconds, array $tagIds): bool
8483
{
8584
return $this->context->withConnection(function (RedisConnection $conn) use ($key, $value, $seconds, $tagIds) {
86-
$client = $conn->client();
8785
$prefix = $this->context->prefix();
8886
$score = now()->addSeconds($seconds)->getTimestamp();
8987
$serialized = $this->serialization->serialize($conn, $value);
9088

9189
// ZADD to each tag's sorted set (sequential - cross-slot)
9290
foreach ($tagIds as $tagId) {
93-
$client->zadd($prefix . $tagId, $score, $key);
91+
$conn->zadd($prefix . $tagId, $score, $key);
9492
}
9593

9694
// SETEX for the cache value
97-
return (bool) $client->setex($prefix . $key, max(1, $seconds), $serialized);
95+
return (bool) $conn->setex($prefix . $key, max(1, $seconds), $serialized);
9896
});
9997
}
10098
}

0 commit comments

Comments
 (0)