Skip to content

Commit f4d789a

Browse files
committed
Add transform parameter to Redis::withConnection() for raw phpredis support
- Add $transform parameter to Redis::getConnection() and withConnection() to control Laravel-style vs raw phpredis behavior (default: true) - Update StoreContext::withConnection() to delegate to Redis::withConnection() with transform: false for coroutine context awareness while maintaining raw phpredis behavior needed by cache operations - Update flushByPattern() to use transform: false for consistency - Remove unused $poolFactory from StoreContext (no longer needed) - Add createStoreWithFakeClient() helper to MocksRedisConnections trait to eliminate test setup duplication - Add tests verifying transform parameter behavior
1 parent e9779ba commit f4d789a

Some content is hidden

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

53 files changed

+261
-273
lines changed

src/cache/src/Redis/Support/StoreContext.php

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
namespace Hypervel\Cache\Redis\Support;
66

7-
use Hyperf\Redis\Pool\PoolFactory;
87
use Hypervel\Cache\Redis\TagMode;
8+
use Hypervel\Context\ApplicationContext;
99
use Hypervel\Redis\RedisConnection;
10+
use Hypervel\Redis\RedisFactory;
1011
use Redis;
1112
use RedisCluster;
1213

@@ -33,7 +34,6 @@ class StoreContext
3334
public const TAG_FIELD_VALUE = '1';
3435

3536
public function __construct(
36-
private readonly PoolFactory $poolFactory,
3737
private readonly string $connectionName,
3838
private readonly string $prefix,
3939
private readonly TagMode $tagMode,
@@ -126,25 +126,20 @@ public function registryKey(): string
126126
/**
127127
* Execute callback with a held connection from the pool.
128128
*
129-
* Use this for operations requiring multiple commands on the same
130-
* connection (cluster mode, complex transactions). The connection
131-
* is automatically returned to the pool after the callback completes.
129+
* Delegates to Redis::withConnection() for context awareness (respects
130+
* active pipeline/multi connections). Uses transform: false to provide
131+
* raw phpredis behavior for cache operations.
132132
*
133133
* @template T
134134
* @param callable(RedisConnection): T $callback
135135
* @return T
136136
*/
137137
public function withConnection(callable $callback): mixed
138138
{
139-
$pool = $this->poolFactory->getPool($this->connectionName);
140-
/** @var RedisConnection $connection */
141-
$connection = $pool->get();
142-
143-
try {
144-
return $callback($connection);
145-
} finally {
146-
$connection->release();
147-
}
139+
return ApplicationContext::getContainer()
140+
->get(RedisFactory::class)
141+
->get($this->connectionName)
142+
->withConnection($callback, transform: false);
148143
}
149144

150145
/**

src/cache/src/RedisStore.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,6 @@ public function setPrefix(string $prefix): void
378378
public function getContext(): StoreContext
379379
{
380380
return $this->context ??= new StoreContext(
381-
$this->getPoolFactory(),
382381
$this->connection,
383382
$this->prefix,
384383
$this->tagMode,

src/redis/src/Redis.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,11 @@ protected function shouldUseSameConnection(string $methodName): bool
108108

109109
/**
110110
* Get a connection from coroutine context, or from redis connection pool.
111+
*
112+
* @param bool $hasContextConnection Whether a connection exists in coroutine context
113+
* @param bool $transform Whether to enable Laravel-style result transformation
111114
*/
112-
protected function getConnection(bool $hasContextConnection): RedisConnection
115+
protected function getConnection(bool $hasContextConnection, bool $transform = true): RedisConnection
113116
{
114117
$connection = $hasContextConnection
115118
? Context::get($this->getContextKey())
@@ -122,7 +125,7 @@ protected function getConnection(bool $hasContextConnection): RedisConnection
122125
throw new InvalidRedisConnectionException('The connection is not a valid RedisConnection.');
123126
}
124127

125-
return $connection->shouldTransform(true);
128+
return $connection->shouldTransform($transform);
126129
}
127130

