Skip to content

Commit 5977681

Browse files
Adds test for fix.
1 parent fb95caf commit 5977681

File tree

3 files changed

+55
-12
lines changed

3 files changed

+55
-12
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ use App\Models\Article;
133133
Article::latest('published_at')->take(200)->cache([5, 300])->get();
134134
```
135135

136+
> [!WARN]
137+
>
138+
> When using stale revalidation,
139+
136140
## Forgetting results with a key
137141

138142
Cache keys are used to identify multiple queries cached with an identifiable name. These are not mandatory, but if you expect to remove a query from the cache, you will need to identify the query with the `key` argument.

src/CacheAwareConnectionProxy.php

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ public function select($query, $bindings = [], $useReadPdo = true)
7676
// We will use the prefix to operate on the cache directly.
7777
$key = $this->cachePrefix.'|'.$this->computedKey;
7878

79+
// If the user is setting an array, we will steer return the results using "flexible".
80+
if (is_array($this->ttl) && count($this->ttl) > 1 && method_exists($this->repository, 'flexible')) {
81+
return $this->returnResultsUsingFlexible($query, $key, $bindings, $useReadPdo);
82+
}
83+
7984
return $this
8085
->retrieveLock($key)
8186
->block($this->lockWait, function () use ($query, $bindings, $useReadPdo, $key): array {
@@ -84,11 +89,7 @@ public function select($query, $bindings = [], $useReadPdo = true)
8489
if ($results === null) {
8590
$results = $this->connection->select($query, $bindings, $useReadPdo);
8691

87-
if (is_array($this->ttl) && count($this->ttl) > 1 && method_exists($this->repository, 'flexible')) {
88-
$this->repository->flexible($key, $results, $this->ttl);
89-
} else {
90-
$this->repository->put($key, $results, $this->ttl);
91-
}
92+
$this->repository->put($key, $results, $this->ttl);
9293

9394
// If the user added a user key, we will append this computed key to it and save it.
9495
if ($this->userKey) {
@@ -130,7 +131,7 @@ protected function getQueryHash(string $query, array $bindings): string
130131
*/
131132
protected function retrieveLock(string $key): Lock
132133
{
133-
if (! $this->lockWait) {
134+
if (!$this->lockWait) {
134135
return new NoLock($key, $this->lockWait);
135136
}
136137

@@ -178,8 +179,12 @@ protected function addComputedKeyToUserKey(string $key, ?array $list): void
178179
/**
179180
* Gets the timestamp for the expiration time.
180181
*/
181-
protected function getTimestamp(DateInterval|DateTimeInterface|int $expiration): int
182+
protected function getTimestamp(DateInterval|DateTimeInterface|array|int $expiration): int
182183
{
184+
if (is_array($expiration)) {
185+
$expiration = $expiration[1];
186+
}
187+
183188
if ($expiration instanceof DateTimeInterface) {
184189
return $expiration->getTimestamp();
185190
}
@@ -219,6 +224,23 @@ public function __call($method, $arguments)
219224
return $this->connection->{$method}(...$arguments);
220225
}
221226

227+
/**
228+
* Returns the results of the query using stale revalidation.
229+
*/
230+
protected function returnResultsUsingFlexible(string $query, string $key, array $bindings, bool $useReadPdo): mixed
231+
{
232+
return $this->repository
233+
->flexible($key, $this->ttl, function () use ($query, $bindings, $key, $useReadPdo): mixed {
234+
$results = $this->connection->select($query, $bindings, $useReadPdo);
235+
236+
if ($this->userKey) {
237+
$this->addComputedKeyToUserKey($key, $this->repository->get($this->userKey));
238+
}
239+
240+
return $results;
241+
});
242+
}
243+
222244
/**
223245
* Create a new CacheAwareProxy instance.
224246
*/
@@ -247,7 +269,7 @@ protected static function store(?string $store, bool $lockable): Repository
247269
{
248270
$repository = cache()->store($store ?? config('cache-query.store'));
249271

250-
if ($lockable && ! $repository->getStore() instanceof LockProvider) {
272+
if ($lockable && !$repository->getStore() instanceof LockProvider) {
251273
$store ??= cache()->getDefaultDriver();
252274

253275
throw new LogicException("The [$store] cache does not support atomic locks.");

tests/CacheAwareConnectionProxyTest.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,8 @@ public function test_uses_db_flexible_caching_when_using_ttl_as_array_of_values(
455455

456456
$repository = $this->mock(CacheRepository::class);
457457
$repository->expects('put')->never();
458-
$repository->expects('flexible')->with($hash, Mockery::type('array'), [5, 300])->once();
459-
$repository->expects('getMultiple')->with([$hash, ''])->times(1)->andReturn(['' => null, $hash => null]);
458+
$repository->expects('flexible')->with($hash, [5, 300], Mockery::type('\Closure'))->once();
459+
$repository->expects('getMultiple')->never();
460460

461461
$this->mock('cache')->shouldReceive('store')->with(null)->andReturn($repository);
462462

@@ -473,14 +473,31 @@ public function test_uses_eloquent_flexible_caching_when_using_ttl_as_array_of_v
473473

474474
$repository = $this->mock(CacheRepository::class);
475475
$repository->expects('put')->never();
476-
$repository->expects('flexible')->with($hash, Mockery::type('array'), [5, 300])->once();
477-
$repository->expects('getMultiple')->with([$hash, ''])->times(1)->andReturn(['' => null, $hash => null]);
476+
$repository->expects('flexible')->with($hash, [5, 300], Mockery::type('\Closure'))->once();
477+
$repository->expects('getMultiple')->never();
478478

479479
$this->mock('cache')->shouldReceive('store')->with(null)->andReturn($repository);
480480

481481
User::where('id', 1)->cache([5, 300])->first();
482482
}
483483

484+
public function test_flexible_cache_uses_user_key(): void
485+
{
486+
$cached = User::query()->cache(key: 'foo', ttl: [5, 300])->with('posts', function ($posts) {
487+
$posts->whereKey(2);
488+
})->whereKey(1)->first();
489+
490+
User::query()->whereKey(1)->delete();
491+
Post::query()->whereKey(2)->delete();
492+
493+
$renewed = User::query()->cache(key: 'foo', ttl: [5, 300])->with('posts', function ($posts) {
494+
$posts->whereKey(2);
495+
})->whereKey(1)->first();
496+
497+
static::assertTrue($cached->is($renewed));
498+
static::assertCount(1, $renewed->posts);
499+
}
500+
484501
public function test_doesnt_uses_flexible_caching_if_repository_is_not_flexible(): void
485502
{
486503
$hash = 'cache-query|fj8Xyz4K1Zh0tdAamPbG1A';

0 commit comments

Comments
 (0)