'redis', 'tenancy.cache.stores' => ['redis'], ]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); withCacheTables(); }); test('global cache manager stores data in global cache', function (string $store, array $bootstrappers) { config([ 'cache.default' => $store, 'tenancy.bootstrappers' => $bootstrappers, ]); if ($store === 'database') withTenantDatabases(true); expect(cache('foo'))->toBe(null); GlobalCache::put('foo', 'bar'); expect(GlobalCache::get('foo'))->toBe('bar'); $tenant1 = Tenant::create(); tenancy()->initialize($tenant1); expect(GlobalCache::get('foo'))->toBe('bar'); GlobalCache::put('abc', 'xyz'); cache(['def' => 'ghi']); expect(cache('def'))->toBe('ghi'); // different stores expect(cache()->store()->getStore() !== GlobalCache::store()->getStore())->toBeTrue(); if ($store === 'redis') { // same underlying connection. the prefix is set ON THE STORE expect(cache()->store()->getStore()->connection() === GlobalCache::store()->getStore()->connection())->toBeTrue(); } else { // different connections expect(cache()->store()->getStore()->getConnection()->getName())->toBe('tenant'); expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); } tenancy()->end(); expect(GlobalCache::get('abc'))->toBe('xyz'); expect(GlobalCache::get('foo'))->toBe('bar'); expect(cache('def'))->toBe(null); $tenant2 = Tenant::create(); tenancy()->initialize($tenant2); expect(GlobalCache::get('abc'))->toBe('xyz'); expect(GlobalCache::get('foo'))->toBe('bar'); expect(cache('def'))->toBe(null); cache(['def' => 'xxx']); expect(cache('def'))->toBe('xxx'); tenancy()->initialize($tenant1); expect(cache('def'))->toBe('ghi'); })->with([ ['redis', [CacheTagsBootstrapper::class]], ['redis', [CacheTenancyBootstrapper::class]], ['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]], ]); test('global cache facade is not persistent', function () { $oldId = spl_object_id(GlobalCache::getFacadeRoot()); $_ = new class {}; expect(spl_object_id(GlobalCache::getFacadeRoot()))->not()->toBe($oldId); }); test('global cache is always central', function (string $store, array $bootstrappers, string $initialCentralCall) { config([ 'cache.default' => $store, 'tenancy.bootstrappers' => $bootstrappers, ]); if ($store === 'database') { withTenantDatabases(true); } // This tells us which "accessor" for the global cache should be instantiated first, before we go // into the tenant context. We make sure to not touch the other one here. This tests that whether // a particular accessor is used "early" makes no difference in the later behavior. if ($initialCentralCall === 'helper') { if ($store === 'database') expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); global_cache()->put('central-helper', true); } else if ($initialCentralCall === 'facade') { if ($store === 'database') expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); GlobalCache::put('central-facade', true); } else if ($initialCentralCall === 'both') { if ($store === 'database') expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); global_cache()->put('central-helper', true); if ($store === 'database') expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); GlobalCache::put('central-facade', true); } $tenant = Tenant::create(); $tenant->enter(); // Here we use both the helper and the facade to ensure the value is accessible via either one if ($initialCentralCall === 'helper') { if ($store === 'database') expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); if ($store === 'database') expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); expect(global_cache('central-helper'))->toBe(true); expect(GlobalCache::get('central-helper'))->toBe(true); } else if ($initialCentralCall === 'facade') { if ($store === 'database') expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); if ($store === 'database') expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); expect(global_cache('central-facade'))->toBe(true); expect(GlobalCache::get('central-facade'))->toBe(true); } else if ($initialCentralCall === 'both') { if ($store === 'database') expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); if ($store === 'database') expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); expect(global_cache('central-helper'))->toBe(true); expect(GlobalCache::get('central-helper'))->toBe(true); expect(global_cache('central-facade'))->toBe(true); expect(GlobalCache::get('central-facade'))->toBe(true); } global_cache()->put('tenant-helper', true); GlobalCache::put('tenant-facade', true); tenancy()->end(); if ($store === 'database') expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); if ($store === 'database') expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central'); expect(global_cache('tenant-helper'))->toBe(true); expect(GlobalCache::get('tenant-helper'))->toBe(true); expect(global_cache('tenant-facade'))->toBe(true); expect(GlobalCache::get('tenant-facade'))->toBe(true); if ($initialCentralCall === 'helper') { expect(GlobalCache::get('central-helper'))->toBe(true); } else if ($initialCentralCall === 'facade') { expect(global_cache('central-facade'))->toBe(true); } else if ($initialCentralCall === 'both') { expect(global_cache('central-helper'))->toBe(true); expect(GlobalCache::get('central-helper'))->toBe(true); expect(global_cache('central-facade'))->toBe(true); expect(GlobalCache::get('central-facade'))->toBe(true); } })->with([ ['redis', [CacheTagsBootstrapper::class]], ['redis', [CacheTenancyBootstrapper::class]], ['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]], ])->with([ 'helper', 'facade', 'both', 'none', ]); test('the global_cache helper supports the same syntax as the cache helper', function (string $store, array $bootstrappers) { config([ 'cache.default' => $store, 'tenancy.bootstrappers' => $bootstrappers, ]); if ($store === 'database') withTenantDatabases(true); $tenant = Tenant::create(); $tenant->enter(); // different stores expect(cache()->store()->getStore() !== GlobalCache::store()->getStore())->toBeTrue(); if ($store === 'redis') { // same underlying connection. the prefix is set ON THE STORE expect(cache()->store()->getStore()->connection() === global_cache()->store()->getStore()->connection())->toBeTrue(); } else { // different connections expect(cache()->store()->getStore()->getConnection()->getName())->toBe('tenant'); expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central'); } expect(cache('foo'))->toBe(null); // tenant cache is empty global_cache(['foo' => 'bar']); expect(global_cache('foo'))->toBe('bar'); global_cache()->set('foo', 'baz'); expect(global_cache()->get('foo'))->toBe('baz'); expect(cache('foo'))->toBe(null); // tenant cache is not affected })->with([ ['redis', [CacheTagsBootstrapper::class]], ['redis', [CacheTenancyBootstrapper::class]], ['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]], ]);