Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 40 additions & 18 deletions src/Illuminate/Cache/MemoizedStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function get($key)
$prefixedKey = $this->prefix($key);

if (array_key_exists($prefixedKey, $this->cache)) {
return $this->cache[$prefixedKey];
return ! is_null($this->cache[$prefixedKey]) ? $this->cache[$prefixedKey] : null;
}

return $this->cache[$prefixedKey] = $this->repository->get($key);
Expand Down Expand Up @@ -100,24 +100,29 @@ public function many(array $keys)
*/
public function put($key, $value, $seconds)
{
unset($this->cache[$this->prefix($key)]);

return $this->repository->put($key, $value, $seconds);
return tap($this->repository->put($key, $value, $seconds), function ($result) use ($key, $value) {
if ($result) {
$this->cache[$this->prefix($key)] = $value;
}
});
}

/**
* Store multiple items in the cache for a given number of seconds.
*
* @param array $values
* @param int $seconds
* @return bool
*/
public function putMany(array $values, $seconds)
{
foreach ($values as $key => $value) {
unset($this->cache[$this->prefix($key)]);
}

return $this->repository->putMany($values, $seconds);
return tap($this->repository->putMany($values, $seconds), function ($result) use ($values) {
if ($result) {
foreach ($values as $key => $value) {
$this->cache[$this->prefix($key)] = $value;
}
}
});
}

/**
Expand All @@ -129,9 +134,11 @@ public function putMany(array $values, $seconds)
*/
public function increment($key, $value = 1)
{
unset($this->cache[$this->prefix($key)]);

return $this->repository->increment($key, $value);
return tap($this->repository->increment($key, $value), function ($result) use ($key) {
if (false !== $result) {
$this->cache[$this->prefix($key)] = $result;
}
});
}

/**
Expand All @@ -143,9 +150,11 @@ public function increment($key, $value = 1)
*/
public function decrement($key, $value = 1)
{
unset($this->cache[$this->prefix($key)]);

return $this->repository->decrement($key, $value);
return tap($this->repository->decrement($key, $value), function ($result) use ($key) {
if (false !== $result) {
$this->cache[$this->prefix($key)] = $result;
}
});
}

/**
Expand All @@ -157,9 +166,11 @@ public function decrement($key, $value = 1)
*/
public function forever($key, $value)
{
unset($this->cache[$this->prefix($key)]);

return $this->repository->forever($key, $value);
return tap($this->repository->forever($key, $value), function ($result) use ($key, $value) {
if ($result) {
$this->cache[$this->prefix($key)] = $value;
}
});
}

/**
Expand Down Expand Up @@ -240,4 +251,15 @@ protected function prefix($key)
{
return $this->getPrefix().$key;
}

private function normalizeForDriver($value)
{
$driver = $this->repository->getStore();

if ($driver instanceof \Illuminate\Cache\RedisStore) {
return (string) $value;
}

return $value;
}
}
4 changes: 2 additions & 2 deletions src/Illuminate/Cache/RedisStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public function add($key, $value, $seconds)
*/
public function increment($key, $value = 1)
{
return $this->connection()->incrby($this->prefix.$key, $value);
return (string) $this->connection()->incrby($this->prefix.$key, $value);
}

/**
Expand All @@ -198,7 +198,7 @@ public function increment($key, $value = 1)
*/
public function decrement($key, $value = 1)
{
return $this->connection()->decrby($this->prefix.$key, $value);
return (string) $this->connection()->decrby($this->prefix.$key, $value);
}