128131
/**
@@ -145,12 +148,13 @@ protected function getContextKey(): string
145148
*
146149
* @template T
147150
* @param callable(RedisConnection): T $callback
151+
* @param bool $transform Whether to enable Laravel-style result transformation (default: true)
148152
* @return T
149153
*/
150-
public function withConnection(callable $callback): mixed
154+
public function withConnection(callable $callback, bool $transform = true): mixed
151155
{
152156
$hasContextConnection = Context::has($this->getContextKey());
153-
$connection = $this->getConnection($hasContextConnection);
157+
$connection = $this->getConnection($hasContextConnection, $transform);
154158

155159
try {
156160
return $callback($connection);
@@ -191,7 +195,8 @@ public function connection(string $name = 'default'): RedisProxy
191195
public function flushByPattern(string $pattern): int
192196
{
193197
return $this->withConnection(
194-
fn (RedisConnection $connection) => $connection->flushByPattern($pattern)
198+
fn (RedisConnection $connection) => $connection->flushByPattern($pattern),
199+
transform: false
195200
);
196201
}
197202
}

tests/Cache/Redis/AllTagSetTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Hypervel\Tests\Cache\Redis;
66

77
use Hypervel\Cache\Redis\AllTagSet;
8+
use Hypervel\Testbench\TestCase;
89
use Hypervel\Tests\Cache\Redis\Concerns\MocksRedisConnections;
9-
use Hypervel\Tests\TestCase;
1010

1111
/**
1212
* Tests for AllTagSet class.

tests/Cache/Redis/AllTaggedCacheTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Hypervel\Tests\Cache\Redis;
66

77
use Carbon\Carbon;
8+
use Hypervel\Testbench\TestCase;
89
use Hypervel\Tests\Cache\Redis\Concerns\MocksRedisConnections;
9-
use Hypervel\Tests\TestCase;
1010
use Redis;
1111
use RuntimeException;
1212

tests/Cache/Redis/AnyTagSetTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use Generator;
88
use Hypervel\Cache\Redis\AnyTagSet;
99
use Hypervel\Cache\RedisStore;
10+
use Hypervel\Testbench\TestCase;
1011
use Hypervel\Tests\Cache\Redis\Concerns\MocksRedisConnections;
11-
use Hypervel\Tests\TestCase;
1212
use Mockery as m;
1313
use Redis;
1414

tests/Cache/Redis/AnyTaggedCacheTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
use Hypervel\Cache\Redis\AnyTaggedCache;
1010
use Hypervel\Cache\Redis\AnyTagSet;
1111
use Hypervel\Cache\TaggedCache;
12+
use Hypervel\Testbench\TestCase;
1213
use Hypervel\Tests\Cache\Redis\Concerns\MocksRedisConnections;
13-
use Hypervel\Tests\TestCase;
1414
use RuntimeException;
1515

1616
/**

tests/Cache/Redis/Concerns/MocksRedisConnections.php

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,22 @@
66

77
use Hyperf\Redis\Pool\PoolFactory;
88
use Hyperf\Redis\Pool\RedisPool;
9-
use Hyperf\Redis\RedisFactory;
9+
use Hyperf\Redis\RedisFactory as HyperfRedisFactory;
1010
use Hypervel\Cache\RedisStore;
1111
use Hypervel\Redis\RedisConnection;
12+
use Hypervel\Redis\RedisFactory as HypervelRedisFactory;
13+
use Hypervel\Redis\RedisProxy;
14+
use Hypervel\Tests\Redis\Stub\FakeRedisClient;
1215
use Mockery as m;
1316
use Redis;
1417
use RedisCluster;
1518

1619
/**
1720
* Shared test infrastructure for Redis cache operation tests.
1821
*
19-
* Provides helper methods for mocking Redis connections, pool factories,
20-
* and creating RedisStore instances for testing.
22+
* Provides helper methods for mocking Redis connections and creating
23+
* RedisStore instances for testing. Requires tests to extend
24+
* `Hypervel\Testbench\TestCase` for proper container setup.
2125
*
2226
* ## Usage Examples
2327
*
@@ -134,6 +138,28 @@ protected function createPoolFactory(
134138
return $poolFactory;
135139
}
136140

141+
/**
142+
* Register a RedisFactory mock in the container.
143+
*
144+
* This sets up the mock that StoreContext::withConnection() uses to get
145+
* connections via ApplicationContext::getContainer().
146+
*/
147+
protected function registerRedisFactoryMock(
148+
m\MockInterface|RedisConnection $connection,
149+
string $connectionName = 'default'
150+
): void {
151+
$redisProxy = m::mock(RedisProxy::class);
152+
$redisProxy->shouldReceive('withConnection')
153+
->andReturnUsing(fn (callable $callback) => $callback($connection));
154+
155+
$redisFactory = m::mock(HypervelRedisFactory::class);
156+
$redisFactory->shouldReceive('get')
157+
->with($connectionName)
158+
->andReturn($redisProxy);
159+
160+
$this->instance(HypervelRedisFactory::class, $redisFactory);
161+
}
162+
137163
/**
138164
* Create a RedisStore with a mocked connection.
139165
*
@@ -148,8 +174,11 @@ protected function createStore(
148174
string $connectionName = 'default',
149175
?string $tagMode = null,
150176
): RedisStore {
177+
// Register RedisFactory mock for StoreContext::withConnection()
178+
$this->registerRedisFactoryMock($connection, $connectionName);
179+
151180
$store = new RedisStore(
152-
m::mock(RedisFactory::class),
181+
m::mock(HyperfRedisFactory::class),
153182
$prefix,
154183
$connectionName,
155184
$this->createPoolFactory($connection, $connectionName)
@@ -189,8 +218,11 @@ protected function createClusterStore(
189218
$connection = $this->mockClusterConnection();
190219
$clusterClient = $connection->_mockClient;
191220

221+
// Register RedisFactory mock for StoreContext::withConnection()
222+
$this->registerRedisFactoryMock($connection, $connectionName);
223+
192224
$store = new RedisStore(
193-
m::mock(RedisFactory::class),
225+
m::mock(HyperfRedisFactory::class),
194226
$prefix,
195227
$connectionName,
196228
$this->createPoolFactory($connection, $connectionName)
@@ -202,4 +234,43 @@ protected function createClusterStore(
202234

203235
return [$store, $clusterClient, $connection];
204236
}
237+
238+
/**
239+
* Create a RedisStore with a FakeRedisClient.
240+
*
241+
* Use this for tests that need proper reference parameter handling (e.g., &$iterator
242+
* in SCAN/HSCAN/ZSCAN operations) which Mockery cannot properly propagate.
243+
*
244+
* @param FakeRedisClient $fakeClient Pre-configured fake client with expected responses
245+
* @param string $prefix Cache key prefix
246+
* @param string $connectionName Redis connection name
247+
* @param null|string $tagMode Optional tag mode ('any' or 'all')
248+
*/
249+
protected function createStoreWithFakeClient(
250+
FakeRedisClient $fakeClient,
251+
string $prefix = 'prefix:',
252+
string $connectionName = 'default',
253+
?string $tagMode = null,
254+
): RedisStore {
255+
$connection = m::mock(RedisConnection::class);
256+
$connection->shouldReceive('release')->zeroOrMoreTimes();
257+
$connection->shouldReceive('serialized')->andReturn(false)->byDefault();
258+
$connection->shouldReceive('client')->andReturn($fakeClient)->byDefault();
259+
260+
// Register RedisFactory mock for StoreContext::withConnection()
261+
$this->registerRedisFactoryMock($connection, $connectionName);
262+
263+
$store = new RedisStore(
264+
m::mock(HyperfRedisFactory::class),
265+
$prefix,
266+
$connectionName,
267+
$this->createPoolFactory($connection, $connectionName)
268+
);
269+
270+
if ($tagMode !== null) {
271+
$store->setTagMode($tagMode);
272+
}
273+
274+
return $store;
275+
}
205276
}

