diff --git a/src/Illuminate/Cache/Events/ForgettingKey.php b/src/Illuminate/Cache/Events/ForgettingKey.php new file mode 100644 index 000000000000..b6a2bb0aaba8 --- /dev/null +++ b/src/Illuminate/Cache/Events/ForgettingKey.php @@ -0,0 +1,8 @@ +value = $value; + $this->seconds = $seconds; + } +} diff --git a/src/Illuminate/Cache/Events/RetrievingKey.php b/src/Illuminate/Cache/Events/RetrievingKey.php new file mode 100644 index 000000000000..39da3ab23994 --- /dev/null +++ b/src/Illuminate/Cache/Events/RetrievingKey.php @@ -0,0 +1,8 @@ +keys = $keys; + } +} diff --git a/src/Illuminate/Cache/Events/WritingKey.php b/src/Illuminate/Cache/Events/WritingKey.php new file mode 100644 index 000000000000..ac874eb13a82 --- /dev/null +++ b/src/Illuminate/Cache/Events/WritingKey.php @@ -0,0 +1,38 @@ +value = $value; + $this->seconds = $seconds; + } +} diff --git a/src/Illuminate/Cache/Events/WritingManyKeys.php b/src/Illuminate/Cache/Events/WritingManyKeys.php new file mode 100644 index 000000000000..e180e6884d11 --- /dev/null +++ b/src/Illuminate/Cache/Events/WritingManyKeys.php @@ -0,0 +1,46 @@ +keys = $keys; + $this->values = $values; + $this->seconds = $seconds; + } +} diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index ab219c308efc..3814ccec3649 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -8,8 +8,15 @@ use DateTimeInterface; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; +use Illuminate\Cache\Events\ForgettingKey; +use Illuminate\Cache\Events\KeyForgetFailed; use Illuminate\Cache\Events\KeyForgotten; +use Illuminate\Cache\Events\KeyWriteFailed; use Illuminate\Cache\Events\KeyWritten; +use Illuminate\Cache\Events\RetrievingKey; +use Illuminate\Cache\Events\RetrievingManyKeys; +use Illuminate\Cache\Events\WritingKey; +use Illuminate\Cache\Events\WritingManyKeys; use Illuminate\Contracts\Cache\Repository as CacheContract; use Illuminate\Contracts\Cache\Store; use Illuminate\Contracts\Events\Dispatcher; @@ -104,6 +111,8 @@ public function get($key, $default = null): mixed return $this->many($key); } + $this->event(new RetrievingKey($this->getName(), $key)); + $value = $this->store->get($this->itemKey($key)); // If we could not find the cache value, we will fire the missed event and get @@ -130,6 +139,8 @@ public function get($key, $default = null): mixed */ public function many(array $keys) { + $this->event(new RetrievingManyKeys($this->getName(), $keys)); + $values = $this->store->many(collect($keys)->map(function ($value, $key) { return is_string($key) ? $key : $value; })->values()->all()); @@ -222,10 +233,14 @@ public function put($key, $value, $ttl = null) return $this->forget($key); } + $this->event(new WritingKey($this->getName(), $key, $value, $seconds)); + $result = $this->store->put($this->itemKey($key), $value, $seconds); if ($result) { $this->event(new KeyWritten($this->getName(), $key, $value, $seconds)); + } else { + $this->event(new KeyWriteFailed($this->getName(), $key, $value, $seconds)); } return $result; @@ -260,11 +275,15 @@ public function putMany(array $values, $ttl = null) return $this->deleteMultiple(array_keys($values)); } + $this->event(new WritingManyKeys($this->getName(), array_keys($values), array_values($values), $seconds)); + $result = $this->store->putMany($values, $seconds); - if ($result) { - foreach ($values as $key => $value) { + foreach ($values as $key => $value) { + if ($result) { $this->event(new KeyWritten($this->getName(), $key, $value, $seconds)); + } else { + $this->event(new KeyWriteFailed($this->getName(), $key, $value, $seconds)); } } @@ -372,10 +391,14 @@ public function decrement($key, $value = 1) */ public function forever($key, $value) { + $this->event(new WritingKey($this->getName(), $key, $value)); + $result = $this->store->forever($this->itemKey($key), $value); if ($result) { $this->event(new KeyWritten($this->getName(), $key, $value)); + } else { + $this->event(new KeyWriteFailed($this->getName(), $key, $value)); } return $result; @@ -456,9 +479,13 @@ public function rememberForever($key, Closure $callback) */ public function forget($key) { + $this->event(new ForgettingKey($this->getName(), $key)); + return tap($this->store->forget($this->itemKey($key)), function ($result) use ($key) { if ($result) { $this->event(new KeyForgotten($this->getName(), $key)); + } else { + $this->event(new KeyForgetFailed($this->getName(), $key)); } }); } diff --git a/tests/Cache/CacheEventsTest.php b/tests/Cache/CacheEventsTest.php index 9513e1495981..30361ba8f8b9 100755 --- a/tests/Cache/CacheEventsTest.php +++ b/tests/Cache/CacheEventsTest.php @@ -5,8 +5,15 @@ use Illuminate\Cache\ArrayStore; use Illuminate\Cache\Events\CacheHit; use Illuminate\Cache\Events\CacheMissed; +use Illuminate\Cache\Events\ForgettingKey; +use Illuminate\Cache\Events\KeyForgetFailed; use Illuminate\Cache\Events\KeyForgotten; +use Illuminate\Cache\Events\KeyWrite; use Illuminate\Cache\Events\KeyWritten; +use Illuminate\Cache\Events\RetrievingKey; +use Illuminate\Cache\Events\RetrievingManyKeys; +use Illuminate\Cache\Events\WritingKey; +use Illuminate\Cache\Events\WritingManyKeys; use Illuminate\Cache\Repository; use Illuminate\Contracts\Cache\Store; use Illuminate\Events\Dispatcher; @@ -25,15 +32,19 @@ public function testHasTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo'])); $this->assertFalse($repository->has('foo')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'baz'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheHit::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux'])); $this->assertTrue($repository->has('baz')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); $this->assertFalse($repository->tags('taylor')->has('foo')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheHit::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux', 'tags' => ['taylor']])); $this->assertTrue($repository->tags('taylor')->has('baz')); } @@ -43,15 +54,24 @@ public function testGetTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo'])); $this->assertNull($repository->get('foo')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingManyKeys::class, ['storeName' => 'array', 'keys' => ['foo', 'bar']])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo'])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'bar'])); + $this->assertSame(['foo' => null, 'bar' => null], $repository->get(['foo', 'bar'])); + + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'baz'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheHit::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux'])); $this->assertSame('qux', $repository->get('baz')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); $this->assertNull($repository->tags('taylor')->get('foo')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheHit::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux', 'tags' => ['taylor']])); $this->assertSame('qux', $repository->tags('taylor')->get('baz')); } @@ -61,7 +81,9 @@ public function testPullTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'baz'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheHit::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux'])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(ForgettingKey::class, ['storeName' => 'array', 'key' => 'baz'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyForgotten::class, ['storeName' => 'array', 'key' => 'baz'])); $this->assertSame('qux', $repository->pull('baz')); } @@ -71,7 +93,9 @@ public function testPullTriggersEventsUsingTags() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheHit::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux', 'tags' => ['taylor']])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(ForgettingKey::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyForgotten::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $this->assertSame('qux', $repository->tags('taylor')->pull('baz')); } @@ -81,9 +105,16 @@ public function testPutTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); $repository->put('foo', 'bar', 99); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingManyKeys::class, ['storeName' => 'array', 'keys' => ['foo', 'baz'], 'values' => ['bar', 'qux'], 'seconds' => 99])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'baz', 'value' => 'qux', 'seconds' => 99])); + $repository->putMany(['foo' => 'bar', 'baz' => 'qux'], 99); + + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99, 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99, 'tags' => ['taylor']])); $repository->tags('taylor')->put('foo', 'bar', 99); } @@ -93,11 +124,15 @@ public function testAddTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo'])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); $this->assertTrue($repository->add('foo', 'bar', 99)); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99, 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99, 'tags' => ['taylor']])); $this->assertTrue($repository->tags('taylor')->add('foo', 'bar', 99)); } @@ -107,9 +142,11 @@ public function testForeverTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null])); $repository->forever('foo', 'bar'); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null, 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null, 'tags' => ['taylor']])); $repository->tags('taylor')->forever('foo', 'bar'); } @@ -119,13 +156,17 @@ public function testRememberTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo'])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99])); $this->assertSame('bar', $repository->remember('foo', 99, function () { return 'bar'; })); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99, 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => 99, 'tags' => ['taylor']])); $this->assertSame('bar', $repository->tags('taylor')->remember('foo', 99, function () { return 'bar'; @@ -137,13 +178,17 @@ public function testRememberForeverTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo'])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null])); $this->assertSame('bar', $repository->rememberForever('foo', function () { return 'bar'; })); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(RetrievingKey::class, ['storeName' => 'array', 'key' => 'foo'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(CacheMissed::class, ['storeName' => 'array', 'key' => 'foo', 'tags' => ['taylor']])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(WritingKey::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null, 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyWritten::class, ['storeName' => 'array', 'key' => 'foo', 'value' => 'bar', 'seconds' => null, 'tags' => ['taylor']])); $this->assertSame('bar', $repository->tags('taylor')->rememberForever('foo', function () { return 'bar'; @@ -155,14 +200,16 @@ public function testForgetTriggersEvents() $dispatcher = $this->getDispatcher(); $repository = $this->getRepository($dispatcher); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(ForgettingKey::class, ['storeName' => 'array', 'key' => 'baz'])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyForgotten::class, ['storeName' => 'array', 'key' => 'baz'])); $this->assertTrue($repository->forget('baz')); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(ForgettingKey::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyForgotten::class, ['storeName' => 'array', 'key' => 'baz', 'tags' => ['taylor']])); $this->assertTrue($repository->tags('taylor')->forget('baz')); } - public function testForgetDoesNotTriggerEventOnFailure() + public function testForgetDoesTriggerFailedEventOnFailure() { $dispatcher = $this->getDispatcher(); $store = m::mock(Store::class); @@ -170,7 +217,8 @@ public function testForgetDoesNotTriggerEventOnFailure() $repository = new Repository($store); $repository->setEventDispatcher($dispatcher); - $dispatcher->shouldReceive('dispatch')->never(); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(ForgettingKey::class, ['key' => 'baz'])); + $dispatcher->shouldReceive('dispatch')->once()->with($this->assertEventMatches(KeyForgetFailed::class, ['key' => 'baz'])); $this->assertFalse($repository->forget('baz')); } diff --git a/tests/Support/SupportFacadesEventTest.php b/tests/Support/SupportFacadesEventTest.php index 15c4a4acc7ab..a5a162036337 100644 --- a/tests/Support/SupportFacadesEventTest.php +++ b/tests/Support/SupportFacadesEventTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Support; use Illuminate\Cache\CacheManager; +use Illuminate\Cache\Events\RetrievingKey; use Illuminate\Cache\Events\CacheMissed; use Illuminate\Config\Repository as ConfigRepository; use Illuminate\Container\Container; @@ -75,13 +76,14 @@ public function testFakeSwapsDispatchersInResolvedCacheRepositories() { $arrayRepository = Cache::store('array'); - $this->events->shouldReceive('dispatch')->once(); + $this->events->shouldReceive('dispatch')->times(2); $arrayRepository->get('foo'); Event::fake(); $arrayRepository->get('bar'); + Event::assertDispatched(RetrievingKey::class); Event::assertDispatched(CacheMissed::class); }