/**
Expand Down
121 changes: 121 additions & 0 deletions tests/Integration/Cache/MemoizedStoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,21 @@
use Illuminate\Cache\Events\WritingKey;
use Illuminate\Contracts\Cache\Store;
use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Exceptions;
use Illuminate\Support\Facades\Redis;
use Orchestra\Testbench\Attributes\WithMigration;
use Orchestra\Testbench\TestCase;
use Throwable;

#[WithMigration('cache')]
class MemoizedStoreTest extends TestCase
{
use InteractsWithRedis;
use LazilyRefreshDatabase;

protected function setUp(): void
{
Expand Down Expand Up @@ -155,6 +159,34 @@ public function test_it_can_retrieve_already_memoized_and_not_yet_memoized_value
$this->assertSame(['name.0' => 'Tim', 'name.1' => 'Otwell'], $memoized);
}

public function test_put_updates_memoized_value()
{
$memoStore = Cache::memo()->getStore();

$reflection = new \ReflectionClass($memoStore);

$cacheProperty = tap($reflection->getProperty('cache'), function ($reflectionProperty) {
$reflectionProperty->setAccessible(true);
});

$prefixedKey = tap($reflection->getMethod('prefix'), function ($method) {
$method->setAccessible(true);
})->invoke($memoStore, 'name');

Cache::memo()->put('name', 'Tim', 60);

$memoStoreValues = $cacheProperty->getValue($memoStore);
$this->assertArrayHasKey($prefixedKey, $memoStoreValues);
$this->assertSame('Tim', $memoStoreValues[$prefixedKey]);

Cache::memo()->put('name', 'Taylor', 60);

$memoStoreValues = $cacheProperty->getValue($memoStore);
$this->assertArrayHasKey($prefixedKey, $memoStoreValues);
$this->assertNotSame('Tim', $memoStoreValues[$prefixedKey]);
$this->assertSame('Taylor', $memoStoreValues[$prefixedKey]);
}

public function test_put_forgets_memoized_value()
{
Cache::put(['name.0' => 'Tim', 'name.1' => 'Taylor'], 60);
Expand Down Expand Up @@ -190,6 +222,34 @@ public function test_put_many_forgets_memoized_value()
$this->assertSame(['name.0' => 'MacDonald', 'name.1' => 'Taylor'], $memoized);
}

public function test_increment_updates_memoized_value()
{
$memoStore = Cache::memo()->getStore();

$reflection = new \ReflectionClass($memoStore);

$cacheProperty = tap($reflection->getProperty('cache'), function ($reflectionProperty) {
$reflectionProperty->setAccessible(true);
});

$prefixedKey = tap($reflection->getMethod('prefix'), function ($method) {
$method->setAccessible(true);
})->invoke($memoStore, 'count');

Cache::memo()->put('count', 5, 60);

$memoStoreValues = $cacheProperty->getValue($memoStore);
$this->assertArrayHasKey($prefixedKey, $memoStoreValues);
$this->assertEquals('5', $memoStoreValues[$prefixedKey]);

Cache::memo()->increment('count', 3);

$memoStoreValues = $cacheProperty->getValue($memoStore);
$this->assertArrayHasKey($prefixedKey, $memoStoreValues);
$this->assertNotSame('5', $memoStoreValues[$prefixedKey]);
$this->assertEquals('8', $memoStoreValues[$prefixedKey]);
}

public function test_increment_forgets_memoized_value()
{
Cache::put('count', 1, 60);
Expand All @@ -207,6 +267,34 @@ public function test_increment_forgets_memoized_value()
$this->assertSame('2', $memoized);
}

public function test_decrement_updates_memoized_value()
{
$memoStore = Cache::memo()->getStore();

$reflection = new \ReflectionClass($memoStore);

$cacheProperty = tap($reflection->getProperty('cache'), function ($reflectionProperty) {
$reflectionProperty->setAccessible(true);
});

$prefixedKey = tap($reflection->getMethod('prefix'), function ($method) {
$method->setAccessible(true);
})->invoke($memoStore, 'count');

Cache::memo()->put('count', 5, 60);

$memoStoreValues = $cacheProperty->getValue($memoStore);
$this->assertArrayHasKey($prefixedKey, $memoStoreValues);
$this->assertEquals('5', $memoStoreValues[$prefixedKey]);

Cache::memo()->decrement('count', 2);

$memoStoreValues = $cacheProperty->getValue($memoStore);
$this->assertArrayHasKey($prefixedKey, $memoStoreValues);
$this->assertNotSame('5', $memoStoreValues[$prefixedKey]);
$this->assertEquals('3', $memoStoreValues[$prefixedKey]);
}

public function test_decrement_forgets_memoized_value()
{
Cache::put('count', 1, 60);
Expand Down Expand Up @@ -495,4 +583,37 @@ public function test_it_supports_with_flexible()

$this->assertSame('value-2', $value);
}

public function test_it_returns_consistent_types_between_memo_and_underlying_store()
{
foreach (['redis', 'database', 'memcached'] as $name) {
Cache::store($name)->put('count', 0);
Cache::store($name)->increment('count');

$memoized = Cache::memo($name)->get('count');
$live = Cache::store($name)->get('count');

$this->assertSame($live, $memoized, "Failed for cache store: $name");
}
}

public function test_it_returns_consistent_types_for_increment_operations()
{
foreach (['redis', 'database', 'memcached', 'array', 'file', 'null'] as $name) {
Cache::store($name)->put('count', 0);
Cache::memo($name)->increment('count');

$this->assertSame(Cache::store($name)->get('count'), Cache::memo($name)->get('count'), $name);
}
}

public function test_it_returns_consistent_types_for_decrement_operations()
{
foreach (['redis', 'database', 'memcached', 'array', 'file', 'null'] as $name) {
Cache::store($name)->put('count', 10);
Cache::memo($name)->decrement('count');

$this->assertSame(Cache::store($name)->get('count'), Cache::memo($name)->get('count'), $name);
}
}
}
Loading