tests/Cache/Redis/ExceptionPropagationTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
use Hypervel\Cache\Redis\AnyTaggedCache;
88
use Hypervel\Cache\Redis\AnyTagSet;
9+
use Hypervel\Testbench\TestCase;
910
use Hypervel\Tests\Cache\Redis\Concerns\MocksRedisConnections;
10-
use Hypervel\Tests\TestCase;
1111
use Mockery as m;
1212
use RedisException;
1313

tests/Cache/Redis/Integration/ClusterFallbackIntegrationTest.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Hypervel\Tests\Cache\Redis\Integration;
66

7-
use Hyperf\Redis\Pool\PoolFactory;
87
use Hypervel\Cache\Redis\AnyTaggedCache;
98
use Hypervel\Cache\Redis\AnyTagSet;
109
use Hypervel\Cache\Redis\Support\StoreContext;
@@ -35,17 +34,11 @@ class ClusterModeRedisStore extends RedisStore
3534
public function getContext(): StoreContext
3635
{
3736
return $this->clusterContext ??= new ClusterModeStoreContext(
38-
$this->getPoolFactoryInternal(),
3937
$this->connection,
4038
$this->getPrefix(),
4139
$this->getTagMode(),
4240
);
4341
}
44-
45-
public function getPoolFactoryInternal(): PoolFactory
46-
{
47-
return parent::getPoolFactory();
48-
}
4942
}
5043

5144
/**

0 commit comments

Comments
 (0)