Skip to content

Commit d717dc6

Browse files
committed
feat: Added support for callable for TTL in Cache Handlers
1 parent 3cdb4c5 commit d717dc6

14 files changed

Lines changed: 255 additions & 13 deletions

File tree

system/Cache/CacheInterface.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ public function save(string $key, mixed $value, int $ttl = 60): bool;
4444
* Attempts to get an item from the cache, or executes the callback
4545
* and stores the result on cache miss.
4646
*
47-
* @param string $key Cache item name
48-
* @param int $ttl Time To Live, in seconds
49-
* @param Closure(): mixed $callback Callback executed on cache miss
47+
* @param string $key Cache item name
48+
* @param callable(): int|callable(mixed $value): int|int $ttl Time To Live, in seconds
49+
* @param Closure(): mixed $callback Callback executed on cache miss
5050
*/
51-
public function remember(string $key, int $ttl, Closure $callback): mixed;
51+
public function remember(string $key, callable|int $ttl, Closure $callback): mixed;
5252

5353
/**
5454
* Deletes a specific item from the cache store.

system/Cache/Handlers/ApcuHandler.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,14 @@ public function save(string $key, $value, int $ttl = 60): bool
5555
return apcu_store($key, $value, $ttl);
5656
}
5757

58-
public function remember(string $key, int $ttl, Closure $callback): mixed
58+
public function remember(string $key, callable|int $ttl, Closure $callback): mixed
5959
{
6060
$key = static::validateKey($key, $this->prefix);
6161

62+
if (is_callable($ttl)) {
63+
return parent::remember($key, $ttl, $callback);
64+
}
65+
6266
return apcu_entry($key, $callback, $ttl);
6367
}
6468

system/Cache/Handlers/BaseHandler.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use CodeIgniter\Cache\CacheInterface;
1818
use CodeIgniter\Exceptions\InvalidArgumentException;
1919
use Config\Cache;
20+
use ReflectionFunction;
2021

2122
/**
2223
* Base class for cache handling
@@ -64,15 +65,23 @@ public static function validateKey($key, $prefix = ''): string
6465
return strlen($prefix . $key) > static::MAX_KEY_LENGTH ? $prefix . md5($key) : $prefix . $key;
6566
}
6667

67-
public function remember(string $key, int $ttl, Closure $callback): mixed
68+
public function remember(string $key, callable|int $ttl, Closure $callback): mixed
6869
{
6970
$value = $this->get($key);
7071

7172
if ($value !== null) {
7273
return $value;
7374
}
7475

75-
$this->save($key, $value = $callback(), $ttl);
76+
$value = $callback();
77+
78+
if (is_callable($ttl)) {
79+
$ttl = (new ReflectionFunction($ttl(...)))->getNumberOfParameters() > 0
80+
? $ttl($value)
81+
: $ttl();
82+
}
83+
84+
$this->save($key, $value, $ttl);
7685

7786
return $value;
7887
}

system/Cache/Handlers/DummyHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function get(string $key): mixed
3131
return null;
3232
}
3333

34-
public function remember(string $key, int $ttl, Closure $callback): mixed
34+
public function remember(string $key, callable|int $ttl, Closure $callback): mixed
3535
{
3636
return null;
3737
}

system/Test/Mock/MockCache.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use CodeIgniter\Cache\LockStoreProviderInterface;
2121
use CodeIgniter\I18n\Time;
2222
use PHPUnit\Framework\Assert;
23+
use ReflectionFunction;
2324

2425
class MockCache extends BaseHandler implements CacheInterface, LockStoreProviderInterface
2526
{
@@ -72,15 +73,23 @@ public function get(string $key): mixed
7273
*
7374
* @return bool|null
7475
*/
75-
public function remember(string $key, int $ttl, Closure $callback): mixed
76+
public function remember(string $key, callable|int $ttl, Closure $callback): mixed
7677
{
7778
$value = $this->get($key);
7879

7980
if ($value !== null) {
8081
return $value;
8182
}
8283

83-
$this->save($key, $value = $callback(), $ttl);
84+
$value = $callback();
85+
86+
if (is_callable($ttl)) {
87+
$ttl = (new ReflectionFunction($ttl(...)))->getNumberOfParameters() > 0
88+
? $ttl($value)
89+
: $ttl();
90+
}
91+
92+
$this->save($key, $value, $ttl);
8493

8594
return $value;
8695
}

