getApp([ 'cache' => [ 'stores' => [ __CLASS__ => [ 'driver' => __CLASS__, ], ], ], ])); $manager->extend(__CLASS__, fn () => $this); $this->assertSame($manager, $manager->store(__CLASS__)); } public function testCustomDriverStaticClosure() { $manager = new CacheManager($this->getApp([ 'cache' => [ 'stores' => [ __CLASS__ => [ 'driver' => __CLASS__, ], ], ], ])); $driver = new stdClass; $manager->extend(__CLASS__, static fn () => $driver); $this->assertSame($driver, $manager->store(__CLASS__)); } public function testCustomDriverOverridesInternalDrivers() { $userConfig = [ 'cache' => [ 'stores' => [ 'my_store' => [ 'driver' => 'array', ], ], ], ]; $app = $this->getApp($userConfig); $cacheManager = new CacheManager($app); $myArrayDriver = (object) ['flag' => 'mm(u_u)mm']; $cacheManager->extend('array', fn () => $myArrayDriver); $driver = $cacheManager->store('my_store'); $this->assertSame('mm(u_u)mm', $driver->flag); } public function testItCanBuildRepositories() { $app = $this->getApp([]); $cacheManager = new CacheManager($app); $arrayCache = $cacheManager->build(['driver' => 'array']); $nullCache = $cacheManager->build(['driver' => 'null']); $this->assertInstanceOf(ArrayStore::class, $arrayCache->getStore()); $this->assertInstanceOf(NullStore::class, $nullCache->getStore()); } public function testItMakesRepositoryWhenContainerHasNoDispatcher() { $userConfig = [ 'cache' => [ 'stores' => [ 'my_store' => [ 'driver' => 'array', ], ], ], ]; $app = $this->getApp($userConfig); $this->assertFalse($app->bound(Dispatcher::class)); $cacheManager = new CacheManager($app); $repo = $cacheManager->repository($theStore = new NullStore); $this->assertNull($repo->getEventDispatcher()); $this->assertSame($theStore, $repo->getStore()); // binding dispatcher after the repo's birth will have no effect. $app->bind(Dispatcher::class, fn () => new Event); $this->assertNull($repo->getEventDispatcher()); $this->assertSame($theStore, $repo->getStore()); $cacheManager = new CacheManager($app); $repo = $cacheManager->repository(new NullStore); // now that the $app has a Dispatcher, the newly born repository will also have one. $this->assertNotNull($repo->getEventDispatcher()); } public function testItRefreshesDispatcherOnAllStores() { $userConfig = [ 'cache' => [ 'stores' => [ 'store_1' => [ 'driver' => 'array', ], 'store_2' => [ 'driver' => 'array', ], ], ], ]; $app = $this->getApp($userConfig); $cacheManager = new CacheManager($app); $repo1 = $cacheManager->store('store_1'); $repo2 = $cacheManager->store('store_2'); $this->assertNull($repo1->getEventDispatcher()); $this->assertNull($repo2->getEventDispatcher()); $dispatcher = new Event; $app->bind(Dispatcher::class, fn () => $dispatcher); $cacheManager->refreshEventDispatcher(); $this->assertNotSame($repo1, $repo2); $this->assertSame($dispatcher, $repo1->getEventDispatcher()); $this->assertSame($dispatcher, $repo2->getEventDispatcher()); } public function testItSetsDefaultDriverChangesGlobalConfig() { $userConfig = [ 'cache' => [ 'default' => 'store_1', 'stores' => [ 'store_1' => [ 'driver' => 'array', ], 'store_2' => [ 'driver' => 'array', ], ], ], ]; $app = $this->getApp($userConfig); $cacheManager = new CacheManager($app); $cacheManager->setDefaultDriver('><((((@>'); $this->assertEquals('><((((@>', $app->get('config')->get('cache.default')); } public function testItPurgesMemoizedStoreObjects() { $userConfig = [ 'cache' => [ 'stores' => [ 'store_1' => [ 'driver' => 'array', ], 'store_2' => [ 'driver' => 'null', ], ], ], ]; $app = $this->getApp($userConfig); $cacheManager = new CacheManager($app); $repo1 = $cacheManager->store('store_1'); $repo2 = $cacheManager->store('store_1'); $repo3 = $cacheManager->store('store_2'); $repo4 = $cacheManager->store('store_2'); $repo5 = $cacheManager->store('store_2'); $this->assertSame($repo1, $repo2); $this->assertSame($repo3, $repo4); $this->assertSame($repo3, $repo5); $this->assertNotSame($repo1, $repo5); $cacheManager->purge('store_1'); // Make sure a now object is built this time. $repo6 = $cacheManager->store('store_1'); $this->assertNotSame($repo1, $repo6); // Make sure Purge does not delete all objects. $repo7 = $cacheManager->store('store_2'); $this->assertSame($repo3, $repo7); } public function testForgetDriver() { $cacheManager = m::mock(CacheManager::class) ->shouldAllowMockingProtectedMethods() ->makePartial(); $cacheManager->shouldReceive('resolve') ->withArgs(['array']) ->times(4) ->andReturn(new ArrayStore); $cacheManager->shouldReceive('getDefaultDriver') ->once() ->andReturn('array'); foreach (['array', ['array'], null] as $option) { $cacheManager->store('array'); $cacheManager->store('array'); $cacheManager->forgetDriver($option); $cacheManager->store('array'); $cacheManager->store('array'); } } public function testForgetDriverForgets() { $cacheManager = new CacheManager([ 'config' => [ 'cache.stores.forget' => [ 'driver' => 'forget', ], ], ]); $cacheManager->extend('forget', function () { return new ArrayStore; }); $cacheManager->store('forget')->forever('foo', 'bar'); $this->assertSame('bar', $cacheManager->store('forget')->get('foo')); $cacheManager->forgetDriver('forget'); $this->assertNull($cacheManager->store('forget')->get('foo')); } public function testThrowExceptionWhenUnknownDriverIsUsed() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Driver [unknown_taxi_driver] is not supported.'); $userConfig = [ 'cache' => [ 'stores' => [ 'my_store' => [ 'driver' => 'unknown_taxi_driver', ], ], ], ]; $app = $this->getApp($userConfig); $cacheManager = new CacheManager($app); $cacheManager->store('my_store'); } public function testThrowExceptionWhenUnknownStoreIsUsed() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Cache store [alien_store] is not defined.'); $userConfig = [ 'cache' => [ 'stores' => [ 'my_store' => [ 'driver' => 'array', ], ], ], ]; $app = $this->getApp($userConfig); $cacheManager = new CacheManager($app); $cacheManager->store('alien_store'); } public function testMakesRepositoryWithoutDispatcherWhenEventsDisabled() { $userConfig = [ 'cache' => [ 'stores' => [ 'my_store' => [ 'driver' => 'array', ], 'my_store_without_events' => [ 'driver' => 'array', 'events' => false, ], ], ], ]; $app = $this->getApp($userConfig); $app->bind(Dispatcher::class, fn () => new Event); $cacheManager = new CacheManager($app); // The repository will have an event dispatcher $repo = $cacheManager->store('my_store'); $this->assertNotNull($repo->getEventDispatcher()); // This repository will not have an event dispatcher as 'with_events' is false $repoWithoutEvents = $cacheManager->store('my_store_without_events'); $this->assertNull($repoWithoutEvents->getEventDispatcher()); } protected function getApp(array $userConfig) { $app = new Container; $app->singleton('config', fn () => new Repository($userConfig)); return $app; } }