tests/system/Cache/Handlers/ApcuHandlerTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,40 @@ public function testRemember(): void
9292
$this->assertNull($this->handler->get(self::$key1));
9393
}
9494

95+
/**
96+
* This test waits for 3 seconds before last assertion so this
97+
* is naturally a "slow" test on the perspective of the default limit.
98+
*
99+
* @timeLimit 3.5
100+
*/
101+
public function testRememberWithTTLCallable(): void
102+
{
103+
$this->handler->remember(self::$key1, static fn (): int => 2, static fn (): string => 'value');
104+
105+
$this->assertSame('value', $this->handler->get(self::$key1));
106+
$this->assertNull($this->handler->get(self::$dummy));
107+
108+
CLI::wait(3);
109+
$this->assertNull($this->handler->get(self::$key1));
110+
}
111+
112+
/**
113+
* This test waits for 3 seconds before last assertion so this
114+
* is naturally a "slow" test on the perspective of the default limit.
115+
*
116+
* @timeLimit 3.5
117+
*/
118+
public function testRememberWithTTLCallableAndValuePassed(): void
119+
{
120+
$this->handler->remember(self::$key1, static fn ($value): int => $value[0], static fn (): array => [2, 3]);
121+
122+
$this->assertSame([2, 3], $this->handler->get(self::$key1));
123+
$this->assertNull($this->handler->get(self::$dummy));
124+
125+
CLI::wait(3);
126+
$this->assertNull($this->handler->get(self::$key1));
127+
}
128+
95129
public function testSave(): void
96130
{
97131
$this->assertTrue($this->handler->save(self::$key1, 'value'));

tests/system/Cache/Handlers/DummyHandlerTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ public function testRemember(): void
4848
$this->assertNull($dummyHandler);
4949
}
5050

51+
public function testRememberWithTTLCallable(): void
52+
{
53+
$dummyHandler = $this->handler->remember('key', static fn (): int => 2, static fn (): string => 'value');
54+
55+
$this->assertNull($dummyHandler);
56+
}
57+
58+
public function testRememberWithTTLCallableAndValuePassed(): void
59+
{
60+
$dummyHandler = $this->handler->remember('key', static fn ($value): int => $value[0], static fn (): array => [2, 3]);
61+
62+
$this->assertNull($dummyHandler);
63+
}
64+
5165
public function testSave(): void
5266
{
5367
$this->assertTrue($this->handler->save('key', 'value'));

tests/system/Cache/Handlers/FileHandlerTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,40 @@ public function testRemember(): void
144144
$this->assertNull($this->handler->get(self::$key1));
145145
}
146146

147+
/**
148+
* This test waits for 3 seconds before last assertion so this
149+
* is naturally a "slow" test on the perspective of the default limit.
150+
*
151+
* @timeLimit 3.5
152+
*/
153+
public function testRememberWithTTLCallable(): void
154+
{
155+
$this->handler->remember(self::$key1, static fn (): int => 2, static fn (): string => 'value');
156+
157+
$this->assertSame('value', $this->handler->get(self::$key1));
158+
$this->assertNull($this->handler->get(self::$dummy));
159+
160+
CLI::wait(3);
161+
$this->assertNull($this->handler->get(self::$key1));
162+
}
163+
164+
/**
165+
* This test waits for 3 seconds before last assertion so this
166+
* is naturally a "slow" test on the perspective of the default limit.
167+
*
168+
* @timeLimit 3.5
169+
*/
170+
public function testRememberWithTTLCallableAndValuePassed(): void
171+
{
172+
$this->handler->remember(self::$key1, static fn ($value): int => $value[0], static fn (): array => [2, 3]);
173+
174+
$this->assertSame([2, 3], $this->handler->get(self::$key1));
175+
$this->assertNull($this->handler->get(self::$dummy));
176+
177+
CLI::wait(3);
178+
$this->assertNull($this->handler->get(self::$key1));
179+
}
180+
147181
/**
148182
* chmod('path', 0444) does not work on Windows
149183
*/

tests/system/Cache/Handlers/MemcachedHandlerTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,40 @@ public function testRemember(): void
9999
$this->assertNull($this->handler->get(self::$key1));
100100
}
101101

102+
/**
103+
* This test waits for 3 seconds before last assertion so this
104+
* is naturally a "slow" test on the perspective of the default limit.
105+
*
106+
* @timeLimit 3.5
107+
*/
108+
public function testRememberWithTTLCallable(): void
109+
{
110+
$this->handler->remember(self::$key1, static fn (): int => 2, static fn (): string => 'value');
111+
112+
$this->assertSame('value', $this->handler->get(self::$key1));
113+
$this->assertNull($this->handler->get(self::$dummy));
114+
115+
CLI::wait(3);
116+
$this->assertNull($this->handler->get(self::$key1));
117+
}
118+
119+
/**
120+
* This test waits for 3 seconds before last assertion so this
121+
* is naturally a "slow" test on the perspective of the default limit.
122+
*
123+
* @timeLimit 3.5
124+
*/
125+
public function testRememberWithTTLCallableAndValuePassed(): void
126+
{
127+
$this->handler->remember(self::$key1, static fn ($value): int => $value[0], static fn (): array => [2, 3]);
128+
129+
$this->assertSame([2, 3], $this->handler->get(self::$key1));
130+
$this->assertNull($this->handler->get(self::$dummy));
131+
132+
CLI::wait(3);
133+
$this->assertNull($this->handler->get(self::$key1));
134+
}
135+
102136
public function testSave(): void
103137
{
104138
$this->assertTrue($this->handler->save(self::$key1, 'value'));

tests/system/Cache/Handlers/PredisHandlerTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,40 @@ public function testRemember(): void
109109
$this->assertNull($this->handler->get(self::$key1));
110110
}
111111

112+
/**
113+
* This test waits for 3 seconds before last assertion so this
114+
* is naturally a "slow" test on the perspective of the default limit.
115+
*
116+
* @timeLimit 3.5
117+
*/
118+
public function testRememberWithTTLCallable(): void
119+
{
120+
$this->handler->remember(self::$key1, static fn (): int => 2, static fn (): string => 'value');
121+
122+
$this->assertSame('value', $this->handler->get(self::$key1));
123+
$this->assertNull($this->handler->get(self::$dummy));
124+
125+
CLI::wait(3);
126+
$this->assertNull($this->handler->get(self::$key1));
127+
}
128+
129+
/**
130+
* This test waits for 3 seconds before last assertion so this
131+
* is naturally a "slow" test on the perspective of the default limit.
132+
*
133+
* @timeLimit 3.5
134+
*/
135+
public function testRememberWithTTLCallableAndValuePassed(): void
136+
{
137+
$this->handler->remember(self::$key1, static fn ($value): int => $value[0], static fn (): array => [2, 3]);
138+
139+
$this->assertSame([2, 3], $this->handler->get(self::$key1));
140+
$this->assertNull($this->handler->get(self::$dummy));
141+
142+
CLI::wait(3);
143+
$this->assertNull($this->handler->get(self::$key1));
144+
}
145+
112146
public function testSave(): void
113147
{
114148
$this->assertTrue($this->handler->save(self::$key1, 'value'));

0 commit comments

Comments
 (0)