From 898d6c5d3b1c7151a44616d438b313fd8ac16dcf Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 17 Nov 2022 16:21:07 +0500 Subject: [PATCH 001/155] cache prefix --- .../PrefixCacheTenancyBootstrapper.php | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/Bootstrappers/PrefixCacheTenancyBootstrapper.php diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php new file mode 100644 index 000000000..a5144176a --- /dev/null +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -0,0 +1,64 @@ +originalPrefix = config('cache.prefix'); + + $this->storeName ??= config('cache.default'); + + $this->cacheKeyBase ??= 'tenant_id_'; + } + + public function bootstrap(Tenant $tenant): void + { + $this->setCachePrefix($this->cacheKeyBase . $tenant->id); + } + + public function revert(): void + { + $this->setCachePrefix($this->originalPrefix); + } + + protected function setCachePrefix(string $prefix): void + { + config()->set('cache.prefix', $prefix); + + app('cache')->forgetDriver($this->storeName); + +// cache()->purge(); +// +// app('cache')->forgetDriver($this->storeName); +// +// // This is important because the `CacheManager` will have the `$app['config']` array cached +// // with old prefixes on the `cache` instance. Simply calling `forgetDriver` only removes +// // the `$store` but doesn't update the `$app['config']`. +// app()->forgetInstance('cache'); +// +// //This is important because the Cache Repository is using an old version of the CacheManager +// app()->forgetInstance('cache.store'); +// +// // Forget the cache repository in the container +// app()->forgetInstance(Repository::class); +// +// Cache::clearResolvedInstances(); + } +} From d6da626f7371b4aa10fab38c61fc6ea2c6065485 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Mon, 21 Nov 2022 17:53:21 +0500 Subject: [PATCH 002/155] prefix cache bootstrapper and tests --- assets/config.php | 1 + .../PrefixCacheTenancyBootstrapper.php | 56 ++++++++----------- tests/BootstrapperTest.php | 12 ++-- tests/TestCase.php | 3 +- 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/assets/config.php b/assets/config.php index 3778e1076..2358f5a77 100644 --- a/assets/config.php +++ b/assets/config.php @@ -102,6 +102,7 @@ Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper::class, + // Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper::class, // prefix cache keys // Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper::class, // Note: phpredis is needed ], diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index a5144176a..88feffff9 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -4,38 +4,30 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\CacheManager; use Illuminate\Cache\Repository; -use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Cache; -use Stancl\Tenancy\CacheManager as TenantCacheManager; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { - protected ?string $originalPrefix; - - public function __construct( - protected Application $app, - protected ?string $storeName = null, - protected ?string $cacheKeyBase = null, - ) { - $this->originalPrefix = config('cache.prefix'); - - $this->storeName ??= config('cache.default'); - - $this->cacheKeyBase ??= 'tenant_id_'; - } + protected null|string $originalPrefix = null; + protected string $storeName; public function bootstrap(Tenant $tenant): void { - $this->setCachePrefix($this->cacheKeyBase . $tenant->id); + $this->originalPrefix = config('cache.prefix'); + $this->storeName = config('cache.default'); + + $this->setCachePrefix('tenant_id_' . $tenant->id); } public function revert(): void { - $this->setCachePrefix($this->originalPrefix); + if ($this->originalPrefix) { + $this->setCachePrefix($this->originalPrefix); + $this->originalPrefix = null; + } } protected function setCachePrefix(string $prefix): void @@ -44,21 +36,17 @@ protected function setCachePrefix(string $prefix): void app('cache')->forgetDriver($this->storeName); -// cache()->purge(); -// -// app('cache')->forgetDriver($this->storeName); -// -// // This is important because the `CacheManager` will have the `$app['config']` array cached -// // with old prefixes on the `cache` instance. Simply calling `forgetDriver` only removes -// // the `$store` but doesn't update the `$app['config']`. -// app()->forgetInstance('cache'); -// -// //This is important because the Cache Repository is using an old version of the CacheManager -// app()->forgetInstance('cache.store'); -// -// // Forget the cache repository in the container -// app()->forgetInstance(Repository::class); -// -// Cache::clearResolvedInstances(); + // This is important because the `CacheManager` will have the `$app['config']` array cached + // with old prefixes on the `cache` instance. Simply calling `forgetDriver` only removes + // the `$store` but doesn't update the `$app['config']`. + app()->forgetInstance('cache'); + + //This is important because the Cache Repository is using an old version of the CacheManager + app()->forgetInstance('cache.store'); + + // Forget the cache repository in the container + app()->forgetInstance(Repository::class); + + Cache::clearResolvedInstances(); } } diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index ba4ea41ac..8a1d0bff5 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\DB; use Stancl\JobPipeline\JobPipeline; use Illuminate\Support\Facades\File; +use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Event; @@ -73,11 +74,9 @@ expect(DB::table('users')->first()->name)->toBe('Foo'); }); -test('cache data is separated', function () { +test('cache data is separated', function (string $bootstrapper) { config([ - 'tenancy.bootstrappers' => [ - CacheTenancyBootstrapper::class, - ], + 'tenancy.bootstrappers' => [$bootstrapper], 'cache.default' => 'redis', ]); @@ -112,7 +111,10 @@ // Asset central is still the same expect(Cache::get('foo'))->toBe('central'); -}); +})->with([ + 'CacheTenancyBootstrapper' => CacheTenancyBootstrapper::class, + 'PrefixCacheTenancyBootstrapper' => PrefixCacheTenancyBootstrapper::class, +]); test('redis data is separated', function () { config(['tenancy.bootstrappers' => [ diff --git a/tests/TestCase.php b/tests/TestCase.php index 7b9deea0e..0dde576de 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -8,7 +8,7 @@ use Illuminate\Foundation\Application; use Illuminate\Support\Facades\Redis; use PDO; -use Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper; +use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper; use Stancl\Tenancy\Facades\GlobalCache; use Stancl\Tenancy\Facades\Tenancy; @@ -113,6 +113,7 @@ protected function getEnvironmentSetUp($app) ]); $app->singleton(RedisTenancyBootstrapper::class); // todo (Samuel) use proper approach eg config for singleton registration + $app->singleton(PrefixCacheTenancyBootstrapper::class); // todo (Samuel) use proper approach eg config for singleton registration } protected function getPackageProviders($app) From c59a51449045fff57233e89e93f7f65405cdd17b Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 11:21:35 +0500 Subject: [PATCH 003/155] remove comment --- assets/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/config.php b/assets/config.php index 2358f5a77..b76a666ab 100644 --- a/assets/config.php +++ b/assets/config.php @@ -102,7 +102,7 @@ Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper::class, - // Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper::class, // prefix cache keys + // Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper::class, // Note: phpredis is needed ], From 90c54ac7331703a54e17942664f15bfefe9e9a3b Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 11:28:27 +0500 Subject: [PATCH 004/155] DI app --- .../PrefixCacheTenancyBootstrapper.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 88feffff9..d409cce8a 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -5,6 +5,7 @@ namespace Stancl\Tenancy\Bootstrappers; use Illuminate\Cache\Repository; +use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; @@ -14,10 +15,15 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper protected null|string $originalPrefix = null; protected string $storeName; + public function __construct( + protected Application $app + ) { + } + public function bootstrap(Tenant $tenant): void { - $this->originalPrefix = config('cache.prefix'); - $this->storeName = config('cache.default'); + $this->originalPrefix = $this->app['config']['cache.prefix']; + $this->storeName = $this->app['config']['cache.default']; $this->setCachePrefix('tenant_id_' . $tenant->id); } @@ -32,20 +38,20 @@ public function revert(): void protected function setCachePrefix(string $prefix): void { - config()->set('cache.prefix', $prefix); + $this->app['config']['cache.prefix'] = $prefix; - app('cache')->forgetDriver($this->storeName); + $this->app['cache']->forgetDriver($this->storeName); // This is important because the `CacheManager` will have the `$app['config']` array cached // with old prefixes on the `cache` instance. Simply calling `forgetDriver` only removes // the `$store` but doesn't update the `$app['config']`. - app()->forgetInstance('cache'); + $this->app->forgetInstance('cache'); //This is important because the Cache Repository is using an old version of the CacheManager - app()->forgetInstance('cache.store'); + $this->app->forgetInstance('cache.store'); // Forget the cache repository in the container - app()->forgetInstance(Repository::class); + $this->app->forgetInstance(Repository::class); Cache::clearResolvedInstances(); } From e5658fa300d36ef825deac5db8c9ed1538c98ef1 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 11:32:23 +0500 Subject: [PATCH 005/155] cache prefix base from config --- assets/config.php | 1 + src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/config.php b/assets/config.php index b76a666ab..609a66f17 100644 --- a/assets/config.php +++ b/assets/config.php @@ -188,6 +188,7 @@ */ 'cache' => [ 'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call. + 'prefix_base' => 'tenant_' // this prefix_base, followed by the tenant_id, will form a cache prefix that will be applied on each cache call ], /** diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index d409cce8a..de4bf1af0 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -25,7 +25,7 @@ public function bootstrap(Tenant $tenant): void $this->originalPrefix = $this->app['config']['cache.prefix']; $this->storeName = $this->app['config']['cache.default']; - $this->setCachePrefix('tenant_id_' . $tenant->id); + $this->setCachePrefix($this->app['config']['tenancy.cache.prefix_base'] . $tenant->id); } public function revert(): void From c4f9324aa85d79e94212ddb48fea626784a0653e Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 13:54:01 +0500 Subject: [PATCH 006/155] Create PrefixCacheBootstrapperTest.php --- tests/PrefixCacheBootstrapperTest.php | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/PrefixCacheBootstrapperTest.php diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php new file mode 100644 index 000000000..388cb1e01 --- /dev/null +++ b/tests/PrefixCacheBootstrapperTest.php @@ -0,0 +1,74 @@ + [PrefixCacheTenancyBootstrapper::class], + 'cache.default' => 'redis', + ]); + + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); +}); + +test('cache prefix is separate for each tenant', function () { + $originalPrefix = config('cache.prefix') . ':'; + + expect($originalPrefix) + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); + + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); + + $tenantOnePrefix = 'tenant_' . $tenant1->id . ':'; + + tenancy()->initialize($tenant1); + expect($tenantOnePrefix) + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); + + $tenantTwoPrefix = 'tenant_' . $tenant2->id . ':'; + + tenancy()->initialize($tenant2); + expect($tenantTwoPrefix) + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); +}); + +test('cache is persisted when reidentification is used', function () { + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); + tenancy()->initialize($tenant1); + + cache(['foo' => 'bar'], 10); + expect(cache('foo'))->toBe('bar'); + + tenancy()->initialize($tenant2); + tenancy()->end(); + + tenancy()->initialize($tenant1); + expect(cache('foo'))->toBe('bar'); +}); + +test('prefix separate cache well enough', function () { + $tenant1 = Tenant::create(); + tenancy()->initialize($tenant1); + + cache()->put('foo', 'bar', 1); + expect(cache()->get('foo'))->toBe('bar'); + + $tenant2 = Tenant::create(); + tenancy()->initialize($tenant2); + + pest()->assertNotSame('bar', cache()->get('foo')); + + cache()->put('foo', 'xyz', 1); + expect(cache()->get('foo'))->toBe('xyz'); +}); + From e970c160d06ddf8d68df3bc2a11442710a2df035 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 14:00:35 +0500 Subject: [PATCH 007/155] remove `null` check --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index de4bf1af0..b1d35a004 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -30,10 +30,8 @@ public function bootstrap(Tenant $tenant): void public function revert(): void { - if ($this->originalPrefix) { - $this->setCachePrefix($this->originalPrefix); - $this->originalPrefix = null; - } + $this->setCachePrefix($this->originalPrefix); + $this->originalPrefix = null; } protected function setCachePrefix(string $prefix): void From c5f7de4b0eb27d0bf3a9877e7db5a6c22bcc27f6 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 14:09:59 +0500 Subject: [PATCH 008/155] fix phpstan error --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index b1d35a004..995de0ba9 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -34,7 +34,7 @@ public function revert(): void $this->originalPrefix = null; } - protected function setCachePrefix(string $prefix): void + protected function setCachePrefix(null|string $prefix): void { $this->app['config']['cache.prefix'] = $prefix; From 2302571f6ac80d8a7f51aa8557e5e5129a8425b7 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 22 Nov 2022 14:13:10 +0500 Subject: [PATCH 009/155] Update PrefixCacheTenancyBootstrapper.php --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 995de0ba9..96679dc91 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -40,17 +40,9 @@ protected function setCachePrefix(null|string $prefix): void $this->app['cache']->forgetDriver($this->storeName); - // This is important because the `CacheManager` will have the `$app['config']` array cached - // with old prefixes on the `cache` instance. Simply calling `forgetDriver` only removes - // the `$store` but doesn't update the `$app['config']`. - $this->app->forgetInstance('cache'); - //This is important because the Cache Repository is using an old version of the CacheManager $this->app->forgetInstance('cache.store'); - // Forget the cache repository in the container - $this->app->forgetInstance(Repository::class); - Cache::clearResolvedInstances(); } } From 2c0a8f4ef950c941be14327f8dac3cb10a11cee7 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 23 Nov 2022 12:59:51 +0500 Subject: [PATCH 010/155] Update PrefixCacheBootstrapperTest.php --- tests/PrefixCacheBootstrapperTest.php | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 388cb1e01..bdd54f446 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -4,8 +4,10 @@ use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; +use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\RevertToCentralContext; beforeEach(function () { config([ @@ -14,6 +16,7 @@ ]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); + Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); test('cache prefix is separate for each tenant', function () { @@ -72,3 +75,31 @@ expect(cache()->get('foo'))->toBe('xyz'); }); +test('central cache is not broke', function () { + cache()->put('key', 'central'); + + $tenant1 = Tenant::create(); + tenancy()->initialize($tenant1); + + cache()->put('key', 'tenant'); + + expect(cache()->get('key'))->toBe('tenant'); + + tenancy()->end(); + + expect(cache()->get('key'))->toBe('central'); +}); + +test('cache base prefix can be customized', function () { + config([ + 'tenancy.cache.prefix_base' => 'custom_' + ]); + + $tenant1 = Tenant::create(); + tenancy()->initialize($tenant1); + + expect('custom_' . $tenant1->id . ':') + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); +}); + From 1e44ef214d01a05952984ab07cd7e274311399ef Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 24 Nov 2022 11:51:43 +0500 Subject: [PATCH 011/155] add comments --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 96679dc91..f3dd204a3 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -40,9 +40,17 @@ protected function setCachePrefix(null|string $prefix): void $this->app['cache']->forgetDriver($this->storeName); - //This is important because the Cache Repository is using an old version of the CacheManager + // The CacheManager will have the $app['config'] array cached with old prefixes on the 'cache' instance + $this->app->forgetInstance('cache'); + + // The Cache Repository is using an old version of the CacheManager so we need to forget it $this->app->forgetInstance('cache.store'); + // Forget the cache repository in the container + $this->app->forgetInstance(Repository::class); + + // It is needed when a call to the facade has been made before bootstrapping tenancy + // The facade has its own cache, separate from the container Cache::clearResolvedInstances(); } } From e550c7dcdda58959f08a1a25a36452b8a46747eb Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 24 Nov 2022 11:57:14 +0500 Subject: [PATCH 012/155] Update PrefixCacheTenancyBootstrapper.php --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index f3dd204a3..29407706a 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -41,12 +41,13 @@ protected function setCachePrefix(null|string $prefix): void $this->app['cache']->forgetDriver($this->storeName); // The CacheManager will have the $app['config'] array cached with old prefixes on the 'cache' instance + // This call will forget the 'cache' instance $this->app->forgetInstance('cache'); // The Cache Repository is using an old version of the CacheManager so we need to forget it $this->app->forgetInstance('cache.store'); - // Forget the cache repository in the container + // Forget the cache repository in the container to cover some edge-cases $this->app->forgetInstance(Repository::class); // It is needed when a call to the facade has been made before bootstrapping tenancy From 3cff2e3ba9a8b1df956da3a17c101358f8a7ba8d Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 24 Nov 2022 12:05:19 +0500 Subject: [PATCH 013/155] Update PrefixCacheBootstrapperTest.php --- tests/PrefixCacheBootstrapperTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index bdd54f446..ee8577cc2 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -86,8 +86,10 @@ expect(cache()->get('key'))->toBe('tenant'); tenancy()->end(); + cache()->put('key2', 'central-two'); expect(cache()->get('key'))->toBe('central'); + expect(cache()->get('key2'))->toBe('central-two'); }); test('cache base prefix can be customized', function () { From 41a6f5b074d92a30b76c2cd233a100be12d5228e Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Mon, 28 Nov 2022 12:08:56 +0500 Subject: [PATCH 014/155] Update config.php --- assets/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/config.php b/assets/config.php index 609a66f17..999bdc90e 100644 --- a/assets/config.php +++ b/assets/config.php @@ -188,7 +188,7 @@ */ 'cache' => [ 'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call. - 'prefix_base' => 'tenant_' // this prefix_base, followed by the tenant_id, will form a cache prefix that will be applied on each cache call + 'prefix_base' => 'tenant_', // This prefix_base, followed by the tenant_id, will form a cache prefix that will be used for every cache key. ], /** From eef58bd93da7225887b48186929f4a6dfec1532a Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Mon, 28 Nov 2022 12:50:14 +0500 Subject: [PATCH 015/155] test names grammar --- tests/PrefixCacheBootstrapperTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index ee8577cc2..1fee7e2a2 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -75,7 +75,7 @@ expect(cache()->get('foo'))->toBe('xyz'); }); -test('central cache is not broke', function () { +test('central cache is persisted', function () { cache()->put('key', 'central'); $tenant1 = Tenant::create(); @@ -92,7 +92,7 @@ expect(cache()->get('key2'))->toBe('central-two'); }); -test('cache base prefix can be customized', function () { +test('cache base prefix is customizable', function () { config([ 'tenancy.cache.prefix_base' => 'custom_' ]); From d6b4d9b7a7a4383b54e3554e4eec8ca3aee031c6 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Mon, 28 Nov 2022 15:09:39 +0500 Subject: [PATCH 016/155] user `getTenantKey` method --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 29407706a..dc9989b41 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -25,7 +25,7 @@ public function bootstrap(Tenant $tenant): void $this->originalPrefix = $this->app['config']['cache.prefix']; $this->storeName = $this->app['config']['cache.default']; - $this->setCachePrefix($this->app['config']['tenancy.cache.prefix_base'] . $tenant->id); + $this->setCachePrefix($this->app['config']['tenancy.cache.prefix_base'] . $tenant->getTenantKey()); } public function revert(): void From b920a2905ea6c0d3bab19c393e87fca0ab930323 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 29 Nov 2022 17:13:04 +0500 Subject: [PATCH 017/155] assert tenants' data is accessible using the prefix from the central context --- tests/PrefixCacheBootstrapperTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 1fee7e2a2..1e714e58a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -21,6 +21,7 @@ test('cache prefix is separate for each tenant', function () { $originalPrefix = config('cache.prefix') . ':'; + cache()->set('key', 'original-value'); expect($originalPrefix) ->toBe(app('cache')->getPrefix()) @@ -32,6 +33,8 @@ $tenantOnePrefix = 'tenant_' . $tenant1->id . ':'; tenancy()->initialize($tenant1); + cache()->set('key', 'tenantone-value'); + expect($tenantOnePrefix) ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); @@ -39,9 +42,18 @@ $tenantTwoPrefix = 'tenant_' . $tenant2->id . ':'; tenancy()->initialize($tenant2); + cache()->set('key', 'tenanttwo-value'); + expect($tenantTwoPrefix) ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); + + // Assert tenants' data is accessible using the prefix from the central context + tenancy()->end(); + config(['cache.prefix' => null]); // stop prefixing cache keys in central + + expect(cache($tenantOnePrefix . 'key'))->toBe('tenantone-value'); + expect(cache($tenantTwoPrefix . 'key'))->toBe('tenanttwo-value'); }); test('cache is persisted when reidentification is used', function () { From 2901d0190c974a065c65a671c6a891fd1b5b1b9f Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Tue, 29 Nov 2022 18:11:10 +0500 Subject: [PATCH 018/155] remove unused line --- tests/PrefixCacheBootstrapperTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 1e714e58a..603cba432 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -21,7 +21,6 @@ test('cache prefix is separate for each tenant', function () { $originalPrefix = config('cache.prefix') . ':'; - cache()->set('key', 'original-value'); expect($originalPrefix) ->toBe(app('cache')->getPrefix()) From 387a10b918386876d937637405fd4e52438212ad Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 30 Nov 2022 10:22:01 +0500 Subject: [PATCH 019/155] use proper DI --- .../PrefixCacheTenancyBootstrapper.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index dc9989b41..3db62c33e 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -4,7 +4,8 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\Repository; +use Illuminate\Cache\Repository as CacheRepository; +use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; @@ -16,16 +17,17 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper protected string $storeName; public function __construct( - protected Application $app + protected Application $app, + protected Repository $config, ) { } public function bootstrap(Tenant $tenant): void { - $this->originalPrefix = $this->app['config']['cache.prefix']; - $this->storeName = $this->app['config']['cache.default']; + $this->originalPrefix = $this->config->get('cache.prefix'); + $this->storeName = $this->config->get('cache.default'); - $this->setCachePrefix($this->app['config']['tenancy.cache.prefix_base'] . $tenant->getTenantKey()); + $this->setCachePrefix($this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); } public function revert(): void @@ -36,7 +38,7 @@ public function revert(): void protected function setCachePrefix(null|string $prefix): void { - $this->app['config']['cache.prefix'] = $prefix; + $this->config->set('cache.prefix', $prefix); $this->app['cache']->forgetDriver($this->storeName); @@ -48,7 +50,7 @@ protected function setCachePrefix(null|string $prefix): void $this->app->forgetInstance('cache.store'); // Forget the cache repository in the container to cover some edge-cases - $this->app->forgetInstance(Repository::class); + $this->app->forgetInstance(CacheRepository::class); // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container From 169a7f7cc9a3ce090d01cea563674c4a5632daef Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 30 Nov 2022 13:25:07 +0500 Subject: [PATCH 020/155] build prefix using original prefix --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 3db62c33e..de4346a1c 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -27,7 +27,7 @@ public function bootstrap(Tenant $tenant): void $this->originalPrefix = $this->config->get('cache.prefix'); $this->storeName = $this->config->get('cache.default'); - $this->setCachePrefix($this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); + $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); } public function revert(): void From 3407faf8119ced1b923a40a84c29c67b23b70aec Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 30 Nov 2022 13:25:39 +0500 Subject: [PATCH 021/155] fix prefix test according to prefix changes --- tests/PrefixCacheBootstrapperTest.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 603cba432..e03c3dfe7 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -20,39 +20,40 @@ }); test('cache prefix is separate for each tenant', function () { - $originalPrefix = config('cache.prefix') . ':'; + $originalPrefix = config('cache.prefix'); + $prefixBase = config('tenancy.cache.prefix_base'); - expect($originalPrefix) + expect($originalPrefix . ':') // cache manager postfix ':' to prefix ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); - $tenantOnePrefix = 'tenant_' . $tenant1->id . ':'; + $tenantOnePrefix = $originalPrefix . $prefixBase . $tenant1->getTenantKey(); tenancy()->initialize($tenant1); cache()->set('key', 'tenantone-value'); - expect($tenantOnePrefix) + expect($tenantOnePrefix . ':') ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); - $tenantTwoPrefix = 'tenant_' . $tenant2->id . ':'; + $tenantTwoPrefix = $originalPrefix . $prefixBase . $tenant2->getTenantKey(); tenancy()->initialize($tenant2); cache()->set('key', 'tenanttwo-value'); - expect($tenantTwoPrefix) + expect($tenantTwoPrefix . ':') ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); // Assert tenants' data is accessible using the prefix from the central context tenancy()->end(); - config(['cache.prefix' => null]); // stop prefixing cache keys in central + config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually - expect(cache($tenantOnePrefix . 'key'))->toBe('tenantone-value'); - expect(cache($tenantTwoPrefix . 'key'))->toBe('tenanttwo-value'); + expect(cache($tenantOnePrefix . ':key'))->toBe('tenantone-value'); + expect(cache($tenantTwoPrefix . ':key'))->toBe('tenanttwo-value'); }); test('cache is persisted when reidentification is used', function () { From 70ee83b3b73e8a62f7fde75d01bcfe8a3d9d11be Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 30 Nov 2022 13:27:15 +0500 Subject: [PATCH 022/155] fix test --- tests/PrefixCacheBootstrapperTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index e03c3dfe7..09d7f6fb1 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -105,14 +105,17 @@ }); test('cache base prefix is customizable', function () { + $originalPrefix = config('cache.prefix'); + $prefixBase = 'custom_'; + config([ - 'tenancy.cache.prefix_base' => 'custom_' + 'tenancy.cache.prefix_base' => $prefixBase ]); $tenant1 = Tenant::create(); tenancy()->initialize($tenant1); - expect('custom_' . $tenant1->id . ':') + expect($originalPrefix . $prefixBase . $tenant1->getTenantKey() . ':') ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); }); From 222686ec1d6772048ded1b6de8e73fac96347bbf Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 1 Dec 2022 13:53:45 +0500 Subject: [PATCH 023/155] CacheManager dependency injection test --- .../PrefixCacheTenancyBootstrapper.php | 2 +- tests/Etc/CacheAction.php | 24 +++++++++++++++++++ tests/PrefixCacheBootstrapperTest.php | 17 +++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/Etc/CacheAction.php diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index de4346a1c..cb14fc052 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -40,7 +40,7 @@ protected function setCachePrefix(null|string $prefix): void { $this->config->set('cache.prefix', $prefix); - $this->app['cache']->forgetDriver($this->storeName); + // $this->app['cache']->forgetDriver($this->storeName); // The CacheManager will have the $app['config'] array cached with old prefixes on the 'cache' instance // This call will forget the 'cache' instance diff --git a/tests/Etc/CacheAction.php b/tests/Etc/CacheAction.php new file mode 100644 index 000000000..01da11e8a --- /dev/null +++ b/tests/Etc/CacheAction.php @@ -0,0 +1,24 @@ +initialized) { + $this->cache->put('key', tenant()->getTenantKey()); + } else { + $this->cache->put('key', 'central-value'); + } + } +} diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 09d7f6fb1..13eeeaf9a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -8,6 +8,7 @@ use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; +use Stancl\Tenancy\Tests\Etc\CacheAction; beforeEach(function () { config([ @@ -120,3 +121,19 @@ ->toBe(app('cache.store')->getPrefix()); }); +test('prefix separate cache well enough using CacheManager dependency injection', function () { + app()->make(CacheAction::class)->handle(); + + expect(cache('key'))->toBe('central-value'); + + $tenant = Tenant::create(); + tenancy()->initialize($tenant); + + expect(cache('key'))->toBeNull(); + app()->make(CacheAction::class)->handle(); + expect(cache('key'))->toBe($tenant->getTenantKey()); + + tenancy()->end(); + + expect(cache('key'))->toBe('central-value'); +}); From 6c955acd137ddc4cb6d90aa0d95abfed042b7006 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 1 Dec 2022 14:58:13 +0500 Subject: [PATCH 024/155] CacheService class as singleton --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- tests/PrefixCacheBootstrapperTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index cb14fc052..de4346a1c 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -40,7 +40,7 @@ protected function setCachePrefix(null|string $prefix): void { $this->config->set('cache.prefix', $prefix); - // $this->app['cache']->forgetDriver($this->storeName); + $this->app['cache']->forgetDriver($this->storeName); // The CacheManager will have the $app['config'] array cached with old prefixes on the 'cache' instance // This call will forget the 'cache' instance diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 13eeeaf9a..4c0c75286 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -122,6 +122,8 @@ }); test('prefix separate cache well enough using CacheManager dependency injection', function () { + $this->app->singleton(CacheAction::class); + app()->make(CacheAction::class)->handle(); expect(cache('key'))->toBe('central-value'); From 2f9130999083e3379391ba01489ffeb9a7d4cbf8 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Thu, 1 Dec 2022 14:59:13 +0500 Subject: [PATCH 025/155] introduce second tenant in test --- tests/PrefixCacheBootstrapperTest.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 4c0c75286..3c342f36f 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -128,12 +128,19 @@ expect(cache('key'))->toBe('central-value'); - $tenant = Tenant::create(); - tenancy()->initialize($tenant); + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); + tenancy()->initialize($tenant1); + + expect(cache('key'))->toBeNull(); + app()->make(CacheAction::class)->handle(); + expect(cache('key'))->toBe($tenant1->getTenantKey()); + + tenancy()->initialize($tenant2); expect(cache('key'))->toBeNull(); app()->make(CacheAction::class)->handle(); - expect(cache('key'))->toBe($tenant->getTenantKey()); + expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); From 19255fd98fc325550d381dd84c30d0fa38637bf6 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 7 Dec 2022 18:24:55 +0500 Subject: [PATCH 026/155] use Repository in service class DI --- tests/Etc/CacheAction.php | 4 ++-- tests/PrefixCacheBootstrapperTest.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Etc/CacheAction.php b/tests/Etc/CacheAction.php index 01da11e8a..825b8772b 100644 --- a/tests/Etc/CacheAction.php +++ b/tests/Etc/CacheAction.php @@ -4,12 +4,12 @@ namespace Stancl\Tenancy\Tests\Etc; -use Illuminate\Cache\CacheManager; +use Illuminate\Cache\Repository; class CacheAction { public function __construct( - protected CacheManager $cache + protected Repository $cache ){ } diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 3c342f36f..3a161714b 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -12,7 +12,9 @@ beforeEach(function () { config([ - 'tenancy.bootstrappers' => [PrefixCacheTenancyBootstrapper::class], + 'tenancy.bootstrappers' => [ + PrefixCacheTenancyBootstrapper::class + ], 'cache.default' => 'redis', ]); From 974414a12d9f828bb37a1a07da926ade8f284ef7 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 7 Dec 2022 18:26:10 +0500 Subject: [PATCH 027/155] Update CacheAction.php --- tests/Etc/CacheAction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Etc/CacheAction.php b/tests/Etc/CacheAction.php index 825b8772b..d72d7f32d 100644 --- a/tests/Etc/CacheAction.php +++ b/tests/Etc/CacheAction.php @@ -6,7 +6,7 @@ use Illuminate\Cache\Repository; -class CacheAction +class CacheAction // todo renamed to CacheService { public function __construct( protected Repository $cache From 4c33df1aa5fb596c4fc35dddad86e2e1970302ca Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 7 Dec 2022 14:48:52 +0100 Subject: [PATCH 028/155] Rename CacheAction to CacheService --- tests/Etc/{CacheAction.php => CacheService.php} | 2 +- tests/PrefixCacheBootstrapperTest.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) rename tests/Etc/{CacheAction.php => CacheService.php} (89%) diff --git a/tests/Etc/CacheAction.php b/tests/Etc/CacheService.php similarity index 89% rename from tests/Etc/CacheAction.php rename to tests/Etc/CacheService.php index d72d7f32d..8e5d17d32 100644 --- a/tests/Etc/CacheAction.php +++ b/tests/Etc/CacheService.php @@ -6,7 +6,7 @@ use Illuminate\Cache\Repository; -class CacheAction // todo renamed to CacheService +class CacheService { public function __construct( protected Repository $cache diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 3a161714b..bf977e822 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -8,7 +8,7 @@ use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Tests\Etc\CacheAction; +use Stancl\Tenancy\Tests\Etc\CacheService; beforeEach(function () { config([ @@ -124,9 +124,9 @@ }); test('prefix separate cache well enough using CacheManager dependency injection', function () { - $this->app->singleton(CacheAction::class); + $this->app->singleton(CacheService::class); - app()->make(CacheAction::class)->handle(); + app()->make(CacheService::class)->handle(); expect(cache('key'))->toBe('central-value'); @@ -135,13 +135,13 @@ tenancy()->initialize($tenant1); expect(cache('key'))->toBeNull(); - app()->make(CacheAction::class)->handle(); + app()->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache('key'))->toBeNull(); - app()->make(CacheAction::class)->handle(); + app()->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); From 825a565fa203e3dc245dd9aca5a0223168424685 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 8 Dec 2022 16:24:54 +0100 Subject: [PATCH 029/155] Update prefix bootstrapper and test (`setStore()` in CacheManager and Repository needed) --- .../PrefixCacheTenancyBootstrapper.php | 36 +++++++++++-------- tests/PrefixCacheBootstrapperTest.php | 4 ++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index de4346a1c..36433cd7f 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -4,21 +4,20 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\Repository as CacheRepository; +use Illuminate\Cache\CacheManager; use Illuminate\Contracts\Config\Repository; -use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { - protected null|string $originalPrefix = null; + protected string|null $originalPrefix = null; protected string $storeName; public function __construct( - protected Application $app, protected Repository $config, + protected CacheManager $cacheManager, ) { } @@ -36,21 +35,30 @@ public function revert(): void $this->originalPrefix = null; } - protected function setCachePrefix(null|string $prefix): void + protected function syncStore(): void { - $this->config->set('cache.prefix', $prefix); + $originalRepository = $this->cacheManager->driver($this->storeName); + + // Delete the repository from CacheManager's $stores cache + // So that it's forced to resolve the repository again on the next attempt to get it + $this->cacheManager->forgetDriver($this->storeName); + + // Let CacheManager create a repository with a fresh store + // To get a new store that uses the current value of `config('cache.prefix')` as the prefix + $newRepository = $this->cacheManager->driver($this->storeName); - $this->app['cache']->forgetDriver($this->storeName); + // Give the new store to the old repository + $originalRepository->setStore($newRepository->getStore()); - // The CacheManager will have the $app['config'] array cached with old prefixes on the 'cache' instance - // This call will forget the 'cache' instance - $this->app->forgetInstance('cache'); + // Overwrite the new repository with the modified old one + $this->cacheManager->setStore($this->storeName, $originalRepository); + } - // The Cache Repository is using an old version of the CacheManager so we need to forget it - $this->app->forgetInstance('cache.store'); + protected function setCachePrefix(string|null $prefix): void + { + $this->config->set('cache.prefix', $prefix); - // Forget the cache repository in the container to cover some edge-cases - $this->app->forgetInstance(CacheRepository::class); + $this->syncStore(); // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index bf977e822..5db60aaec 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -26,7 +26,7 @@ $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); - expect($originalPrefix . ':') // cache manager postfix ':' to prefix + expect($originalPrefix . ':') // RedisStore suffixes prefix with ':' ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); @@ -53,7 +53,9 @@ // Assert tenants' data is accessible using the prefix from the central context tenancy()->end(); + config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually + app('cache')->forgetDriver(config('cache.default')); expect(cache($tenantOnePrefix . ':key'))->toBe('tenantone-value'); expect(cache($tenantTwoPrefix . ':key'))->toBe('tenanttwo-value'); From 50d46139f675d6da3e724c97e1ff797e392a7f31 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 9 Dec 2022 12:21:37 +0100 Subject: [PATCH 030/155] Add macro --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 36433cd7f..f8b59946e 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -5,10 +5,10 @@ namespace Stancl\Tenancy\Bootstrappers; use Illuminate\Cache\CacheManager; -use Illuminate\Contracts\Config\Repository; +use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Support\Facades\Cache; +use Illuminate\Contracts\Config\Repository; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Contracts\Tenant; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { @@ -23,6 +23,10 @@ public function __construct( public function bootstrap(Tenant $tenant): void { + Cache::macro('setStore', function($store) { + $this->store = $store; + }); + $this->originalPrefix = $this->config->get('cache.prefix'); $this->storeName = $this->config->get('cache.default'); From 012a39f79d41e431546dc32b670bd33d1ffab2cb Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Fri, 9 Dec 2022 11:22:03 +0000 Subject: [PATCH 031/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index f8b59946e..1e502e1da 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -5,10 +5,10 @@ namespace Stancl\Tenancy\Bootstrappers; use Illuminate\Cache\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; -use Illuminate\Support\Facades\Cache; use Illuminate\Contracts\Config\Repository; +use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Contracts\Tenant; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { @@ -23,7 +23,7 @@ public function __construct( public function bootstrap(Tenant $tenant): void { - Cache::macro('setStore', function($store) { + Cache::macro('setStore', function ($store) { $this->store = $store; }); From dc9c8fcf6851656940d8b3afd0a1f6727a6dc3d9 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 16:58:40 +0100 Subject: [PATCH 032/155] Simplify cache store refreshing --- .../PrefixCacheTenancyBootstrapper.php | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 1e502e1da..dce58029e 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -39,30 +39,11 @@ public function revert(): void $this->originalPrefix = null; } - protected function syncStore(): void - { - $originalRepository = $this->cacheManager->driver($this->storeName); - - // Delete the repository from CacheManager's $stores cache - // So that it's forced to resolve the repository again on the next attempt to get it - $this->cacheManager->forgetDriver($this->storeName); - - // Let CacheManager create a repository with a fresh store - // To get a new store that uses the current value of `config('cache.prefix')` as the prefix - $newRepository = $this->cacheManager->driver($this->storeName); - - // Give the new store to the old repository - $originalRepository->setStore($newRepository->getStore()); - - // Overwrite the new repository with the modified old one - $this->cacheManager->setStore($this->storeName, $originalRepository); - } - protected function setCachePrefix(string|null $prefix): void { $this->config->set('cache.prefix', $prefix); - $this->syncStore(); + $this->cacheManager->refreshStore(); // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container From 9ec0b6dae30c457e51356102441172acea517acf Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 17:05:53 +0100 Subject: [PATCH 033/155] Make Tenancy override CacheManager --- .../CacheTenancyBootstrapper.php | 8 ----- src/TenancyServiceProvider.php | 15 ++++++--- tests/PrefixCacheBootstrapperTest.php | 32 ++++++++++++++++--- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/Bootstrappers/CacheTenancyBootstrapper.php b/src/Bootstrappers/CacheTenancyBootstrapper.php index 29547faea..6c963115b 100644 --- a/src/Bootstrappers/CacheTenancyBootstrapper.php +++ b/src/Bootstrappers/CacheTenancyBootstrapper.php @@ -7,7 +7,6 @@ use Illuminate\Cache\CacheManager; use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Cache; -use Stancl\Tenancy\CacheManager as TenantCacheManager; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; @@ -25,19 +24,12 @@ public function bootstrap(Tenant $tenant): void $this->resetFacadeCache(); $this->originalCache = $this->originalCache ?? $this->app['cache']; - $this->app->extend('cache', function () { - return new TenantCacheManager($this->app); - }); } public function revert(): void { $this->resetFacadeCache(); - $this->app->extend('cache', function () { - return $this->originalCache; - }); - $this->originalCache = null; } diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index ded96f359..4884d07bc 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -4,16 +4,17 @@ namespace Stancl\Tenancy; +use Stancl\Tenancy\Enums\LogMode; use Illuminate\Cache\CacheManager; -use Illuminate\Database\Console\Migrations\FreshCommand; -use Illuminate\Support\Facades\Event; -use Illuminate\Support\ServiceProvider; -use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; use Stancl\Tenancy\Contracts\Domain; use Stancl\Tenancy\Contracts\Tenant; -use Stancl\Tenancy\Enums\LogMode; +use Illuminate\Support\Facades\Event; +use Illuminate\Support\ServiceProvider; use Stancl\Tenancy\Events\Contracts\TenancyEvent; use Stancl\Tenancy\Resolvers\DomainTenantResolver; +use Stancl\Tenancy\CacheManager as TenantCacheManager; +use Illuminate\Database\Console\Migrations\FreshCommand; +use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; class TenancyServiceProvider extends ServiceProvider { @@ -97,6 +98,10 @@ public function boot(): void return new Commands\MigrateFreshOverride; }); + $this->app->singleton('cache', function ($app) { + return new TenantCacheManager($app); + }); + $this->publishes([ __DIR__ . '/../assets/config.php' => config_path('tenancy.php'), ], 'config'); diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 5db60aaec..41e0643c6 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -2,13 +2,15 @@ declare(strict_types=1); +use Illuminate\Cache\CacheManager; use Illuminate\Support\Facades\Event; -use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; use Stancl\Tenancy\Events\TenancyEnded; +use Stancl\Tenancy\Tests\Etc\CacheService; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Tests\Etc\CacheService; +use Stancl\Tenancy\CacheManager as TenancyCacheManager; +use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; beforeEach(function () { config([ @@ -22,6 +24,26 @@ Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +test('Tenancy overrides CacheManager', function() { + expect(app('cache')::class)->toBe(TenancyCacheManager::class); + expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + + tenancy()->initialize(Tenant::create(['id' => 'first'])); + + expect(app('cache')::class)->toBe(TenancyCacheManager::class); + expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + + tenancy()->initialize(Tenant::create(['id' => 'second'])); + + expect(app('cache')::class)->toBe(TenancyCacheManager::class); + expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + + tenancy()->end(); + + expect(app('cache')::class)->toBe(TenancyCacheManager::class); + expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); +}); + test('cache prefix is separate for each tenant', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); @@ -45,21 +67,21 @@ $tenantTwoPrefix = $originalPrefix . $prefixBase . $tenant2->getTenantKey(); tenancy()->initialize($tenant2); + cache()->set('key', 'tenanttwo-value'); expect($tenantTwoPrefix . ':') ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); - // Assert tenants' data is accessible using the prefix from the central context - tenancy()->end(); + // Assert tenants' data is accessible using the prefix from the central context tenancy()->end(); config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually app('cache')->forgetDriver(config('cache.default')); expect(cache($tenantOnePrefix . ':key'))->toBe('tenantone-value'); expect(cache($tenantTwoPrefix . ':key'))->toBe('tenanttwo-value'); -}); +})->group('prefix'); test('cache is persisted when reidentification is used', function () { $tenant1 = Tenant::create(); From d364568e5324f45af47344bac74d9072dcf5009e Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 17:06:49 +0100 Subject: [PATCH 034/155] Update CacheManager, add refreshStore() --- src/CacheManager.php | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index f28134b83..6a662c9a5 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -18,21 +18,34 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - $tags = [config('tenancy.cache.tag_base') . tenant()->getTenantKey()]; + // todo0 Make PrefixCacheTenancyBootstrapper work with tags + /* if (tenancy()->initialized) { + $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - if ($method === 'tags') { - $count = count($parameters); + if ($method === 'tags') { + $count = count($parameters); - if ($count !== 1) { - throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); + if ($count !== 1) { + throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); + } + + $names = $parameters[0]; + $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + + return $this->store()->tags(array_merge($tags, $names)); } - $names = $parameters[0]; - $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + return $this->store()->tags($tags)->$method(...$parameters); + } */ + + return parent::__call($method, $parameters); + } + - return $this->store()->tags(array_merge($tags, $names)); - } + public function refreshStore(string|null $repository = null): void + { + $newStore = $this->resolve($repository ?? $this->getDefaultDriver())->getStore(); - return $this->store()->tags($tags)->$method(...$parameters); + $this->driver($repository)->setStore($newStore); } } From 3cadefd41c296ac2666ee4f65133d9f8a2b80f9d Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Mon, 12 Dec 2022 16:07:21 +0000 Subject: [PATCH 035/155] Fix code style (php-cs-fixer) --- src/CacheManager.php | 1 - src/TenancyServiceProvider.php | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 6a662c9a5..920139194 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -41,7 +41,6 @@ public function __call($method, $parameters) return parent::__call($method, $parameters); } - public function refreshStore(string|null $repository = null): void { $newStore = $this->resolve($repository ?? $this->getDefaultDriver())->getStore(); diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 4884d07bc..37ad701bc 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -4,17 +4,17 @@ namespace Stancl\Tenancy; -use Stancl\Tenancy\Enums\LogMode; use Illuminate\Cache\CacheManager; -use Stancl\Tenancy\Contracts\Domain; -use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; +use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; +use Stancl\Tenancy\CacheManager as TenantCacheManager; +use Stancl\Tenancy\Contracts\Domain; +use Stancl\Tenancy\Contracts\Tenant; +use Stancl\Tenancy\Enums\LogMode; use Stancl\Tenancy\Events\Contracts\TenancyEvent; use Stancl\Tenancy\Resolvers\DomainTenantResolver; -use Stancl\Tenancy\CacheManager as TenantCacheManager; -use Illuminate\Database\Console\Migrations\FreshCommand; -use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; class TenancyServiceProvider extends ServiceProvider { From b41d8d19dc5fb4b98712197a5affa51ba1e692fe Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 17:10:59 +0100 Subject: [PATCH 036/155] Uncomment cache tagging --- src/CacheManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 920139194..8eddb67d0 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -19,7 +19,7 @@ class CacheManager extends BaseCacheManager public function __call($method, $parameters) { // todo0 Make PrefixCacheTenancyBootstrapper work with tags - /* if (tenancy()->initialized) { + if (tenancy()->initialized) { $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; if ($method === 'tags') { @@ -36,7 +36,7 @@ public function __call($method, $parameters) } return $this->store()->tags($tags)->$method(...$parameters); - } */ + } return parent::__call($method, $parameters); } From d3c7fef002ab2ae94a55e13f21903af252389933 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 17:16:53 +0100 Subject: [PATCH 037/155] Revert condition in CacheManager to avoid excessive nesting --- src/CacheManager.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 8eddb67d0..f80cd017b 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -19,26 +19,26 @@ class CacheManager extends BaseCacheManager public function __call($method, $parameters) { // todo0 Make PrefixCacheTenancyBootstrapper work with tags - if (tenancy()->initialized) { - $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - - if ($method === 'tags') { - $count = count($parameters); + if (! tenancy()->initialized) { + return parent::__call($method, $parameters); + } - if ($count !== 1) { - throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); - } + $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - $names = $parameters[0]; - $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + if ($method === 'tags') { + $count = count($parameters); - return $this->store()->tags(array_merge($tags, $names)); + if ($count !== 1) { + throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); } - return $this->store()->tags($tags)->$method(...$parameters); + $names = $parameters[0]; + $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + + return $this->store()->tags(array_merge($tags, $names)); } - return parent::__call($method, $parameters); + return $this->store()->tags($tags)->$method(...$parameters); } public function refreshStore(string|null $repository = null): void From 35a3412011f61e8ffa4a605430d70e07a7d304e8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 17:25:29 +0100 Subject: [PATCH 038/155] Move `Cache::macro()` to a slightly more appropriate place --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 4 ---- src/CacheManager.php | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index dce58029e..86c83bd2d 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -23,10 +23,6 @@ public function __construct( public function bootstrap(Tenant $tenant): void { - Cache::macro('setStore', function ($store) { - $this->store = $store; - }); - $this->originalPrefix = $this->config->get('cache.prefix'); $this->storeName = $this->config->get('cache.default'); diff --git a/src/CacheManager.php b/src/CacheManager.php index f80cd017b..ce39d2392 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -4,6 +4,7 @@ namespace Stancl\Tenancy; +use Illuminate\Support\Facades\Cache; use Illuminate\Cache\CacheManager as BaseCacheManager; // todo move to Cache namespace? @@ -43,6 +44,10 @@ public function __call($method, $parameters) public function refreshStore(string|null $repository = null): void { + Cache::macro('setStore', function ($store) { + $this->store = $store; + }); + $newStore = $this->resolve($repository ?? $this->getDefaultDriver())->getStore(); $this->driver($repository)->setStore($newStore); From bc70a2fab89e93c19e042e1ad0d8476d90a771e2 Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Mon, 12 Dec 2022 16:25:57 +0000 Subject: [PATCH 039/155] Fix code style (php-cs-fixer) --- src/CacheManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index ce39d2392..80c353719 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -4,8 +4,8 @@ namespace Stancl\Tenancy; -use Illuminate\Support\Facades\Cache; use Illuminate\Cache\CacheManager as BaseCacheManager; +use Illuminate\Support\Facades\Cache; // todo move to Cache namespace? From 5c6226befc2000e5fdee17f9f96fe2b3e4f8e1ec Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 12 Dec 2022 17:31:05 +0100 Subject: [PATCH 040/155] Use better class for the macro --- src/CacheManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 80c353719..41a2bdd6c 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -5,7 +5,7 @@ namespace Stancl\Tenancy; use Illuminate\Cache\CacheManager as BaseCacheManager; -use Illuminate\Support\Facades\Cache; +use Illuminate\Cache\Repository; // todo move to Cache namespace? @@ -44,7 +44,7 @@ public function __call($method, $parameters) public function refreshStore(string|null $repository = null): void { - Cache::macro('setStore', function ($store) { + Repository::macro('setStore', function ($store) { $this->store = $store; }); From 87efdd29542fb7548b9356e41b63385d47399bad Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 13 Dec 2022 05:25:57 +0100 Subject: [PATCH 041/155] Toggle cache tags --- src/CacheManager.php | 5 +++-- tests/BootstrapperTest.php | 5 ++++- tests/CacheManagerTest.php | 7 +++++-- tests/GlobalCacheTest.php | 3 +++ tests/PrefixCacheBootstrapperTest.php | 2 ++ 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 41a2bdd6c..14965de9c 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -11,6 +11,8 @@ class CacheManager extends BaseCacheManager { + public static bool $addTags = false; + /** * Add tags and forward the call to the inner cache store. * @@ -19,8 +21,7 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - // todo0 Make PrefixCacheTenancyBootstrapper work with tags - if (! tenancy()->initialized) { + if (! tenancy()->initialized || ! static::$addTags) { return parent::__call($method, $parameters); } diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 8a1d0bff5..7ad65c48f 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -28,6 +28,7 @@ use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; +use Stancl\Tenancy\CacheManager; beforeEach(function () { $this->mockConsoleOutput = false; @@ -75,6 +76,8 @@ }); test('cache data is separated', function (string $bootstrapper) { + CacheManager::$addTags = true; + config([ 'tenancy.bootstrappers' => [$bootstrapper], 'cache.default' => 'redis', @@ -114,7 +117,7 @@ })->with([ 'CacheTenancyBootstrapper' => CacheTenancyBootstrapper::class, 'PrefixCacheTenancyBootstrapper' => PrefixCacheTenancyBootstrapper::class, -]); +])->group('bootstrapper'); test('redis data is separated', function () { config(['tenancy.bootstrappers' => [ diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index 03580fe12..49f4dfe9f 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -2,17 +2,20 @@ declare(strict_types=1); +use Stancl\Tenancy\CacheManager; +use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Event; -use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Tests\Etc\Tenant; +use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; beforeEach(function () { config(['tenancy.bootstrappers' => [ CacheTenancyBootstrapper::class, ]]); + CacheManager::$addTags = true; + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index ea38341b1..fad1764ae 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; +use Stancl\Tenancy\CacheManager; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Facades\GlobalCache; @@ -16,6 +17,8 @@ CacheTenancyBootstrapper::class, ]]); + CacheManager::$addTags = true; + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 41e0643c6..94b0ea67a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -20,6 +20,8 @@ 'cache.default' => 'redis', ]); + TenancyCacheManager::$addTags = false; + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); From 7092f4c856e6c43bb40b68af277002afc2d3ca89 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 14 Dec 2022 16:21:45 +0100 Subject: [PATCH 042/155] Make CacheManager::$addTags default to `true` --- src/CacheManager.php | 2 +- tests/CacheManagerTest.php | 2 -- tests/GlobalCacheTest.php | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 14965de9c..e316c3ea2 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -11,7 +11,7 @@ class CacheManager extends BaseCacheManager { - public static bool $addTags = false; + public static bool $addTags = true; /** * Add tags and forward the call to the inner cache store. diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index 49f4dfe9f..fd32cd075 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -14,8 +14,6 @@ CacheTenancyBootstrapper::class, ]]); - CacheManager::$addTags = true; - Event::listen(TenancyInitialized::class, BootstrapTenancy::class); }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index fad1764ae..f32406142 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -17,8 +17,6 @@ CacheTenancyBootstrapper::class, ]]); - CacheManager::$addTags = true; - Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); From fa00fc7a2800d619251d32fdd9c899133aed5b43 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 16 Dec 2022 11:12:33 +0100 Subject: [PATCH 043/155] Add changes to PR to Laravel --- src/CacheManager.php | 60 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index e316c3ea2..21751f602 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -4,8 +4,16 @@ namespace Stancl\Tenancy; -use Illuminate\Cache\CacheManager as BaseCacheManager; +use Illuminate\Cache\ApcStore; +use Illuminate\Cache\FileStore; +use Illuminate\Cache\NullStore; +use Illuminate\Cache\ApcWrapper; +use Illuminate\Cache\ArrayStore; +use Illuminate\Cache\RedisStore; use Illuminate\Cache\Repository; +use Illuminate\Cache\MemcachedStore; +use Illuminate\Contracts\Cache\Store; +use Illuminate\Cache\CacheManager as BaseCacheManager; // todo move to Cache namespace? @@ -49,8 +57,54 @@ public function refreshStore(string|null $repository = null): void $this->store = $store; }); - $newStore = $this->resolve($repository ?? $this->getDefaultDriver())->getStore(); + $this->driver($repository)->setStore($this->createStore($repository ?? $this->getDefaultDriver())); + } + + protected function createApcStore(array $config): ApcStore + { + return new ApcStore(new ApcWrapper, $this->getPrefix($config)); + } + + protected function createArrayStore(array $config): ArrayStore + { + return new ArrayStore($config['serialize'] ?? false); + } + + protected function createFileStore(array $config): FileStore + { + return new FileStore($this->app['files'], $config['path'], $config['permission'] ?? null); + } + + protected function createMemcachedStore(array $config): MemcachedStore + { + $memcached = $this->app['memcached.connector']->connect( + $config['servers'], + $config['persistent_id'] ?? null, + $config['options'] ?? [], + array_filter($config['sasl'] ?? []) + ); + + return new MemcachedStore($memcached, $this->getPrefix($config)); + } + + protected function createRedisStore(array $config): RedisStore + { + $connection = $config['connection'] ?? 'default'; + $store = new RedisStore($this->app['redis'], $this->getPrefix($config), $connection); + + return $store->setLockConnection($config['lock_connection'] ?? $connection); + } + + protected function createNullStore(): NullStore + { + return new NullStore; + } + + public function createStore(string|null $name, array|null $config = null): Store + { + $name ??= 'null'; + $storeCreationMethod = 'create' . ucfirst($name) . 'Store'; - $this->driver($repository)->setStore($newStore); + return $this->{$storeCreationMethod}($config ?? $this->getConfig($name)); } } From c9ba569e49df4f227e1e14c777b5a99c4860a836 Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Fri, 16 Dec 2022 10:13:00 +0000 Subject: [PATCH 044/155] Fix code style (php-cs-fixer) --- src/CacheManager.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 21751f602..72b2c35e3 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -5,15 +5,15 @@ namespace Stancl\Tenancy; use Illuminate\Cache\ApcStore; -use Illuminate\Cache\FileStore; -use Illuminate\Cache\NullStore; use Illuminate\Cache\ApcWrapper; use Illuminate\Cache\ArrayStore; +use Illuminate\Cache\CacheManager as BaseCacheManager; +use Illuminate\Cache\FileStore; +use Illuminate\Cache\MemcachedStore; +use Illuminate\Cache\NullStore; use Illuminate\Cache\RedisStore; use Illuminate\Cache\Repository; -use Illuminate\Cache\MemcachedStore; use Illuminate\Contracts\Cache\Store; -use Illuminate\Cache\CacheManager as BaseCacheManager; // todo move to Cache namespace? From 8a54e19644c5b9da89f5c762bc3bea3dbfb9ecf8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 22 Dec 2022 09:41:45 +0100 Subject: [PATCH 045/155] Revert changes, add comment --- src/CacheManager.php | 59 +++----------------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 72b2c35e3..70c335ad3 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -4,16 +4,8 @@ namespace Stancl\Tenancy; -use Illuminate\Cache\ApcStore; -use Illuminate\Cache\ApcWrapper; -use Illuminate\Cache\ArrayStore; use Illuminate\Cache\CacheManager as BaseCacheManager; -use Illuminate\Cache\FileStore; -use Illuminate\Cache\MemcachedStore; -use Illuminate\Cache\NullStore; -use Illuminate\Cache\RedisStore; use Illuminate\Cache\Repository; -use Illuminate\Contracts\Cache\Store; // todo move to Cache namespace? @@ -53,58 +45,13 @@ public function __call($method, $parameters) public function refreshStore(string|null $repository = null): void { + // Could be public setStore(string $store) in Illuminate\Cache\Repository Repository::macro('setStore', function ($store) { $this->store = $store; }); - $this->driver($repository)->setStore($this->createStore($repository ?? $this->getDefaultDriver())); - } - - protected function createApcStore(array $config): ApcStore - { - return new ApcStore(new ApcWrapper, $this->getPrefix($config)); - } - - protected function createArrayStore(array $config): ArrayStore - { - return new ArrayStore($config['serialize'] ?? false); - } - - protected function createFileStore(array $config): FileStore - { - return new FileStore($this->app['files'], $config['path'], $config['permission'] ?? null); - } - - protected function createMemcachedStore(array $config): MemcachedStore - { - $memcached = $this->app['memcached.connector']->connect( - $config['servers'], - $config['persistent_id'] ?? null, - $config['options'] ?? [], - array_filter($config['sasl'] ?? []) - ); - - return new MemcachedStore($memcached, $this->getPrefix($config)); - } - - protected function createRedisStore(array $config): RedisStore - { - $connection = $config['connection'] ?? 'default'; - $store = new RedisStore($this->app['redis'], $this->getPrefix($config), $connection); - - return $store->setLockConnection($config['lock_connection'] ?? $connection); - } - - protected function createNullStore(): NullStore - { - return new NullStore; - } - - public function createStore(string|null $name, array|null $config = null): Store - { - $name ??= 'null'; - $storeCreationMethod = 'create' . ucfirst($name) . 'Store'; + $newStore = $this->resolve($repository ?? $this->getDefaultDriver())->getStore(); - return $this->{$storeCreationMethod}($config ?? $this->getConfig($name)); + $this->driver($repository)->setStore($newStore); } } From a59d5a1069e9cc9c5b78126dd0a9719263aa0a18 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 4 Jan 2023 15:08:09 +0100 Subject: [PATCH 046/155] Add test --- tests/Etc/CacheManagerService.php | 27 ++++++++++++++++++ tests/PrefixCacheBootstrapperTest.php | 41 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/Etc/CacheManagerService.php diff --git a/tests/Etc/CacheManagerService.php b/tests/Etc/CacheManagerService.php new file mode 100644 index 000000000..c41e35604 --- /dev/null +++ b/tests/Etc/CacheManagerService.php @@ -0,0 +1,27 @@ +cache = $cacheManager->driver('redis2'); + } + + public function handle(): void + { + if (tenancy()->initialized) { + $this->cache->put('key', tenant()->getTenantKey()); + } else { + $this->cache->put('key', 'central-value'); + } + } +} diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 94b0ea67a..420f6a88e 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -2,12 +2,14 @@ declare(strict_types=1); +use Illuminate\Cache\RedisStore; use Illuminate\Cache\CacheManager; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Tests\Etc\CacheService; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Tests\Etc\CacheManagerService; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\CacheManager as TenancyCacheManager; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; @@ -174,3 +176,42 @@ expect(cache('key'))->toBe('central-value'); }); + +test('stores other than the default one are not prefixed', function () { + config(['cache.default' => 'redis']); + config(['cache.stores.redis2' => config('cache.stores.redis')]); + + app(CacheManager::class)->extend('redis2', function($config) { + $redis = $this->app['redis']; + + $connection = $config['connection'] ?? 'default'; + + $store = new RedisStore($redis, $this->getPrefix($config), $connection); + + return $this->repository( + $store->setLockConnection($config['lock_connection'] ?? $connection) + ); + }); + + $this->app->singleton(CacheManagerService::class); + + app()->make(CacheManagerService::class)->handle(); + expect(cache()->driver('redis2')->get('key'))->toBe('central-value'); + + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); + tenancy()->initialize($tenant1); + + expect(cache()->driver('redis2')->get('key'))->toBe('central-value'); + app()->make(CacheManagerService::class)->handle(); + expect(cache()->driver('redis2')->get('key'))->toBe($tenant1->getTenantKey()); + + tenancy()->initialize($tenant2); + + expect(cache()->driver('redis2')->get('key'))->toBe($tenant1->getTenantKey()); + app()->make(CacheManagerService::class)->handle(); + expect(cache()->driver('redis2')->get('key'))->toBe($tenant2->getTenantKey()); + + tenancy()->end(); + expect(cache()->driver('redis2')->get('key'))->toBe($tenant2->getTenantKey()); +}); From 1c21c66913ce1b29353f63bc6e24417abf8b74cb Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 11:42:12 +0100 Subject: [PATCH 047/155] Make `$cache` non-nullable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Samuel Štancl --- tests/Etc/CacheManagerService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Etc/CacheManagerService.php b/tests/Etc/CacheManagerService.php index c41e35604..101b21986 100644 --- a/tests/Etc/CacheManagerService.php +++ b/tests/Etc/CacheManagerService.php @@ -9,7 +9,7 @@ class CacheManagerService { - public Repository|null $cache = null; + public Repository $cache; public function __construct(CacheManager $cacheManager) { From 4b0df42f8a074f16e269c26181c57bfde94c213b Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 12:47:03 +0100 Subject: [PATCH 048/155] Add and test `nonTenantCacheDrivers` --- .../PrefixCacheTenancyBootstrapper.php | 1 + tests/PrefixCacheBootstrapperTest.php | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 86c83bd2d..a8ce64f2f 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,6 +14,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { protected string|null $originalPrefix = null; protected string $storeName; + public static array $nonTenantCacheDrivers = []; public function __construct( protected Repository $config, diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 420f6a88e..8181de8a8 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -215,3 +215,30 @@ tenancy()->end(); expect(cache()->driver('redis2')->get('key'))->toBe($tenant2->getTenantKey()); }); + +test('drivers specified in the nonTenantCacheDrivers property do not get prefixed', function() { + PrefixCacheTenancyBootstrapper::$nonTenantCacheDrivers[] = config('cache.default'); + $this->app->singleton(CacheService::class); + + app()->make(CacheService::class)->handle(); + + expect(cache('key'))->toBe('central-value'); + + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); + tenancy()->initialize($tenant1); + + expect(cache('key'))->toBe('central-value'); + app()->make(CacheService::class)->handle(); + expect(cache('key'))->toBe($tenant1->getTenantKey()); + + tenancy()->initialize($tenant2); + + expect(cache('key'))->toBe($tenant1->getTenantKey()); + app()->make(CacheService::class)->handle(); + expect(cache('key'))->toBe($tenant2->getTenantKey()); + + tenancy()->end(); + + expect(cache('key'))->toBe($tenant2->getTenantKey()); +}); From 86c388a2b67aaaa9524b5b9cbc9be6c7cbd8f745 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 13:05:24 +0100 Subject: [PATCH 049/155] Add nonTenantCacheDrivers check --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index a8ce64f2f..f213ebe69 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -27,7 +27,9 @@ public function bootstrap(Tenant $tenant): void $this->originalPrefix = $this->config->get('cache.prefix'); $this->storeName = $this->config->get('cache.default'); - $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); + if (! in_array($this->storeName, static::$nonTenantCacheDrivers)) { + $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); + } } public function revert(): void From ffefe1b45ce307d9b32705363ce9191a004f0658 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 13:05:39 +0100 Subject: [PATCH 050/155] Test that the prefix stays the same --- tests/PrefixCacheBootstrapperTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 8181de8a8..f547a99a4 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -217,10 +217,16 @@ }); test('drivers specified in the nonTenantCacheDrivers property do not get prefixed', function() { + $defaultPrefix = config('cache.prefix'); PrefixCacheTenancyBootstrapper::$nonTenantCacheDrivers[] = config('cache.default'); + $expectPrefixToBeAnEmptyString = fn() => expect($defaultPrefix . ':') + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); + $this->app->singleton(CacheService::class); app()->make(CacheService::class)->handle(); + $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe('central-value'); @@ -230,15 +236,18 @@ expect(cache('key'))->toBe('central-value'); app()->make(CacheService::class)->handle(); + $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache('key'))->toBe($tenant1->getTenantKey()); app()->make(CacheService::class)->handle(); + $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); + $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe($tenant2->getTenantKey()); }); From 30d73d2694bf0e33c6a63145f3157f2a2aa1ef23 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:13:00 +0100 Subject: [PATCH 051/155] Change nonTenantCacheDrivers to tenantCacheStores --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index f213ebe69..faa12a493 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,7 +14,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { protected string|null $originalPrefix = null; protected string $storeName; - public static array $nonTenantCacheDrivers = []; + public static array $tenantCacheStores = []; public function __construct( protected Repository $config, @@ -27,7 +27,7 @@ public function bootstrap(Tenant $tenant): void $this->originalPrefix = $this->config->get('cache.prefix'); $this->storeName = $this->config->get('cache.default'); - if (! in_array($this->storeName, static::$nonTenantCacheDrivers)) { + if (in_array($this->storeName, static::$tenantCacheStores)) { $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); } } From 42381d00e2d218feba10b9dfcc41f3e02aa42fd1 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:14:20 +0100 Subject: [PATCH 052/155] Remove redundant CacheManager extend() call --- tests/PrefixCacheBootstrapperTest.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index f547a99a4..cf324bed7 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -181,18 +181,6 @@ config(['cache.default' => 'redis']); config(['cache.stores.redis2' => config('cache.stores.redis')]); - app(CacheManager::class)->extend('redis2', function($config) { - $redis = $this->app['redis']; - - $connection = $config['connection'] ?? 'default'; - - $store = new RedisStore($redis, $this->getPrefix($config), $connection); - - return $this->repository( - $store->setLockConnection($config['lock_connection'] ?? $connection) - ); - }); - $this->app->singleton(CacheManagerService::class); app()->make(CacheManagerService::class)->handle(); From 7f10b9af41802bd0e49e4eb93c87804bad477dd8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:24:37 +0100 Subject: [PATCH 053/155] Make 'redis' the only tenant cache store in beforeEach, test that tenantCacheStores works --- tests/PrefixCacheBootstrapperTest.php | 48 +++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index cf324bed7..d67943427 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -19,9 +19,11 @@ 'tenancy.bootstrappers' => [ PrefixCacheTenancyBootstrapper::class ], - 'cache.default' => 'redis', + 'cache.default' => $cacheDriver = 'redis', ]); + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + TenancyCacheManager::$addTags = false; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); @@ -204,38 +206,58 @@ expect(cache()->driver('redis2')->get('key'))->toBe($tenant2->getTenantKey()); }); -test('drivers specified in the nonTenantCacheDrivers property do not get prefixed', function() { - $defaultPrefix = config('cache.prefix'); - PrefixCacheTenancyBootstrapper::$nonTenantCacheDrivers[] = config('cache.default'); - $expectPrefixToBeAnEmptyString = fn() => expect($defaultPrefix . ':') - ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); +test('stores specified in tenantCacheStores get prefixed', function() { + // Make the currently used store ('redis') the only store in $tenantCacheStores + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; - $this->app->singleton(CacheService::class); + app()->make(CacheService::class)->handle(); + expect(cache('key'))->toBe($centralValue = 'central-value'); + + $tenant1 = Tenant::create(); + $tenant2 = Tenant::create(); + + tenancy()->initialize($tenant1); + expect(cache('key'))->toBeNull(); app()->make(CacheService::class)->handle(); - $expectPrefixToBeAnEmptyString(); + expect(cache('key'))->toBe($tenant1->getTenantKey()); + + tenancy()->initialize($tenant2); + expect(cache('key'))->toBeNull(); + app()->make(CacheService::class)->handle(); + expect(cache('key'))->toBe($tenant2->getTenantKey()); + + tenancy()->end(); + expect(cache('key'))->toBe($centralValue); +}); + +test('stores that are not specified in tenantCacheStores do not get prefixed', function() { + config(['cache.stores.redis2' => config('cache.stores.redis')]); + config(['cache.default' => 'redis2']); + // Make 'redis' the only store in $tenantCacheStores so that the current store ('redis2') doesn't get prefixed + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + + $this->app->singleton(CacheService::class); + + app()->make(CacheService::class)->handle(); expect(cache('key'))->toBe('central-value'); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); tenancy()->initialize($tenant1); + // The cache isn't prefixed, so it isn't separated expect(cache('key'))->toBe('central-value'); app()->make(CacheService::class)->handle(); - $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache('key'))->toBe($tenant1->getTenantKey()); app()->make(CacheService::class)->handle(); - $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); - - $expectPrefixToBeAnEmptyString(); expect(cache('key'))->toBe($tenant2->getTenantKey()); }); From b38aee0a6a9e7310d1410dea38471129aec7c9e4 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:28:33 +0100 Subject: [PATCH 054/155] Remove unused import, change word --- tests/PrefixCacheBootstrapperTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index d67943427..e7fe4b505 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use Illuminate\Cache\RedisStore; use Illuminate\Cache\CacheManager; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyEnded; @@ -50,7 +49,7 @@ expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); }); -test('cache prefix is separate for each tenant', function () { +test('cache prefix is different for each tenant', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); From 5ea5299ed15e5012a30b49497585c0fc65c06885 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:37:43 +0100 Subject: [PATCH 055/155] Make CacheService a singleton in a test --- tests/PrefixCacheBootstrapperTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index e7fe4b505..c02a0b0df 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -209,6 +209,8 @@ // Make the currently used store ('redis') the only store in $tenantCacheStores PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + $this->app->singleton(CacheService::class); + app()->make(CacheService::class)->handle(); expect(cache('key'))->toBe($centralValue = 'central-value'); From 507df55b4c7ac4e74b8765b7b1cee324899142f2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:45:25 +0100 Subject: [PATCH 056/155] Update test name --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index c02a0b0df..d884fc550 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -152,7 +152,7 @@ ->toBe(app('cache.store')->getPrefix()); }); -test('prefix separate cache well enough using CacheManager dependency injection', function () { +test('cache is prefixed correctly when using a repository injected in a singleton', function () { $this->app->singleton(CacheService::class); app()->make(CacheService::class)->handle(); From 52db2a0c06ccb11ccf673d0a3e518cdea250895a Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 5 Jan 2023 16:49:49 +0100 Subject: [PATCH 057/155] Remove group('prefix') --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index d884fc550..17b5e00a8 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -86,7 +86,7 @@ expect(cache($tenantOnePrefix . ':key'))->toBe('tenantone-value'); expect(cache($tenantTwoPrefix . ':key'))->toBe('tenanttwo-value'); -})->group('prefix'); +}); test('cache is persisted when reidentification is used', function () { $tenant1 = Tenant::create(); From d945d1facc24c9aeae9c702a646929f012715fa5 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 6 Jan 2023 07:17:55 +0100 Subject: [PATCH 058/155] Rename CacheManagerService --- ...acheManagerService.php => SpecificCacheStoreService.php} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/Etc/{CacheManagerService.php => SpecificCacheStoreService.php} (70%) diff --git a/tests/Etc/CacheManagerService.php b/tests/Etc/SpecificCacheStoreService.php similarity index 70% rename from tests/Etc/CacheManagerService.php rename to tests/Etc/SpecificCacheStoreService.php index 101b21986..579e2caa4 100644 --- a/tests/Etc/CacheManagerService.php +++ b/tests/Etc/SpecificCacheStoreService.php @@ -7,13 +7,13 @@ use Illuminate\Cache\CacheManager; use Illuminate\Cache\Repository; -class CacheManagerService +class SpecificCacheStoreService { public Repository $cache; - public function __construct(CacheManager $cacheManager) + public function __construct(CacheManager $cacheManager, string $cacheStoreName) { - $this->cache = $cacheManager->driver('redis2'); + $this->cache = $cacheManager->store($cacheStoreName); } public function handle(): void From 1104aba4ef167d58b33bf5c170e779a0076b71d2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 6 Jan 2023 07:20:37 +0100 Subject: [PATCH 059/155] Improve specific cache store in a service test --- tests/PrefixCacheBootstrapperTest.php | 29 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 17b5e00a8..efd019d62 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -8,7 +8,7 @@ use Stancl\Tenancy\Tests\Etc\CacheService; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Tests\Etc\CacheManagerService; +use Stancl\Tenancy\Tests\Etc\SpecificCacheStoreService; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\CacheManager as TenancyCacheManager; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; @@ -178,31 +178,36 @@ expect(cache('key'))->toBe('central-value'); }); -test('stores other than the default one are not prefixed', function () { +test('specific central cache store can be used inside a service', function () { config(['cache.default' => 'redis']); config(['cache.stores.redis2' => config('cache.stores.redis')]); + $cacheStore = 'redis2'; // Non-default, central cache store name that we'll use using cache()->store($cacheStore) - $this->app->singleton(CacheManagerService::class); + // Service uses the 'redis2' store which is central/not prefixed (not present in PrefixCacheTenancyBootstrapper::$tenantCacheStores) + $this->app->singleton(SpecificCacheStoreService::class, function() use ($cacheStore) { + return new SpecificCacheStoreService($this->app->make(CacheManager::class), $cacheStore); + }); - app()->make(CacheManagerService::class)->handle(); - expect(cache()->driver('redis2')->get('key'))->toBe('central-value'); + app()->make(SpecificCacheStoreService::class)->handle(); + expect(cache()->store($cacheStore)->get('key'))->toBe('central-value'); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); tenancy()->initialize($tenant1); - expect(cache()->driver('redis2')->get('key'))->toBe('central-value'); - app()->make(CacheManagerService::class)->handle(); - expect(cache()->driver('redis2')->get('key'))->toBe($tenant1->getTenantKey()); + // The store isn't prefixed, so the cache isn't separated + expect(cache()->store($cacheStore)->get('key'))->toBe('central-value'); + app()->make(SpecificCacheStoreService::class)->handle(); + expect(cache()->store($cacheStore)->get('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); - expect(cache()->driver('redis2')->get('key'))->toBe($tenant1->getTenantKey()); - app()->make(CacheManagerService::class)->handle(); - expect(cache()->driver('redis2')->get('key'))->toBe($tenant2->getTenantKey()); + expect(cache()->store($cacheStore)->get('key'))->toBe($tenant1->getTenantKey()); + app()->make(SpecificCacheStoreService::class)->handle(); + expect(cache()->store($cacheStore)->get('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); - expect(cache()->driver('redis2')->get('key'))->toBe($tenant2->getTenantKey()); + expect(cache()->store($cacheStore)->get('key'))->toBe($tenant2->getTenantKey()); }); test('stores specified in tenantCacheStores get prefixed', function() { From caa0c87153507abdd02499b965a0e5a7ec8a9f6b Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 6 Jan 2023 07:22:07 +0100 Subject: [PATCH 060/155] Improve comment --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index efd019d62..67010dbcf 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -181,7 +181,7 @@ test('specific central cache store can be used inside a service', function () { config(['cache.default' => 'redis']); config(['cache.stores.redis2' => config('cache.stores.redis')]); - $cacheStore = 'redis2'; // Non-default, central cache store name that we'll use using cache()->store($cacheStore) + $cacheStore = 'redis2'; // Name of the non-default, central cache store that we'll use using cache()->store($cacheStore) // Service uses the 'redis2' store which is central/not prefixed (not present in PrefixCacheTenancyBootstrapper::$tenantCacheStores) $this->app->singleton(SpecificCacheStoreService::class, function() use ($cacheStore) { From 8deeef25beb2bd549aecf264484dccef29020232 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 6 Jan 2023 08:34:56 +0100 Subject: [PATCH 061/155] Improve tests --- tests/PrefixCacheBootstrapperTest.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 67010dbcf..0ca5f8996 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -49,13 +49,16 @@ expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); }); -test('cache prefix is different for each tenant', function () { +test('correct cache prefix is used in all contexts', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); + $expectPrefixToBe = function(string $prefix) { + expect($prefix . ':') // RedisStore suffixes prefix with ':' + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); + }; - expect($originalPrefix . ':') // RedisStore suffixes prefix with ':' - ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); + $expectPrefixToBe($originalPrefix); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); @@ -65,9 +68,7 @@ tenancy()->initialize($tenant1); cache()->set('key', 'tenantone-value'); - expect($tenantOnePrefix . ':') - ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); + $expectPrefixToBe($tenantOnePrefix); $tenantTwoPrefix = $originalPrefix . $prefixBase . $tenant2->getTenantKey(); @@ -75,9 +76,7 @@ cache()->set('key', 'tenanttwo-value'); - expect($tenantTwoPrefix . ':') - ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); + $expectPrefixToBe($tenantTwoPrefix); // Assert tenants' data is accessible using the prefix from the central context tenancy()->end(); @@ -103,7 +102,7 @@ expect(cache('foo'))->toBe('bar'); }); -test('prefix separate cache well enough', function () { +test('prefixing separates the cache', function () { $tenant1 = Tenant::create(); tenancy()->initialize($tenant1); @@ -238,7 +237,7 @@ expect(cache('key'))->toBe($centralValue); }); -test('stores that are not specified in tenantCacheStores do not get prefixed', function() { +test('stores not specified in tenantCacheStores do not get prefixed', function() { config(['cache.stores.redis2' => config('cache.stores.redis')]); config(['cache.default' => 'redis2']); // Make 'redis' the only store in $tenantCacheStores so that the current store ('redis2') doesn't get prefixed From 62a2ed163c8f5f5f3b23dc5c78d7187d0aabed9f Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 31 Jan 2023 08:13:06 +0100 Subject: [PATCH 062/155] Use my Laravel fork --- composer.json | 8 +++++++- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 4 +++- src/CacheManager.php | 12 ------------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 098b1cc49..d453f5060 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "stancl/virtualcolumn": "^1.3" }, "require-dev": { - "laravel/framework": "^9.0", + "laravel/framework": "dev-cache-methods as 9.21", "orchestra/testbench": "^7.0", "league/flysystem-aws-s3-v3": "^3.0", "doctrine/dbal": "^2.10", @@ -33,6 +33,12 @@ "nunomaduro/larastan": "^1.0", "spatie/invade": "^1.1" }, + "repositories": [ + { + "type": "vcs", + "url": "http://github.com/lukinovec/framework" + } + ], "autoload": { "psr-4": { "Stancl\\Tenancy\\": "src/" diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index faa12a493..9f17cc2fb 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -42,7 +42,9 @@ protected function setCachePrefix(string|null $prefix): void { $this->config->set('cache.prefix', $prefix); - $this->cacheManager->refreshStore(); + $newStore = $this->cacheManager->resolve($this->storeName ?? $this->cacheManager->getDefaultDriver())->getStore(); + + $this->cacheManager->driver($this->storeName)->setStore($newStore); // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container diff --git a/src/CacheManager.php b/src/CacheManager.php index 70c335ad3..d9c35521d 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -42,16 +42,4 @@ public function __call($method, $parameters) return $this->store()->tags($tags)->$method(...$parameters); } - - public function refreshStore(string|null $repository = null): void - { - // Could be public setStore(string $store) in Illuminate\Cache\Repository - Repository::macro('setStore', function ($store) { - $this->store = $store; - }); - - $newStore = $this->resolve($repository ?? $this->getDefaultDriver())->getStore(); - - $this->driver($repository)->setStore($newStore); - } } From a4aa499269b4b2f290a09b01deea6db0f9d7d6ba Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Tue, 31 Jan 2023 07:13:35 +0000 Subject: [PATCH 063/155] Fix code style (php-cs-fixer) --- src/CacheManager.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index d9c35521d..757151d8d 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -5,7 +5,6 @@ namespace Stancl\Tenancy; use Illuminate\Cache\CacheManager as BaseCacheManager; -use Illuminate\Cache\Repository; // todo move to Cache namespace? From 9b36bf29ce30ffeae63f8ac6077faafd2f9085df Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 31 Jan 2023 08:21:27 +0100 Subject: [PATCH 064/155] Downgrade Laravel --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c09216ec7..73674c6d3 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "stancl/virtualcolumn": "^1.3" }, "require-dev": { - "laravel/framework": "dev-cache-methods as 9.38", + "laravel/framework": "dev-cache-methods as 9.21", "orchestra/testbench": "^7.0", "league/flysystem-aws-s3-v3": "^3.0", "doctrine/dbal": "^2.10", From bd6332f0e63eb7b53cdd34d8e042788f4a28d987 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 1 Feb 2023 06:20:27 +0100 Subject: [PATCH 065/155] Upgrade Laravel --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 73674c6d3..2b1cb6622 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "stancl/virtualcolumn": "^1.3" }, "require-dev": { - "laravel/framework": "dev-cache-methods as 9.21", + "laravel/framework": "dev-cache-methods as 9.47", "orchestra/testbench": "^7.0", "league/flysystem-aws-s3-v3": "^3.0", "doctrine/dbal": "^2.10", From cc9928bc34ba317bf5c6d5b15c14699a75d6fe8e Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 1 Feb 2023 07:01:52 +0100 Subject: [PATCH 066/155] Hint Repository implementation instead of contract --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 9f17cc2fb..dda6b0b75 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -5,7 +5,8 @@ namespace Stancl\Tenancy\Bootstrappers; use Illuminate\Cache\CacheManager; -use Illuminate\Contracts\Config\Repository; +use Illuminate\Cache\Repository; +use Illuminate\Contracts\Config\Repository as RepositoryContract; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; @@ -17,7 +18,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper public static array $tenantCacheStores = []; public function __construct( - protected Repository $config, + protected RepositoryContract $config, protected CacheManager $cacheManager, ) { } @@ -44,7 +45,10 @@ protected function setCachePrefix(string|null $prefix): void $newStore = $this->cacheManager->resolve($this->storeName ?? $this->cacheManager->getDefaultDriver())->getStore(); - $this->cacheManager->driver($this->storeName)->setStore($newStore); + /** @var Repository $repository */ + $repository = $this->cacheManager->driver($this->storeName); + + $repository->setStore($newStore); // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container From 95170312eaa6ec241ca0111b329f3b03bb3492a7 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 1 Feb 2023 11:33:09 +0100 Subject: [PATCH 067/155] Fix types --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index dda6b0b75..51c1cecb6 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -4,12 +4,12 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\CacheManager; use Illuminate\Cache\Repository; -use Illuminate\Contracts\Config\Repository as RepositoryContract; +use Illuminate\Cache\CacheManager; +use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Contracts\Config\Repository as ConfigRepository; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { @@ -18,7 +18,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper public static array $tenantCacheStores = []; public function __construct( - protected RepositoryContract $config, + protected ConfigRepository $config, protected CacheManager $cacheManager, ) { } From 9ed7308754a94c4b79b5b8dfb96969890cca217f Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Wed, 1 Feb 2023 10:33:33 +0000 Subject: [PATCH 068/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 51c1cecb6..d6ab298ed 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -4,12 +4,12 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\Repository; use Illuminate\Cache\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Cache\Repository; +use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Illuminate\Contracts\Config\Repository as ConfigRepository; +use Stancl\Tenancy\Contracts\Tenant; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { From c3e3a33ed0a02fdb182007dbfa9efb76078adda2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 1 Feb 2023 11:51:28 +0100 Subject: [PATCH 069/155] Fix test --- tests/PrefixCacheBootstrapperTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 0ca5f8996..86559c230 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -78,8 +78,11 @@ $expectPrefixToBe($tenantTwoPrefix); - // Assert tenants' data is accessible using the prefix from the central context tenancy()->end(); + // Prefix gets reverted to default after ending tenancy + tenancy()->end(); + $expectPrefixToBe($originalPrefix); + // Assert tenant's data is accessible using the prefix from the central context config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually app('cache')->forgetDriver(config('cache.default')); From e11a71e421f9fe4f57220b0541317347510d94fd Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 2 Feb 2023 11:16:45 +0100 Subject: [PATCH 070/155] Use Laravel fork in ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 314d6e4c3..6b6bb7f76 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - laravel: ['^9.0'] + laravel: ['dev-cache-methods as 9.47'] steps: - name: Checkout From a48e447389526f8ad1b23f7f4a43fd9000e3765b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 17:49:15 +0100 Subject: [PATCH 071/155] use dev-master before our changes are released in L10 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fdee61db..a5009f475 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: include: - laravel: "^9.0" php: "8.0" - - laravel: "^10.0" + - laravel: "dev-master" php: "8.2" steps: From 587396b5caccc732fe5449ff6f2bb614b564a96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 18:21:02 +0100 Subject: [PATCH 072/155] remove laravel fork from repositories --- composer.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/composer.json b/composer.json index 1431cec54..b5734c1bb 100644 --- a/composer.json +++ b/composer.json @@ -35,12 +35,6 @@ "nunomaduro/larastan": "^2.4", "spatie/invade": "^1.1" }, - "repositories": [ - { - "type": "vcs", - "url": "http://github.com/lukinovec/framework" - } - ], "autoload": { "psr-4": { "Stancl\\Tenancy\\": "src/" From c254f621cebd05d11b3d7358b74f36b28ad11167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 18:22:29 +0100 Subject: [PATCH 073/155] use 10.x-dev instead of master --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5009f475..e822f1278 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: include: - laravel: "^9.0" php: "8.0" - - laravel: "dev-master" + - laravel: "10.x-dev" php: "8.2" steps: From d655d3acf70dde8005ebe52cfc894edf37c41f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 18:31:16 +0100 Subject: [PATCH 074/155] remove L9 support --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 39d8b730c..ae7230a99 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,6 @@ jobs: strategy: matrix: include: - - laravel: "^9.0" - php: "8.0" - laravel: "dev-master" php: "8.2" From 4acf7e26b5a122cffe4840fe9ffebb8c231b10d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 18:35:46 +0100 Subject: [PATCH 075/155] 10.x-dev (fix conflict resolution) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae7230a99..8d9a3f24e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: include: - - laravel: "dev-master" + - laravel: "10.x-dev" php: "8.2" steps: From 5f3079d2ff62979e79ab2cfd94f45f917f66b317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 18:38:20 +0100 Subject: [PATCH 076/155] use the laravel version from the ci matrix for the phpstan job as well --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d9a3f24e..8d615ce83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,9 @@ jobs: with: php-version: '8.2' - uses: actions/checkout@v2 - - name: Install composer dependencies - run: composer install + - name: Install Composer dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update + composer update --prefer-dist --no-interaction - name: Run phpstan run: vendor/bin/phpstan analyse --xdebug From 76dae7b025fa762bcf94f72039fbb73946fb3ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 21 Feb 2023 18:42:31 +0100 Subject: [PATCH 077/155] Revert "use the laravel version from the ci matrix for the phpstan job as well" This reverts commit 5f3079d2ff62979e79ab2cfd94f45f917f66b317. --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d615ce83..8d9a3f24e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,9 +114,7 @@ jobs: with: php-version: '8.2' - uses: actions/checkout@v2 - - name: Install Composer dependencies - run: | - composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update - composer update --prefer-dist --no-interaction + - name: Install composer dependencies + run: composer install - name: Run phpstan run: vendor/bin/phpstan analyse --xdebug From 9e8af40715850a02ec9ca81108ee52559d09669e Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 21 Feb 2023 18:48:57 +0100 Subject: [PATCH 078/155] Test that non-default stores get prefixed too --- tests/PrefixCacheBootstrapperTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 86559c230..c493b5801 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -269,3 +269,21 @@ tenancy()->end(); expect(cache('key'))->toBe($tenant2->getTenantKey()); }); + +test('stores that are not default get prefixed too', function () { + config(['cache.stores.redis2' => config('cache.stores.redis')]); + config(['cache.default' => 'redis2']); + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; + + $defaultPrefix = cache()->store()->getPrefix(); + + expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); + + tenancy()->initialize($tenant = Tenant::create()); + $generateTenantPrefix = fn (Tenant $tenant) => str($defaultPrefix)->beforeLast(':') . 'tenant_' . $tenant->getTenantKey() . ':'; + + // Default store + expect(cache()->store()->getPrefix())->toBe($generateTenantPrefix($tenant)); + // Non-default store + expect(cache()->store('redis')->getPrefix())->toBe($generateTenantPrefix($tenant)); +}); From a152d31ac4b0e0da7a3cb281ad41b488633589e4 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 23 Feb 2023 14:17:30 +0100 Subject: [PATCH 079/155] Use new Laravel release, remove L9 support --- .github/workflows/ci.yml | 2 +- composer.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d9a3f24e..cbd3a4bd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: include: - - laravel: "10.x-dev" + - laravel: 10 php: "8.2" steps: diff --git a/composer.json b/composer.json index b5734c1bb..753981836 100644 --- a/composer.json +++ b/composer.json @@ -26,8 +26,8 @@ "spatie/invade": "^1.1" }, "require-dev": { - "laravel/framework": "^9.38|^10.0", - "orchestra/testbench": "^7.0|^8.0", + "laravel/framework": "^10.1.1", + "orchestra/testbench": "^8.0", "league/flysystem-aws-s3-v3": "^3.12.2", "doctrine/dbal": "^3.6.0", "spatie/valuestore": "^1.2.5", From cf799d3529ddebd6d92e625308020e38710c1378 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 23 Feb 2023 14:21:36 +0100 Subject: [PATCH 080/155] Complete L9 support removal --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 753981836..1ab85736e 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "require": { "php": "^8.2", "ext-json": "*", - "illuminate/support": "^9.38|^10.0", + "illuminate/support": "^10.0", "facade/ignition-contracts": "^1.0.2", "spatie/ignition": "^1.4", "ramsey/uuid": "^4.7.3", From a7e4956ee57a9329a949d5144d764d03d698bb80 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 23 Feb 2023 14:22:51 +0100 Subject: [PATCH 081/155] Specify 10.1.1 as the minimal Laravel version in ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cbd3a4bd0..1ed8937f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: include: - - laravel: 10 + - laravel: "^10.1.1" php: "8.2" steps: From 46383927886ca00373ed9d0c1bc0c516f88bead7 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 23 Feb 2023 14:33:29 +0100 Subject: [PATCH 082/155] Use 10.x-dev --- .github/workflows/ci.yml | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ed8937f6..8d9a3f24e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: include: - - laravel: "^10.1.1" + - laravel: "10.x-dev" php: "8.2" steps: diff --git a/composer.json b/composer.json index 1ab85736e..4794d6e0c 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "spatie/invade": "^1.1" }, "require-dev": { - "laravel/framework": "^10.1.1", + "laravel/framework": "10.x-dev", "orchestra/testbench": "^8.0", "league/flysystem-aws-s3-v3": "^3.12.2", "doctrine/dbal": "^3.6.0", From b7155719278edca13b912edf22483a6c35cf4d1d Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 24 Feb 2023 09:17:24 +0100 Subject: [PATCH 083/155] Prefix all cache stores specified in `$tenantCacheStores` --- .../PrefixCacheTenancyBootstrapper.php | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index d6ab298ed..fea1a6a7e 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,7 +14,6 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { protected string|null $originalPrefix = null; - protected string $storeName; public static array $tenantCacheStores = []; public function __construct( @@ -26,16 +25,14 @@ public function __construct( public function bootstrap(Tenant $tenant): void { $this->originalPrefix = $this->config->get('cache.prefix'); - $this->storeName = $this->config->get('cache.default'); - if (in_array($this->storeName, static::$tenantCacheStores)) { - $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); - } + $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); } public function revert(): void { $this->setCachePrefix($this->originalPrefix); + $this->originalPrefix = null; } @@ -43,15 +40,25 @@ protected function setCachePrefix(string|null $prefix): void { $this->config->set('cache.prefix', $prefix); - $newStore = $this->cacheManager->resolve($this->storeName ?? $this->cacheManager->getDefaultDriver())->getStore(); - - /** @var Repository $repository */ - $repository = $this->cacheManager->driver($this->storeName); - - $repository->setStore($newStore); + foreach (static::$tenantCacheStores as $driver) { + // Refresh driver's store to make the driver use the current prefix + $this->refreshStore($driver); + } // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container Cache::clearResolvedInstances(); } + + /** + * Refresh cache driver's store. + */ + protected function refreshStore(string $driver): void + { + $newStore = $this->cacheManager->resolve($driver)->getStore(); + /** @var Repository $repository */ + $repository = $this->cacheManager->driver($driver); + + $repository->setStore($newStore); + } } From 5a20a0e2a76155c68ac49409c040466ccb41c1e7 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 14 Mar 2023 17:19:31 +0100 Subject: [PATCH 084/155] Update Laravel --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4794d6e0c..cb916564d 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "spatie/invade": "^1.1" }, "require-dev": { - "laravel/framework": "10.x-dev", + "laravel/framework": "^10.1", "orchestra/testbench": "^8.0", "league/flysystem-aws-s3-v3": "^3.12.2", "doctrine/dbal": "^3.6.0", From 660b772fe3d2654ac94ff46cf600d442d32ab578 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 14 Mar 2023 17:19:45 +0100 Subject: [PATCH 085/155] Use tmpfs in docker-compose --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 465b36cde..5855220b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,6 +40,8 @@ services: test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] timeout: 10s retries: 10 + tmpfs: + - /var/lib/mysql mysql2: image: mysql:5.7 environment: @@ -51,6 +53,8 @@ services: test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] timeout: 10s retries: 10 + tmpfs: + - /var/lib/mysql postgres: image: postgres:11 environment: From 8348389fb3faf9bc8c09791f964db4c9d7f95c6e Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 14 Mar 2023 17:22:56 +0100 Subject: [PATCH 086/155] Add customizing cache store prefixes --- .../PrefixCacheTenancyBootstrapper.php | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index fea1a6a7e..49ce21c03 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -4,17 +4,21 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\CacheManager; +use Closure; use Illuminate\Cache\Repository; -use Illuminate\Contracts\Config\Repository as ConfigRepository; +use Illuminate\Cache\CacheManager; +use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Contracts\Config\Repository as ConfigRepository; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { - protected string|null $originalPrefix = null; - public static array $tenantCacheStores = []; + protected array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' + public static array $tenantCacheStores = []; // E.g. 'redis' + public static array $prefixGenerators = [ + // driverName => Closure(Tenant $tenant) + ]; public function __construct( protected ConfigRepository $config, @@ -24,32 +28,62 @@ public function __construct( public function bootstrap(Tenant $tenant): void { - $this->originalPrefix = $this->config->get('cache.prefix'); + // If the user didn't specify the default generator + // Use static::defaultPrefixGenerator() as the default prefix generator + if (! isset(static::$prefixGenerators['default'])) { + static::generatePrefixUsing('default', static::defaultPrefixGenerator($this->config->get('cache.prefix'))); + } + + foreach (static::$tenantCacheStores as $store) { + $this->originalPrefixes[$store] = $this->config->get('cache.prefix'); - $this->setCachePrefix($this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey()); + $this->setCachePrefix($store, $this->getStorePrefix($store, $tenant)); + } } public function revert(): void { - $this->setCachePrefix($this->originalPrefix); + foreach ($this->originalPrefixes as $driver => $prefix) { + $this->setCachePrefix($driver, $prefix); + } + + $this->originalPrefixes = []; + } - $this->originalPrefix = null; + public static function defaultPrefixGenerator(string $originalPrefix = ''): Closure + { + return function (Tenant $tenant) use ($originalPrefix) { + return $originalPrefix . config('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + }; } - protected function setCachePrefix(string|null $prefix): void + protected function setCachePrefix(string $driver, string|null $prefix): void { $this->config->set('cache.prefix', $prefix); - foreach (static::$tenantCacheStores as $driver) { - // Refresh driver's store to make the driver use the current prefix - $this->refreshStore($driver); - } + // Refresh driver's store to make the driver use the current prefix + $this->refreshStore($driver); // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container Cache::clearResolvedInstances(); } + public function getStorePrefix(string $store, Tenant $tenant): string + { + if (isset(static::$prefixGenerators[$store])) { + return static::$prefixGenerators[$store]($tenant); + } + + // Use default generator if the store doesn't have a custom generator + return static::$prefixGenerators['default']($tenant); + } + + public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void + { + static::$prefixGenerators[$store] = $prefixGenerator; + } + /** * Refresh cache driver's store. */ From 7b91e3fdec3b8c4312fe73c6356bc03839b253c2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 14 Mar 2023 17:24:57 +0100 Subject: [PATCH 087/155] Test cache prefixing customization --- tests/PrefixCacheBootstrapperTest.php | 71 ++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index c493b5801..5d1683a0b 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -22,6 +22,7 @@ ]); PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + PrefixCacheTenancyBootstrapper::$prefixGenerators = []; TenancyCacheManager::$addTags = false; @@ -29,6 +30,10 @@ Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +afterEach(function () { + PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; +}); + test('Tenancy overrides CacheManager', function() { expect(app('cache')::class)->toBe(TenancyCacheManager::class); expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); @@ -270,20 +275,74 @@ expect(cache('key'))->toBe($tenant2->getTenantKey()); }); -test('stores that are not default get prefixed too', function () { +test('non default stores get prefixed too', function () { config(['cache.stores.redis2' => config('cache.stores.redis')]); + // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; + // The prefix is the same for both drivers in the central context + $originalConfigPrefix = config('cache.prefix'); $defaultPrefix = cache()->store()->getPrefix(); - expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); tenancy()->initialize($tenant = Tenant::create()); - $generateTenantPrefix = fn (Tenant $tenant) => str($defaultPrefix)->beforeLast(':') . 'tenant_' . $tenant->getTenantKey() . ':'; - // Default store - expect(cache()->store()->getPrefix())->toBe($generateTenantPrefix($tenant)); + // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator + expect(cache()->store()->getPrefix())->toBe($prefix = PrefixCacheTenancyBootstrapper::defaultPrefixGenerator($originalConfigPrefix)($tenant) . ':'); // Non-default store - expect(cache()->store('redis')->getPrefix())->toBe($generateTenantPrefix($tenant)); + expect(cache()->store('redis')->getPrefix())->toBe($prefix); + + tenancy()->end(); +}); + +test('cache store prefix generation can be customized', function() { + config(['cache.default' => 'redis']); + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + + expect(PrefixCacheTenancyBootstrapper::$prefixGenerators)->not()->toHaveKey('redis'); + + // Add custom prefix generator for the 'redis' store + PrefixCacheTenancyBootstrapper::generatePrefixUsing('redis', $generateTenantPrefix = function (Tenant $tenant) { + return 'redis_tenant_cache_' . $tenant->getTenantKey(); + }); + + expect(PrefixCacheTenancyBootstrapper::$prefixGenerators)->toHaveKey('redis'); + + tenancy()->initialize($tenant = Tenant::create()); + + // Expect the 'redis' store to use the prefix generated by the custom generator + expect(cache()->store('redis')->getPrefix())->toBe($generateTenantPrefix($tenant) . ':'); + + tenancy()->end(); +}); + +test('stores get prefixed by the default prefix generator if the store does not have a corresponding generator', function() { + config(['cache.stores.redis2' => config('cache.stores.redis')]); + // Make 'redis2' the default cache driver + config(['cache.default' => 'redis2']); + + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; + + // Don't add a generator for 'redis2' + // Let the default generator generate the prefix + // The default generator is created for you in bootstrap() + tenancy()->initialize($tenant = Tenant::create()); + $defaultGenerator = PrefixCacheTenancyBootstrapper::$prefixGenerators['default']; + expect(cache()->store()->getPrefix())->toBe($defaultGenerator($tenant) . ':'); + // Other stores without a prefix generator use the default generator too + expect(cache()->store('redis')->getPrefix())->toBe($defaultGenerator($tenant) . ':'); + tenancy()->end(); + + // You can override the default prefix generator + PrefixCacheTenancyBootstrapper::generatePrefixUsing('default', $newDefaultGenerator = function (Tenant $tenant) { + return 'new_' . $tenant->getTenantKey(); + }); + + tenancy()->initialize($tenant = Tenant::create()); + // The store gets prefixed using the new default generator + expect(cache()->store()->getPrefix())->toBe($newDefaultGenerator($tenant) . ':'); + expect(cache()->store('redis')->getPrefix())->toBe($newDefaultGenerator($tenant) . ':'); + + tenancy()->end(); }); From 9388459d7d877a37f760bb8cb55da77dd513a9ee Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Tue, 14 Mar 2023 16:30:41 +0000 Subject: [PATCH 088/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 49ce21c03..daaf5c20a 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -5,12 +5,12 @@ namespace Stancl\Tenancy\Bootstrappers; use Closure; -use Illuminate\Cache\Repository; use Illuminate\Cache\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Cache\Repository; +use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Illuminate\Contracts\Config\Repository as ConfigRepository; +use Stancl\Tenancy\Contracts\Tenant; class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { From e9aa5be546c4d59f71f841ee3260c1f4b87b1011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Mon, 20 Mar 2023 21:50:17 +0100 Subject: [PATCH 089/155] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d9a3f24e..aca092db4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: include: - - laravel: "10.x-dev" + - laravel: "^10.0" php: "8.2" steps: From c45f900b787b3017607ef252dace7fd44086e5d4 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 30 Mar 2023 14:37:32 +0200 Subject: [PATCH 090/155] Delete tmpfs from docker-compose.yml (there were no benefits) --- docker-compose.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5855220b2..465b36cde 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,8 +40,6 @@ services: test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] timeout: 10s retries: 10 - tmpfs: - - /var/lib/mysql mysql2: image: mysql:5.7 environment: @@ -53,8 +51,6 @@ services: test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] timeout: 10s retries: 10 - tmpfs: - - /var/lib/mysql postgres: image: postgres:11 environment: From 8ea3cc9739b1a2b83f692e8f5695e5a933225b88 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 31 Mar 2023 07:51:20 +0200 Subject: [PATCH 091/155] Use default prefix generator inline, delete the 'default' key logic --- .../PrefixCacheTenancyBootstrapper.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index daaf5c20a..38e0e48c9 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -28,12 +28,6 @@ public function __construct( public function bootstrap(Tenant $tenant): void { - // If the user didn't specify the default generator - // Use static::defaultPrefixGenerator() as the default prefix generator - if (! isset(static::$prefixGenerators['default'])) { - static::generatePrefixUsing('default', static::defaultPrefixGenerator($this->config->get('cache.prefix'))); - } - foreach (static::$tenantCacheStores as $store) { $this->originalPrefixes[$store] = $this->config->get('cache.prefix'); @@ -50,13 +44,6 @@ public function revert(): void $this->originalPrefixes = []; } - public static function defaultPrefixGenerator(string $originalPrefix = ''): Closure - { - return function (Tenant $tenant) use ($originalPrefix) { - return $originalPrefix . config('tenancy.cache.prefix_base') . $tenant->getTenantKey(); - }; - } - protected function setCachePrefix(string $driver, string|null $prefix): void { $this->config->set('cache.prefix', $prefix); @@ -75,8 +62,7 @@ public function getStorePrefix(string $store, Tenant $tenant): string return static::$prefixGenerators[$store]($tenant); } - // Use default generator if the store doesn't have a custom generator - return static::$prefixGenerators['default']($tenant); + return $this->config->get('cache.prefix', '') . config('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void From 1f1c7cc2bc1f0a10653870e171241e88ac12386c Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 31 Mar 2023 09:19:46 +0200 Subject: [PATCH 092/155] Fix original prefix logic --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 38e0e48c9..be4e952ed 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -28,8 +28,10 @@ public function __construct( public function bootstrap(Tenant $tenant): void { + $originalPrefix = $this->config->get('cache.prefix'); + foreach (static::$tenantCacheStores as $store) { - $this->originalPrefixes[$store] = $this->config->get('cache.prefix'); + $this->originalPrefixes[$store] = $originalPrefix; $this->setCachePrefix($store, $this->getStorePrefix($store, $tenant)); } @@ -62,7 +64,7 @@ public function getStorePrefix(string $store, Tenant $tenant): string return static::$prefixGenerators[$store]($tenant); } - return $this->config->get('cache.prefix', '') . config('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + return $this->originalPrefixes[$store] . config('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void From 7bbd5350c7ec6babfad183950719e2eccbe59097 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 31 Mar 2023 09:20:10 +0200 Subject: [PATCH 093/155] Update tests --- tests/PrefixCacheBootstrapperTest.php | 36 ++++++++++----------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 5d1683a0b..d17bafff5 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -282,16 +282,18 @@ PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; // The prefix is the same for both drivers in the central context - $originalConfigPrefix = config('cache.prefix'); + $tenant = Tenant::create(); $defaultPrefix = cache()->store()->getPrefix(); + $expectedPrefix = config('cache.prefix', '') . config('tenancy.cache.prefix_base', '') . $tenant->getTenantKey(); + expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); - tenancy()->initialize($tenant = Tenant::create()); + tenancy()->initialize($tenant); // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator - expect(cache()->store()->getPrefix())->toBe($prefix = PrefixCacheTenancyBootstrapper::defaultPrefixGenerator($originalConfigPrefix)($tenant) . ':'); + expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); // Non-default store - expect(cache()->store('redis')->getPrefix())->toBe($prefix); + expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); tenancy()->end(); }); @@ -317,32 +319,20 @@ tenancy()->end(); }); -test('stores get prefixed by the default prefix generator if the store does not have a corresponding generator', function() { +test('stores get prefixed using the default way if the store does not have a corresponding generator', function() { config(['cache.stores.redis2' => config('cache.stores.redis')]); // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); + $tenant = Tenant::create(); + $expectedPrefix = config('cache.prefix', '') . config('tenancy.cache.prefix_base', '') . $tenant->getTenantKey(); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; // Don't add a generator for 'redis2' - // Let the default generator generate the prefix - // The default generator is created for you in bootstrap() - tenancy()->initialize($tenant = Tenant::create()); - $defaultGenerator = PrefixCacheTenancyBootstrapper::$prefixGenerators['default']; - expect(cache()->store()->getPrefix())->toBe($defaultGenerator($tenant) . ':'); + // Let the prefix get created using the default approach + tenancy()->initialize($tenant); + expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); // Other stores without a prefix generator use the default generator too - expect(cache()->store('redis')->getPrefix())->toBe($defaultGenerator($tenant) . ':'); - tenancy()->end(); - - // You can override the default prefix generator - PrefixCacheTenancyBootstrapper::generatePrefixUsing('default', $newDefaultGenerator = function (Tenant $tenant) { - return 'new_' . $tenant->getTenantKey(); - }); - - tenancy()->initialize($tenant = Tenant::create()); - // The store gets prefixed using the new default generator - expect(cache()->store()->getPrefix())->toBe($newDefaultGenerator($tenant) . ':'); - expect(cache()->store('redis')->getPrefix())->toBe($newDefaultGenerator($tenant) . ':'); - + expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); tenancy()->end(); }); From 840cd831d6a762638a9da4c30d979d4f5beb4dce Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 31 Mar 2023 14:10:56 +0200 Subject: [PATCH 094/155] Delete CacheTenancyBootstrapper --- assets/config.php | 3 +- .../CacheTenancyBootstrapper.php | 45 ------------------- tests/BootstrapperTest.php | 12 +++-- tests/CacheManagerTest.php | 6 +-- tests/GlobalCacheTest.php | 6 +-- 5 files changed, 9 insertions(+), 63 deletions(-) delete mode 100644 src/Bootstrappers/CacheTenancyBootstrapper.php diff --git a/assets/config.php b/assets/config.php index 0a4a6233d..e5c1a24b4 100644 --- a/assets/config.php +++ b/assets/config.php @@ -98,7 +98,6 @@ */ 'bootstrappers' => [ Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper::class, - Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper::class, @@ -179,7 +178,7 @@ ], /** - * Cache tenancy config. Used by CacheTenancyBootstrapper. + * Cache tenancy config. Used by the custom CacheManager and the PrefixCacheTenancyBootstrapper. * * This works for all Cache facade calls, cache() helper * calls and direct calls to injected cache stores. diff --git a/src/Bootstrappers/CacheTenancyBootstrapper.php b/src/Bootstrappers/CacheTenancyBootstrapper.php deleted file mode 100644 index 6c963115b..000000000 --- a/src/Bootstrappers/CacheTenancyBootstrapper.php +++ /dev/null @@ -1,45 +0,0 @@ -resetFacadeCache(); - - $this->originalCache = $this->originalCache ?? $this->app['cache']; - } - - public function revert(): void - { - $this->resetFacadeCache(); - - $this->originalCache = null; - } - - /** - * This wouldn't be necessary, but is needed when a call to the - * facade has been made prior to bootstrapping tenancy. The - * facade has its own cache, separate from the container. - */ - public function resetFacadeCache(): void - { - Cache::clearResolvedInstances(); - } -} diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 4515625d7..d61187125 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -31,7 +31,6 @@ use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper; -use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper; use Stancl\Tenancy\Middleware\InitializeTenancyBySubdomain; use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; @@ -84,11 +83,13 @@ expect(DB::table('users')->first()->name)->toBe('Foo'); }); -test('cache data is separated', function (string $bootstrapper) { +test('cache data is separated', function () { CacheManager::$addTags = true; config([ - 'tenancy.bootstrappers' => [$bootstrapper], + 'tenancy.bootstrappers' => [ + PrefixCacheTenancyBootstrapper::class, + ], 'cache.default' => 'redis', ]); @@ -123,10 +124,7 @@ // Asset central is still the same expect(Cache::get('foo'))->toBe('central'); -})->with([ - 'CacheTenancyBootstrapper' => CacheTenancyBootstrapper::class, - 'PrefixCacheTenancyBootstrapper' => PrefixCacheTenancyBootstrapper::class, -])->group('bootstrapper'); +}); test('redis data is separated', function () { config(['tenancy.bootstrappers' => [ diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index fd32cd075..7b1b99da7 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -7,13 +7,11 @@ use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => [ - CacheTenancyBootstrapper::class, - ]]); + config(['tenancy.bootstrappers' => []]); + CacheManager::$addTags = true; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index f32406142..c4fcb0e54 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -3,8 +3,6 @@ declare(strict_types=1); use Illuminate\Support\Facades\Event; -use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; -use Stancl\Tenancy\CacheManager; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Facades\GlobalCache; @@ -13,9 +11,7 @@ use Stancl\Tenancy\Tests\Etc\Tenant; beforeEach(function () { - config(['tenancy.bootstrappers' => [ - CacheTenancyBootstrapper::class, - ]]); + config(['tenancy.bootstrappers' => []]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); From 66669934f91556802d89ef27c0f667ad0308cda7 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 31 Mar 2023 14:11:45 +0200 Subject: [PATCH 095/155] Reset static properties in afterEach --- tests/PrefixCacheBootstrapperTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index d17bafff5..d9a0afb5b 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -8,9 +8,9 @@ use Stancl\Tenancy\Tests\Etc\CacheService; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Tests\Etc\SpecificCacheStoreService; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\CacheManager as TenancyCacheManager; +use Stancl\Tenancy\Tests\Etc\SpecificCacheStoreService; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; beforeEach(function () { @@ -32,6 +32,9 @@ afterEach(function () { PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; + PrefixCacheTenancyBootstrapper::$prefixGenerators = []; + + TenancyCacheManager::$addTags = true; }); test('Tenancy overrides CacheManager', function() { From 5849afa4c8b70fdcb668ec0d6ce98f3cfd53ce2c Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 7 Apr 2023 12:03:55 +0200 Subject: [PATCH 096/155] Use `$this->config` instead of `config()` --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index be4e952ed..7a84b39d5 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -64,7 +64,7 @@ public function getStorePrefix(string $store, Tenant $tenant): string return static::$prefixGenerators[$store]($tenant); } - return $this->originalPrefixes[$store] . config('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + return $this->originalPrefixes[$store] . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void From 7ebfc375d6ef0f43311544b26750020b9f905a6f Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 11 Apr 2023 14:28:28 +0200 Subject: [PATCH 097/155] Disable cache tagging by default, add CacheTagBootstrapper --- src/Bootstrappers/CacheTagBootstrapper.php | 22 ++++++++++++++++++++++ src/CacheManager.php | 2 +- tests/BootstrapperTest.php | 7 ++----- tests/CacheManagerTest.php | 5 ++--- tests/GlobalCacheTest.php | 7 ++++--- 5 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 src/Bootstrappers/CacheTagBootstrapper.php diff --git a/src/Bootstrappers/CacheTagBootstrapper.php b/src/Bootstrappers/CacheTagBootstrapper.php new file mode 100644 index 000000000..3721e9db7 --- /dev/null +++ b/src/Bootstrappers/CacheTagBootstrapper.php @@ -0,0 +1,22 @@ +mockConsoleOutput = false; @@ -84,11 +83,9 @@ }); test('cache data is separated', function () { - CacheManager::$addTags = true; - config([ 'tenancy.bootstrappers' => [ - PrefixCacheTenancyBootstrapper::class, + CacheTagBootstrapper::class, ], 'cache.default' => 'redis', ]); diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index 7b1b99da7..ff8a853b8 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -2,16 +2,15 @@ declare(strict_types=1); -use Stancl\Tenancy\CacheManager; use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Bootstrappers\CacheTagBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => []]); + config(['tenancy.bootstrappers' => [CacheTagBootstrapper::class]]); - CacheManager::$addTags = true; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index c4fcb0e54..f59ea4010 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -2,16 +2,17 @@ declare(strict_types=1); +use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyEnded; -use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Facades\GlobalCache; +use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Tests\Etc\Tenant; +use Stancl\Tenancy\Bootstrappers\CacheTagBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => []]); + config(['tenancy.bootstrappers' => [CacheTagBootstrapper::class]]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); From 52dabed8788f12407c6ea3477903196393613b70 Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Tue, 11 Apr 2023 12:29:44 +0000 Subject: [PATCH 098/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/CacheTagBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/CacheTagBootstrapper.php b/src/Bootstrappers/CacheTagBootstrapper.php index 3721e9db7..73adf0224 100644 --- a/src/Bootstrappers/CacheTagBootstrapper.php +++ b/src/Bootstrappers/CacheTagBootstrapper.php @@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Bootstrappers; use Stancl\Tenancy\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Contracts\Tenant; class CacheTagBootstrapper implements TenancyBootstrapper { From 70051e70b3b0fc79db7a89a4ee4ad1d8bb04796b Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 11 Apr 2023 15:01:08 +0200 Subject: [PATCH 099/155] Rename bootstrapper --- ...CacheTagBootstrapper.php => CacheTaggingBootstrapper.php} | 5 ++++- tests/BootstrapperTest.php | 4 ++-- tests/CacheManagerTest.php | 4 ++-- tests/GlobalCacheTest.php | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) rename src/Bootstrappers/{CacheTagBootstrapper.php => CacheTaggingBootstrapper.php} (78%) diff --git a/src/Bootstrappers/CacheTagBootstrapper.php b/src/Bootstrappers/CacheTaggingBootstrapper.php similarity index 78% rename from src/Bootstrappers/CacheTagBootstrapper.php rename to src/Bootstrappers/CacheTaggingBootstrapper.php index 73adf0224..57a3502be 100644 --- a/src/Bootstrappers/CacheTagBootstrapper.php +++ b/src/Bootstrappers/CacheTaggingBootstrapper.php @@ -8,7 +8,10 @@ use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; -class CacheTagBootstrapper implements TenancyBootstrapper +/** + * Separate tenant cache using tagging. + */ +class CacheTaggingBootstrapper implements TenancyBootstrapper { public function bootstrap(Tenant $tenant): void { diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 70501def6..af6034793 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -28,7 +28,7 @@ use Stancl\Tenancy\Tests\Etc\TestingBroadcaster; use Stancl\Tenancy\Listeners\DeleteTenantStorage; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Bootstrappers\CacheTagBootstrapper; +use Stancl\Tenancy\Bootstrappers\CacheTaggingBootstrapper; use Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper; @@ -85,7 +85,7 @@ test('cache data is separated', function () { config([ 'tenancy.bootstrappers' => [ - CacheTagBootstrapper::class, + CacheTaggingBootstrapper::class, ], 'cache.default' => 'redis', ]); diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index ff8a853b8..b3930756a 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -6,10 +6,10 @@ use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Bootstrappers\CacheTagBootstrapper; +use Stancl\Tenancy\Bootstrappers\CacheTaggingBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => [CacheTagBootstrapper::class]]); + config(['tenancy.bootstrappers' => [CacheTaggingBootstrapper::class]]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index f59ea4010..465d7bd77 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -9,10 +9,10 @@ use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Bootstrappers\CacheTagBootstrapper; +use Stancl\Tenancy\Bootstrappers\CacheTaggingBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => [CacheTagBootstrapper::class]]); + config(['tenancy.bootstrappers' => [CacheTaggingBootstrapper::class]]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); From 2d0ee2c7cd869e650b1fae4ceb318dbed2ec82b6 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 12 Apr 2023 07:17:29 +0200 Subject: [PATCH 100/155] Improve CacheManager --- src/CacheManager.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 76db6369f..0f3f19ed9 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -20,10 +20,15 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - if (! tenancy()->initialized || ! static::$addTags) { - return parent::__call($method, $parameters); + if (tenancy()->initialized && static::$addTags) { + return $this->callWithTag($method, $parameters); } + return parent::__call($method, $parameters); + } + + protected function callWithTag($method, $parameters) + { $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; if ($method === 'tags') { From 940fb1744bfe6bf58401ab21ae46966c3607f01d Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 12 Apr 2023 07:21:33 +0200 Subject: [PATCH 101/155] Move logic from separate method to __call --- src/CacheManager.php | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 0f3f19ed9..d343ac521 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -21,29 +21,24 @@ class CacheManager extends BaseCacheManager public function __call($method, $parameters) { if (tenancy()->initialized && static::$addTags) { - return $this->callWithTag($method, $parameters); - } + $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - return parent::__call($method, $parameters); - } + if ($method === 'tags') { + $count = count($parameters); - protected function callWithTag($method, $parameters) - { - $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; + if ($count !== 1) { + throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); + } - if ($method === 'tags') { - $count = count($parameters); + $names = $parameters[0]; + $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items - if ($count !== 1) { - throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); + return $this->store()->tags(array_merge($tags, $names)); } - $names = $parameters[0]; - $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items - - return $this->store()->tags(array_merge($tags, $names)); + return $this->store()->tags($tags)->$method(...$parameters); } - return $this->store()->tags($tags)->$method(...$parameters); + return parent::__call($method, $parameters); } } From 39e62c7dcf2e613a309d133af0e457076290bf62 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 12 Apr 2023 08:23:31 +0200 Subject: [PATCH 102/155] Make original prefixes customizable --- .../PrefixCacheTenancyBootstrapper.php | 14 +++++++------- tests/PrefixCacheBootstrapperTest.php | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 7a84b39d5..e9c4fe01a 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,7 +14,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { - protected array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' + public static array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' public static array $tenantCacheStores = []; // E.g. 'redis' public static array $prefixGenerators = [ // driverName => Closure(Tenant $tenant) @@ -28,22 +28,22 @@ public function __construct( public function bootstrap(Tenant $tenant): void { - $originalPrefix = $this->config->get('cache.prefix'); - foreach (static::$tenantCacheStores as $store) { - $this->originalPrefixes[$store] = $originalPrefix; + static::$originalPrefixes[$store] ??= $this->config->get('cache.prefix'); + } + foreach (static::$tenantCacheStores as $store) { $this->setCachePrefix($store, $this->getStorePrefix($store, $tenant)); } } public function revert(): void { - foreach ($this->originalPrefixes as $driver => $prefix) { + foreach (static::$originalPrefixes as $driver => $prefix) { $this->setCachePrefix($driver, $prefix); } - $this->originalPrefixes = []; + static::$originalPrefixes = []; } protected function setCachePrefix(string $driver, string|null $prefix): void @@ -64,7 +64,7 @@ public function getStorePrefix(string $store, Tenant $tenant): string return static::$prefixGenerators[$store]($tenant); } - return $this->originalPrefixes[$store] . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + return static::$originalPrefixes[$store] . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index d9a0afb5b..d64502f7c 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -23,6 +23,7 @@ PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerators = []; + PrefixCacheTenancyBootstrapper::$originalPrefixes = []; TenancyCacheManager::$addTags = false; @@ -33,6 +34,7 @@ afterEach(function () { PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; PrefixCacheTenancyBootstrapper::$prefixGenerators = []; + PrefixCacheTenancyBootstrapper::$originalPrefixes = []; TenancyCacheManager::$addTags = true; }); @@ -339,3 +341,18 @@ expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); tenancy()->end(); }); + +test('stores can have different original prefixes', function() { + config(['cache.default' => 'redis']); + config(['cache.stores.redis2' => config('cache.stores.redis')]); + config(['cache.prefix' => $defaultOriginalPrefix = 'default_prefix_']); + + // The prefix specified for a store in PrefixCacheTenancyBootstrapper::$originalPrefixes + // Will be used as the original prefix for that store instead of `config('cache.prefix')` + PrefixCacheTenancyBootstrapper::$originalPrefixes = ['redis2' => $customOriginalPrefix = 'redis2_prefix_']; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; + + tenancy()->initialize(Tenant::create()); + expect(cache()->store('redis')->getPrefix())->toStartWith($defaultOriginalPrefix); + expect(cache()->store('redis2')->getPrefix())->toStartWith($customOriginalPrefix); +}); From e894c782ab67624e28f6b087c6bf9aad2c525b87 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 12 Apr 2023 08:33:45 +0200 Subject: [PATCH 103/155] Add info in comment --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index e9c4fe01a..d6da07833 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,7 +14,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { - public static array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' + public static array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' (if not specified, use config('cache.prefix') as the default) public static array $tenantCacheStores = []; // E.g. 'redis' public static array $prefixGenerators = [ // driverName => Closure(Tenant $tenant) From 9d9e2b32cef15c7aff9697d403b1334470b6ab61 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 12 Apr 2023 09:10:23 +0200 Subject: [PATCH 104/155] Add defaultPrefix property --- src/Bootstrappers/PrefixCacheTenancyBootstrapper.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index d6da07833..fe6650ca8 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,6 +14,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { + protected string|null $defaultPrefix = null; public static array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' (if not specified, use config('cache.prefix') as the default) public static array $tenantCacheStores = []; // E.g. 'redis' public static array $prefixGenerators = [ @@ -28,8 +29,10 @@ public function __construct( public function bootstrap(Tenant $tenant): void { + $this->defaultPrefix = $this->config->get('cache.prefix'); + foreach (static::$tenantCacheStores as $store) { - static::$originalPrefixes[$store] ??= $this->config->get('cache.prefix'); + static::$originalPrefixes[$store] ??= $this->defaultPrefix; } foreach (static::$tenantCacheStores as $store) { @@ -56,6 +59,10 @@ protected function setCachePrefix(string $driver, string|null $prefix): void // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container Cache::clearResolvedInstances(); + + // Now that the store uses the passed prefix + // Set the configured prefix back to the default one + $this->config->set('cache.prefix', $this->defaultPrefix); } public function getStorePrefix(string $store, Tenant $tenant): string @@ -64,7 +71,7 @@ public function getStorePrefix(string $store, Tenant $tenant): string return static::$prefixGenerators[$store]($tenant); } - return static::$originalPrefixes[$store] . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + return (static::$originalPrefixes[$store] ?? $this->defaultPrefix) . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void From 35b0dea2702c4b5cfc726ace6db52cdb64495ed8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 12 Apr 2023 09:40:00 +0200 Subject: [PATCH 105/155] Use `$this->app` instead of `app()` --- tests/PrefixCacheBootstrapperTest.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index d64502f7c..f0a046412 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -167,7 +167,7 @@ test('cache is prefixed correctly when using a repository injected in a singleton', function () { $this->app->singleton(CacheService::class); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe('central-value'); @@ -176,13 +176,13 @@ tenancy()->initialize($tenant1); expect(cache('key'))->toBeNull(); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache('key'))->toBeNull(); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); @@ -200,7 +200,7 @@ return new SpecificCacheStoreService($this->app->make(CacheManager::class), $cacheStore); }); - app()->make(SpecificCacheStoreService::class)->handle(); + $this->app->make(SpecificCacheStoreService::class)->handle(); expect(cache()->store($cacheStore)->get('key'))->toBe('central-value'); $tenant1 = Tenant::create(); @@ -209,13 +209,13 @@ // The store isn't prefixed, so the cache isn't separated expect(cache()->store($cacheStore)->get('key'))->toBe('central-value'); - app()->make(SpecificCacheStoreService::class)->handle(); + $this->app->make(SpecificCacheStoreService::class)->handle(); expect(cache()->store($cacheStore)->get('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache()->store($cacheStore)->get('key'))->toBe($tenant1->getTenantKey()); - app()->make(SpecificCacheStoreService::class)->handle(); + $this->app->make(SpecificCacheStoreService::class)->handle(); expect(cache()->store($cacheStore)->get('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); @@ -228,7 +228,7 @@ $this->app->singleton(CacheService::class); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($centralValue = 'central-value'); $tenant1 = Tenant::create(); @@ -237,13 +237,13 @@ tenancy()->initialize($tenant1); expect(cache('key'))->toBeNull(); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache('key'))->toBeNull(); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); @@ -258,7 +258,7 @@ $this->app->singleton(CacheService::class); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe('central-value'); $tenant1 = Tenant::create(); @@ -267,13 +267,13 @@ // The cache isn't prefixed, so it isn't separated expect(cache('key'))->toBe('central-value'); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); tenancy()->initialize($tenant2); expect(cache('key'))->toBe($tenant1->getTenantKey()); - app()->make(CacheService::class)->handle(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); From 4ab692bb057e287d516ff6df1bb8ecb7e86f8fd2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 07:07:11 +0200 Subject: [PATCH 106/155] Rename bootstrapper --- ...CacheTaggingBootstrapper.php => CacheTagsBootstrapper.php} | 4 +++- tests/BootstrapperTest.php | 4 ++-- tests/CacheManagerTest.php | 4 ++-- tests/GlobalCacheTest.php | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) rename src/Bootstrappers/{CacheTaggingBootstrapper.php => CacheTagsBootstrapper.php} (85%) diff --git a/src/Bootstrappers/CacheTaggingBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php similarity index 85% rename from src/Bootstrappers/CacheTaggingBootstrapper.php rename to src/Bootstrappers/CacheTagsBootstrapper.php index 57a3502be..1e9bb90d4 100644 --- a/src/Bootstrappers/CacheTaggingBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -9,9 +9,11 @@ use Stancl\Tenancy\Contracts\Tenant; /** + * todo name + * * Separate tenant cache using tagging. */ -class CacheTaggingBootstrapper implements TenancyBootstrapper +class CacheTagsBootstrapper implements TenancyBootstrapper { public function bootstrap(Tenant $tenant): void { diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index af6034793..a71b54d45 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -28,7 +28,7 @@ use Stancl\Tenancy\Tests\Etc\TestingBroadcaster; use Stancl\Tenancy\Listeners\DeleteTenantStorage; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Bootstrappers\CacheTaggingBootstrapper; +use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper; use Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper; @@ -85,7 +85,7 @@ test('cache data is separated', function () { config([ 'tenancy.bootstrappers' => [ - CacheTaggingBootstrapper::class, + CacheTagsBootstrapper::class, ], 'cache.default' => 'redis', ]); diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index b3930756a..f0e8c2a11 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -6,10 +6,10 @@ use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Bootstrappers\CacheTaggingBootstrapper; +use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => [CacheTaggingBootstrapper::class]]); + config(['tenancy.bootstrappers' => [CacheTagsBootstrapper::class]]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index 465d7bd77..6106a13c0 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -9,10 +9,10 @@ use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Bootstrappers\CacheTaggingBootstrapper; +use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => [CacheTaggingBootstrapper::class]]); + config(['tenancy.bootstrappers' => [CacheTagsBootstrapper::class]]); Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); From c9ba00c1fc0cf224b523091e7fa2e212e46a466a Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Thu, 13 Apr 2023 05:07:38 +0000 Subject: [PATCH 107/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/CacheTagsBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 1e9bb90d4..1af367e03 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -9,7 +9,7 @@ use Stancl\Tenancy\Contracts\Tenant; /** - * todo name + * todo name. * * Separate tenant cache using tagging. */ From 8ac4d87e942939c67ebb8ebe215a9c7414461321 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 07:47:18 +0200 Subject: [PATCH 108/155] Use a single original prefix --- .../PrefixCacheTenancyBootstrapper.php | 19 ++++++------------- tests/PrefixCacheBootstrapperTest.php | 17 ----------------- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index fe6650ca8..826ebd59b 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -14,8 +14,7 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { - protected string|null $defaultPrefix = null; - public static array $originalPrefixes = []; // E.g. 'redis' => 'redis_prefix_' (if not specified, use config('cache.prefix') as the default) + protected string|null $originalPrefix = null; public static array $tenantCacheStores = []; // E.g. 'redis' public static array $prefixGenerators = [ // driverName => Closure(Tenant $tenant) @@ -29,11 +28,7 @@ public function __construct( public function bootstrap(Tenant $tenant): void { - $this->defaultPrefix = $this->config->get('cache.prefix'); - - foreach (static::$tenantCacheStores as $store) { - static::$originalPrefixes[$store] ??= $this->defaultPrefix; - } + $this->originalPrefix = $this->config->get('cache.prefix'); foreach (static::$tenantCacheStores as $store) { $this->setCachePrefix($store, $this->getStorePrefix($store, $tenant)); @@ -42,11 +37,9 @@ public function bootstrap(Tenant $tenant): void public function revert(): void { - foreach (static::$originalPrefixes as $driver => $prefix) { - $this->setCachePrefix($driver, $prefix); + foreach (static::$tenantCacheStores as $store) { + $this->setCachePrefix($store, $this->originalPrefix); } - - static::$originalPrefixes = []; } protected function setCachePrefix(string $driver, string|null $prefix): void @@ -62,7 +55,7 @@ protected function setCachePrefix(string $driver, string|null $prefix): void // Now that the store uses the passed prefix // Set the configured prefix back to the default one - $this->config->set('cache.prefix', $this->defaultPrefix); + $this->config->set('cache.prefix', $this->originalPrefix); } public function getStorePrefix(string $store, Tenant $tenant): string @@ -71,7 +64,7 @@ public function getStorePrefix(string $store, Tenant $tenant): string return static::$prefixGenerators[$store]($tenant); } - return (static::$originalPrefixes[$store] ?? $this->defaultPrefix) . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + return $this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index f0a046412..f0d0ac40a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -23,7 +23,6 @@ PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerators = []; - PrefixCacheTenancyBootstrapper::$originalPrefixes = []; TenancyCacheManager::$addTags = false; @@ -34,7 +33,6 @@ afterEach(function () { PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; PrefixCacheTenancyBootstrapper::$prefixGenerators = []; - PrefixCacheTenancyBootstrapper::$originalPrefixes = []; TenancyCacheManager::$addTags = true; }); @@ -341,18 +339,3 @@ expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); tenancy()->end(); }); - -test('stores can have different original prefixes', function() { - config(['cache.default' => 'redis']); - config(['cache.stores.redis2' => config('cache.stores.redis')]); - config(['cache.prefix' => $defaultOriginalPrefix = 'default_prefix_']); - - // The prefix specified for a store in PrefixCacheTenancyBootstrapper::$originalPrefixes - // Will be used as the original prefix for that store instead of `config('cache.prefix')` - PrefixCacheTenancyBootstrapper::$originalPrefixes = ['redis2' => $customOriginalPrefix = 'redis2_prefix_']; - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; - - tenancy()->initialize(Tenant::create()); - expect(cache()->store('redis')->getPrefix())->toStartWith($defaultOriginalPrefix); - expect(cache()->store('redis2')->getPrefix())->toStartWith($customOriginalPrefix); -}); From 740d4e78d85e5def9d1135b830fdc3abb502a8ee Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 12:46:33 +0200 Subject: [PATCH 109/155] Update prefix generator logic + tests --- .../PrefixCacheTenancyBootstrapper.php | 38 +++++++++---------- tests/PrefixCacheBootstrapperTest.php | 26 +++++++------ 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index 826ebd59b..c03738e8f 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -15,10 +15,8 @@ class PrefixCacheTenancyBootstrapper implements TenancyBootstrapper { protected string|null $originalPrefix = null; - public static array $tenantCacheStores = []; // E.g. 'redis' - public static array $prefixGenerators = [ - // driverName => Closure(Tenant $tenant) - ]; + public static array $tenantCacheStores = []; // E.g. ['redis'] + public static Closure|null $prefixGenerator = null; public function __construct( protected ConfigRepository $config, @@ -30,8 +28,19 @@ public function bootstrap(Tenant $tenant): void { $this->originalPrefix = $this->config->get('cache.prefix'); + // Use default prefix generator if the prefix generator isn't set + static::$prefixGenerator ??= function (Tenant $tenant) { + return $this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + }; + + $prefix = (static::$prefixGenerator)($tenant); + foreach (static::$tenantCacheStores as $store) { - $this->setCachePrefix($store, $this->getStorePrefix($store, $tenant)); + $this->setCachePrefix($store, $prefix); + + // Now that the store uses the passed prefix + // Set the configured prefix back to the default one + $this->config->set('cache.prefix', $this->originalPrefix); } } @@ -40,6 +49,8 @@ public function revert(): void foreach (static::$tenantCacheStores as $store) { $this->setCachePrefix($store, $this->originalPrefix); } + + static::$prefixGenerator = null; } protected function setCachePrefix(string $driver, string|null $prefix): void @@ -52,24 +63,11 @@ protected function setCachePrefix(string $driver, string|null $prefix): void // It is needed when a call to the facade has been made before bootstrapping tenancy // The facade has its own cache, separate from the container Cache::clearResolvedInstances(); - - // Now that the store uses the passed prefix - // Set the configured prefix back to the default one - $this->config->set('cache.prefix', $this->originalPrefix); - } - - public function getStorePrefix(string $store, Tenant $tenant): string - { - if (isset(static::$prefixGenerators[$store])) { - return static::$prefixGenerators[$store]($tenant); - } - - return $this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); } - public static function generatePrefixUsing(string $store, Closure $prefixGenerator): void + public static function generatePrefixUsing(Closure $prefixGenerator): void { - static::$prefixGenerators[$store] = $prefixGenerator; + static::$prefixGenerator = $prefixGenerator; } /** diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index f0d0ac40a..da4800dad 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -22,7 +22,7 @@ ]); PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; - PrefixCacheTenancyBootstrapper::$prefixGenerators = []; + PrefixCacheTenancyBootstrapper::$prefixGenerator = null; TenancyCacheManager::$addTags = false; @@ -32,7 +32,7 @@ afterEach(function () { PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; - PrefixCacheTenancyBootstrapper::$prefixGenerators = []; + PrefixCacheTenancyBootstrapper::$prefixGenerator = null; TenancyCacheManager::$addTags = true; }); @@ -74,9 +74,12 @@ $tenantOnePrefix = $originalPrefix . $prefixBase . $tenant1->getTenantKey(); tenancy()->initialize($tenant1); + // Default prefix generator + $prefixGenerator = PrefixCacheTenancyBootstrapper::$prefixGenerator; + cache()->set('key', 'tenantone-value'); - $expectPrefixToBe($tenantOnePrefix); + $expectPrefixToBe($prefixGenerator($tenant1)); $tenantTwoPrefix = $originalPrefix . $prefixBase . $tenant2->getTenantKey(); @@ -84,7 +87,7 @@ cache()->set('key', 'tenanttwo-value'); - $expectPrefixToBe($tenantTwoPrefix); + $expectPrefixToBe($prefixGenerator($tenant2)); // Prefix gets reverted to default after ending tenancy tenancy()->end(); @@ -287,11 +290,11 @@ // The prefix is the same for both drivers in the central context $tenant = Tenant::create(); $defaultPrefix = cache()->store()->getPrefix(); - $expectedPrefix = config('cache.prefix', '') . config('tenancy.cache.prefix_base', '') . $tenant->getTenantKey(); expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); tenancy()->initialize($tenant); + $expectedPrefix = (PrefixCacheTenancyBootstrapper::$prefixGenerator)($tenant); // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); @@ -305,19 +308,17 @@ config(['cache.default' => 'redis']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; - expect(PrefixCacheTenancyBootstrapper::$prefixGenerators)->not()->toHaveKey('redis'); - // Add custom prefix generator for the 'redis' store - PrefixCacheTenancyBootstrapper::generatePrefixUsing('redis', $generateTenantPrefix = function (Tenant $tenant) { + PrefixCacheTenancyBootstrapper::generatePrefixUsing($customPrefixGenerator = function (Tenant $tenant) { return 'redis_tenant_cache_' . $tenant->getTenantKey(); }); - expect(PrefixCacheTenancyBootstrapper::$prefixGenerators)->toHaveKey('redis'); + expect(PrefixCacheTenancyBootstrapper::$prefixGenerator)->toBe($customPrefixGenerator); tenancy()->initialize($tenant = Tenant::create()); // Expect the 'redis' store to use the prefix generated by the custom generator - expect(cache()->store('redis')->getPrefix())->toBe($generateTenantPrefix($tenant) . ':'); + expect(cache()->store('redis')->getPrefix())->toBe($customPrefixGenerator($tenant) . ':'); tenancy()->end(); }); @@ -327,15 +328,18 @@ // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); $tenant = Tenant::create(); - $expectedPrefix = config('cache.prefix', '') . config('tenancy.cache.prefix_base', '') . $tenant->getTenantKey(); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; // Don't add a generator for 'redis2' // Let the prefix get created using the default approach tenancy()->initialize($tenant); + + $expectedPrefix = (PrefixCacheTenancyBootstrapper::$prefixGenerator)($tenant); + expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); // Other stores without a prefix generator use the default generator too expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); + tenancy()->end(); }); From 651302943f2b7bc626b76463166688423a640318 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 13:10:41 +0200 Subject: [PATCH 110/155] Correct `$addTags` reset in a test --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index da4800dad..c4588c92f 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -34,7 +34,7 @@ PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; - TenancyCacheManager::$addTags = true; + TenancyCacheManager::$addTags = false; }); test('Tenancy overrides CacheManager', function() { From 9e15110ad932e8804461c3acbfc55531444732d8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 13:36:58 +0200 Subject: [PATCH 111/155] Update cache tests so that both prefixing and tagging is covered --- tests/BootstrapperTest.php | 27 +++++++++++++++++----- tests/GlobalCacheTest.php | 46 +++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index a71b54d45..9e5f8c72b 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -36,6 +36,8 @@ use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\BroadcastTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; +use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; +use Stancl\Tenancy\CacheManager; beforeEach(function () { $this->mockConsoleOutput = false; @@ -82,12 +84,19 @@ expect(DB::table('users')->first()->name)->toBe('Foo'); }); -test('cache data is separated', function () { +test('cache data is separated', function (string $bootstrapper) { + $cacheDriver = 'redis'; + + if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { + CacheManager::$addTags = false; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + } else { + CacheManager::$addTags = true; + } + config([ - 'tenancy.bootstrappers' => [ - CacheTagsBootstrapper::class, - ], - 'cache.default' => 'redis', + 'tenancy.bootstrappers' => [$bootstrapper], + 'cache.default' => $cacheDriver, ]); $tenant1 = Tenant::create(); @@ -121,7 +130,13 @@ // Asset central is still the same expect(Cache::get('foo'))->toBe('central'); -}); + + // Reset the static property + CacheManager::$addTags = false; +})->with([ + 'tagging' => CacheTagsBootstrapper::class, + 'prefixing' => PrefixCacheTenancyBootstrapper::class, +])->group('bootstrapper'); test('redis data is separated', function () { config(['tenancy.bootstrappers' => [ diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index 6106a13c0..44e14dfeb 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Stancl\Tenancy\CacheManager; use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Events\TenancyEnded; @@ -10,15 +11,28 @@ use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper; +use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; beforeEach(function () { - config(['tenancy.bootstrappers' => [CacheTagsBootstrapper::class]]); - Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); -test('global cache manager stores data in global cache', function () { +test('global cache manager stores data in global cache', function (string $bootstrapper) { + $cacheDriver = 'redis'; + + if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { + CacheManager::$addTags = false; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + } else { + CacheManager::$addTags = true; + } + + config([ + 'tenancy.bootstrappers' => [$bootstrapper], + 'cache.default' => $cacheDriver, + ]); + expect(cache('foo'))->toBe(null); GlobalCache::put(['foo' => 'bar'], 1); expect(GlobalCache::get('foo'))->toBe('bar'); @@ -46,9 +60,26 @@ tenancy()->initialize($tenant1); expect(cache('def'))->toBe('ghi'); -}); +})->with([ + 'tagging' => CacheTagsBootstrapper::class, + 'prefixing' => PrefixCacheTenancyBootstrapper::class, +]); + +test('the global_cache helper supports the same syntax as the cache helper', function (string $bootstrapper) { + $cacheDriver = 'redis'; + + if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { + CacheManager::$addTags = false; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + } else { + CacheManager::$addTags = true; + } + + config([ + 'tenancy.bootstrappers' => [$bootstrapper], + 'cache.default' => $cacheDriver, + ]); -test('the global_cache helper supports the same syntax as the cache helper', function () { $tenant = Tenant::create(); $tenant->enter(); @@ -61,4 +92,7 @@ expect(global_cache()->get('foo'))->toBe('baz'); expect(cache('foo'))->toBe(null); // tenant cache is not affected -}); +})->with([ + 'tagging' => CacheTagsBootstrapper::class, + 'prefixing' => PrefixCacheTenancyBootstrapper::class, +]); From dd57d9bbdc7faa63624b796d3973506a499287e2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 13:44:00 +0200 Subject: [PATCH 112/155] Simplify cache tests --- tests/BootstrapperTest.php | 8 +++++--- tests/GlobalCacheTest.php | 32 ++++++-------------------------- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 9e5f8c72b..72ad55de4 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -41,6 +41,7 @@ beforeEach(function () { $this->mockConsoleOutput = false; + CacheManager::$addTags = false; Event::listen( TenantCreated::class, @@ -53,6 +54,10 @@ Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +afterEach(function () { + CacheManager::$addTags = false; +}); + test('database data is separated', function () { config(['tenancy.bootstrappers' => [ DatabaseTenancyBootstrapper::class, @@ -88,10 +93,7 @@ $cacheDriver = 'redis'; if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { - CacheManager::$addTags = false; PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; - } else { - CacheManager::$addTags = true; } config([ diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index 44e14dfeb..f57cc4f34 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -14,24 +14,16 @@ use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; beforeEach(function () { + CacheManager::$addTags = false; + config(['cache.default' => $cacheDriver = 'redis']); + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); test('global cache manager stores data in global cache', function (string $bootstrapper) { - $cacheDriver = 'redis'; - - if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { - CacheManager::$addTags = false; - PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; - } else { - CacheManager::$addTags = true; - } - - config([ - 'tenancy.bootstrappers' => [$bootstrapper], - 'cache.default' => $cacheDriver, - ]); + config(['tenancy.bootstrappers' => [$bootstrapper]]); expect(cache('foo'))->toBe(null); GlobalCache::put(['foo' => 'bar'], 1); @@ -66,19 +58,7 @@ ]); test('the global_cache helper supports the same syntax as the cache helper', function (string $bootstrapper) { - $cacheDriver = 'redis'; - - if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { - CacheManager::$addTags = false; - PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; - } else { - CacheManager::$addTags = true; - } - - config([ - 'tenancy.bootstrappers' => [$bootstrapper], - 'cache.default' => $cacheDriver, - ]); + config(['tenancy.bootstrappers' => [$bootstrapper]]); $tenant = Tenant::create(); $tenant->enter(); From 3481e24c7d36dbdcc5e010a995f367ba38a86c04 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 13 Apr 2023 13:45:29 +0200 Subject: [PATCH 113/155] Delete afterEach --- tests/BootstrapperTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 72ad55de4..36614c34e 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -54,10 +54,6 @@ Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); -afterEach(function () { - CacheManager::$addTags = false; -}); - test('database data is separated', function () { config(['tenancy.bootstrappers' => [ DatabaseTenancyBootstrapper::class, From 0c1912b9c58d8e911e5f3a6a0705e9e5342c9154 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Fri, 14 Apr 2023 12:33:08 +0200 Subject: [PATCH 114/155] Small testing improvements --- tests/BootstrapperTest.php | 23 ++++++++++------------- tests/GlobalCacheTest.php | 8 ++++---- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 36614c34e..901587f6b 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -42,6 +42,7 @@ beforeEach(function () { $this->mockConsoleOutput = false; CacheManager::$addTags = false; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; Event::listen( TenantCreated::class, @@ -54,6 +55,11 @@ Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +afterEach(function () { + CacheManager::$addTags = false; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; +}); + test('database data is separated', function () { config(['tenancy.bootstrappers' => [ DatabaseTenancyBootstrapper::class, @@ -86,15 +92,9 @@ }); test('cache data is separated', function (string $bootstrapper) { - $cacheDriver = 'redis'; - - if ($bootstrapper === PrefixCacheTenancyBootstrapper::class) { - PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; - } - config([ 'tenancy.bootstrappers' => [$bootstrapper], - 'cache.default' => $cacheDriver, + 'cache.default' => 'redis', ]); $tenant1 = Tenant::create(); @@ -128,13 +128,10 @@ // Asset central is still the same expect(Cache::get('foo'))->toBe('central'); - - // Reset the static property - CacheManager::$addTags = false; })->with([ - 'tagging' => CacheTagsBootstrapper::class, - 'prefixing' => PrefixCacheTenancyBootstrapper::class, -])->group('bootstrapper'); + CacheTagsBootstrapper::class, + PrefixCacheTenancyBootstrapper::class, +]); test('redis data is separated', function () { config(['tenancy.bootstrappers' => [ diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index f57cc4f34..e7b026283 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -53,8 +53,8 @@ tenancy()->initialize($tenant1); expect(cache('def'))->toBe('ghi'); })->with([ - 'tagging' => CacheTagsBootstrapper::class, - 'prefixing' => PrefixCacheTenancyBootstrapper::class, + CacheTagsBootstrapper::class, + PrefixCacheTenancyBootstrapper::class, ]); test('the global_cache helper supports the same syntax as the cache helper', function (string $bootstrapper) { @@ -73,6 +73,6 @@ expect(cache('foo'))->toBe(null); // tenant cache is not affected })->with([ - 'tagging' => CacheTagsBootstrapper::class, - 'prefixing' => PrefixCacheTenancyBootstrapper::class, + CacheTagsBootstrapper::class, + PrefixCacheTenancyBootstrapper::class, ]); From 13b85a2d3be9041d069f00f6e7306d4a9ad32290 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 12:36:59 +0200 Subject: [PATCH 115/155] Set `cache.default` in beforeEach --- tests/BootstrapperTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 901587f6b..fe62a9ae7 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -42,7 +42,8 @@ beforeEach(function () { $this->mockConsoleOutput = false; CacheManager::$addTags = false; - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + config(['cache.default' => $cacheDriver = 'redis']); + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; Event::listen( TenantCreated::class, @@ -92,9 +93,10 @@ }); test('cache data is separated', function (string $bootstrapper) { + expect(config('cache.default'))->toBe('redis'); + config([ 'tenancy.bootstrappers' => [$bootstrapper], - 'cache.default' => 'redis', ]); $tenant1 = Tenant::create(); From 52d9643535e1bc0a507cae4afb54af484208f999 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 14:34:54 +0200 Subject: [PATCH 116/155] Update cache prefixing and tests --- .../PrefixCacheTenancyBootstrapper.php | 16 +++---- tests/PrefixCacheBootstrapperTest.php | 46 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php index c03738e8f..ad0ea6f4a 100644 --- a/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php +++ b/src/Bootstrappers/PrefixCacheTenancyBootstrapper.php @@ -28,12 +28,7 @@ public function bootstrap(Tenant $tenant): void { $this->originalPrefix = $this->config->get('cache.prefix'); - // Use default prefix generator if the prefix generator isn't set - static::$prefixGenerator ??= function (Tenant $tenant) { - return $this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); - }; - - $prefix = (static::$prefixGenerator)($tenant); + $prefix = $this->generatePrefix($tenant); foreach (static::$tenantCacheStores as $store) { $this->setCachePrefix($store, $prefix); @@ -49,8 +44,6 @@ public function revert(): void foreach (static::$tenantCacheStores as $store) { $this->setCachePrefix($store, $this->originalPrefix); } - - static::$prefixGenerator = null; } protected function setCachePrefix(string $driver, string|null $prefix): void @@ -65,6 +58,13 @@ protected function setCachePrefix(string $driver, string|null $prefix): void Cache::clearResolvedInstances(); } + public function generatePrefix(Tenant $tenant): string + { + $defaultPrefix = $this->originalPrefix . $this->config->get('tenancy.cache.prefix_base') . $tenant->getTenantKey(); + + return static::$prefixGenerator ? (static::$prefixGenerator)($tenant) : $defaultPrefix; + } + public static function generatePrefixUsing(Closure $prefixGenerator): void { static::$prefixGenerator = $prefixGenerator; diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index c4588c92f..3de493aba 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -33,8 +33,6 @@ afterEach(function () { PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; - - TenancyCacheManager::$addTags = false; }); test('Tenancy overrides CacheManager', function() { @@ -60,38 +58,35 @@ test('correct cache prefix is used in all contexts', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); - $expectPrefixToBe = function(string $prefix) { + $getDefaultPrefixForTenant = fn (Tenant $tenant) => $originalPrefix . $prefixBase . $tenant->getTenantKey(); + $generatePrefixForTenant = function (Tenant $tenant) { + return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); + }; + + $expectCachePrefixToBe = function (string $prefix) { expect($prefix . ':') // RedisStore suffixes prefix with ':' ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); }; - $expectPrefixToBe($originalPrefix); + $expectCachePrefixToBe($originalPrefix); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); - $tenantOnePrefix = $originalPrefix . $prefixBase . $tenant1->getTenantKey(); - tenancy()->initialize($tenant1); - // Default prefix generator - $prefixGenerator = PrefixCacheTenancyBootstrapper::$prefixGenerator; - cache()->set('key', 'tenantone-value'); - - $expectPrefixToBe($prefixGenerator($tenant1)); - - $tenantTwoPrefix = $originalPrefix . $prefixBase . $tenant2->getTenantKey(); + expect($generatePrefixForTenant($tenant1))->toBe($tenantOnePrefix = $getDefaultPrefixForTenant($tenant1)); + $expectCachePrefixToBe($tenantOnePrefix); tenancy()->initialize($tenant2); - cache()->set('key', 'tenanttwo-value'); - - $expectPrefixToBe($prefixGenerator($tenant2)); + expect($generatePrefixForTenant($tenant2))->toBe($tenantTwoPrefix = $getDefaultPrefixForTenant($tenant2)); + $expectCachePrefixToBe($tenantTwoPrefix); // Prefix gets reverted to default after ending tenancy tenancy()->end(); - $expectPrefixToBe($originalPrefix); + $expectCachePrefixToBe($originalPrefix); // Assert tenant's data is accessible using the prefix from the central context config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually @@ -282,6 +277,10 @@ }); test('non default stores get prefixed too', function () { + $generatePrefixForTenant = function (Tenant $tenant) { + return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); + }; + config(['cache.stores.redis2' => config('cache.stores.redis')]); // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); @@ -294,7 +293,8 @@ expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); tenancy()->initialize($tenant); - $expectedPrefix = (PrefixCacheTenancyBootstrapper::$prefixGenerator)($tenant); + + $expectedPrefix = $generatePrefixForTenant($tenant); // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); @@ -327,7 +327,11 @@ config(['cache.stores.redis2' => config('cache.stores.redis')]); // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); + $originalPrefix = config('cache.prefix'); + $prefixBase = config('tenancy.cache.prefix_base'); + $tenant = Tenant::create(); + $defaultPrefix = $originalPrefix . $prefixBase . $tenant->getTenantKey(); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; @@ -335,11 +339,9 @@ // Let the prefix get created using the default approach tenancy()->initialize($tenant); - $expectedPrefix = (PrefixCacheTenancyBootstrapper::$prefixGenerator)($tenant); - - expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); + expect(cache()->store()->getPrefix())->toBe($defaultPrefix . ':'); // Other stores without a prefix generator use the default generator too - expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); + expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix . ':'); tenancy()->end(); }); From 859b2c534a57a53541ff0d6d3569affd826b7e7d Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 14:49:23 +0200 Subject: [PATCH 117/155] Add assertion --- tests/PrefixCacheBootstrapperTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 3de493aba..a12622d8d 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -105,6 +105,7 @@ expect(cache('foo'))->toBe('bar'); tenancy()->initialize($tenant2); + expect(cache('foo'))->not()->toBe('bar'); tenancy()->end(); tenancy()->initialize($tenant1); From d84878bd45fc4a3700aedb970d21ed27a99fb355 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 14:51:52 +0200 Subject: [PATCH 118/155] Refactor assertion --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index a12622d8d..7c7aa1506 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -122,7 +122,7 @@ $tenant2 = Tenant::create(); tenancy()->initialize($tenant2); - pest()->assertNotSame('bar', cache()->get('foo')); + expect(cache()->get('foo'))->not()->toBe('bar'); cache()->put('foo', 'xyz', 1); expect(cache()->get('foo'))->toBe('xyz'); From ce433845378d3b26ea84a273dc8afd52846a6aee Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 14:54:45 +0200 Subject: [PATCH 119/155] Refactor assertions --- tests/CacheManagerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index f0e8c2a11..744d81d20 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -58,7 +58,7 @@ $tenant2 = Tenant::create(); tenancy()->initialize($tenant2); - pest()->assertNotSame('bar', cache()->get('foo')); + expect(cache('foo'))->not()->toBe('bar'); cache()->put('foo', 'xyz', 1); expect(cache()->get('foo'))->toBe('xyz'); @@ -74,7 +74,7 @@ $tenant2 = Tenant::create(); tenancy()->initialize($tenant2); - pest()->assertNotSame('bar', cache('foo')); + expect(cache('foo'))->not()->toBe('bar'); cache(['foo' => 'xyz'], 1); expect(cache('foo'))->toBe('xyz'); From bd41ae4fe5d77ce1fda894a449914208feacbccf Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 15:06:22 +0200 Subject: [PATCH 120/155] Delete TTL from cache put calls --- tests/PrefixCacheBootstrapperTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 7c7aa1506..3869d0b0f 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -101,7 +101,7 @@ $tenant2 = Tenant::create(); tenancy()->initialize($tenant1); - cache(['foo' => 'bar'], 10); + cache(['foo' => 'bar']); expect(cache('foo'))->toBe('bar'); tenancy()->initialize($tenant2); @@ -116,7 +116,7 @@ $tenant1 = Tenant::create(); tenancy()->initialize($tenant1); - cache()->put('foo', 'bar', 1); + cache()->put('foo', 'bar'); expect(cache()->get('foo'))->toBe('bar'); $tenant2 = Tenant::create(); @@ -124,7 +124,7 @@ expect(cache()->get('foo'))->not()->toBe('bar'); - cache()->put('foo', 'xyz', 1); + cache()->put('foo', 'xyz'); expect(cache()->get('foo'))->toBe('xyz'); }); @@ -134,6 +134,7 @@ $tenant1 = Tenant::create(); tenancy()->initialize($tenant1); + expect(cache('key'))->toBeNull(); cache()->put('key', 'tenant'); expect(cache()->get('key'))->toBe('tenant'); From 90684a7d92064bd7abbbdd2e75026dfc330db159 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 15:10:06 +0200 Subject: [PATCH 121/155] Add re-initialization cache assertion --- tests/PrefixCacheBootstrapperTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 3869d0b0f..933c73da8 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -126,6 +126,9 @@ cache()->put('foo', 'xyz'); expect(cache()->get('foo'))->toBe('xyz'); + + tenancy()->initialize($tenant1); + expect(cache()->get('foo'))->toBe('bar'); }); test('central cache is persisted', function () { From 9925e491126ed1f8bd44bfca083f51954e627868 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 15:11:30 +0200 Subject: [PATCH 122/155] Assert that cache is null from the beginning --- tests/PrefixCacheBootstrapperTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 933c73da8..5c2e60d0a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -168,6 +168,8 @@ test('cache is prefixed correctly when using a repository injected in a singleton', function () { $this->app->singleton(CacheService::class); + expect(cache('key'))->toBeNull(); + $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe('central-value'); From 4c9cb7cf51b9d3002b61b567d8df39a34d4ad7cb Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 17:00:15 +0200 Subject: [PATCH 123/155] Merge the tenantCacheStores tests --- tests/PrefixCacheBootstrapperTest.php | 46 ++++++++++++++++++--------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 5c2e60d0a..d97c70931 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -225,7 +225,9 @@ expect(cache()->store($cacheStore)->get('key'))->toBe($tenant2->getTenantKey()); }); -test('stores specified in tenantCacheStores get prefixed', function() { +test('only the stores specified in tenantCacheStores get prefixed', function() { + config(['cache.stores.redis2' => config('cache.stores.redis')]); + // Make the currently used store ('redis') the only store in $tenantCacheStores PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; @@ -243,44 +245,58 @@ $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); + // Switch to an unprefixed store + config(['cache.default' => 'redis2']); + expect(cache('key'))->toBe($centralValue); + config(['cache.default' => 'redis']); + tenancy()->initialize($tenant2); expect(cache('key'))->toBeNull(); $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); - tenancy()->end(); - expect(cache('key'))->toBe($centralValue); -}); - -test('stores not specified in tenantCacheStores do not get prefixed', function() { - config(['cache.stores.redis2' => config('cache.stores.redis')]); + // Switch to an unprefixed store config(['cache.default' => 'redis2']); - // Make 'redis' the only store in $tenantCacheStores so that the current store ('redis2') doesn't get prefixed - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + expect(cache('key'))->toBe($centralValue); + // Switch back to the prefixed store + config(['cache.default' => 'redis']); - $this->app->singleton(CacheService::class); + tenancy()->end(); + expect(cache('key'))->toBe($centralValue); $this->app->make(CacheService::class)->handle(); - expect(cache('key'))->toBe('central-value'); + expect(cache('key'))->toBe($centralValue); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); + tenancy()->initialize($tenant1); - // The cache isn't prefixed, so it isn't separated - expect(cache('key'))->toBe('central-value'); + expect(cache('key'))->toBeNull(); $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); + // Switch to an unprefixed store + config(['cache.default' => 'redis2']); + expect(cache('key'))->toBe($centralValue); + // Switch back to the prefixed store + config(['cache.default' => 'redis']); + tenancy()->initialize($tenant2); - expect(cache('key'))->toBe($tenant1->getTenantKey()); + expect(cache('key'))->toBeNull(); $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); + // Switch to an unprefixed store + config(['cache.default' => 'redis2']); + expect(cache('key'))->toBe($centralValue); + // Switch back to the prefixed store + config(['cache.default' => 'redis']); + tenancy()->end(); - expect(cache('key'))->toBe($tenant2->getTenantKey()); + expect(cache('key'))->toBe($centralValue); }); test('non default stores get prefixed too', function () { From b4f4fd1d944e313b25a645b85200d8d33e9e075e Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 17:00:28 +0200 Subject: [PATCH 124/155] Fix formatting --- tests/Etc/CacheService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Etc/CacheService.php b/tests/Etc/CacheService.php index 8e5d17d32..c228d59ed 100644 --- a/tests/Etc/CacheService.php +++ b/tests/Etc/CacheService.php @@ -10,7 +10,7 @@ class CacheService { public function __construct( protected Repository $cache - ){ + ) { } public function handle(): void From 2309b833270c5c83b010ff4bd16817886991630b Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 17:05:03 +0200 Subject: [PATCH 125/155] Improve test name --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index d97c70931..490b86262 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -299,7 +299,7 @@ expect(cache('key'))->toBe($centralValue); }); -test('non default stores get prefixed too', function () { +test('non default stores get prefixed too when specified in tenantCacheStores', function () { $generatePrefixForTenant = function (Tenant $tenant) { return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); }; From ca907e68bed47cf44809ed721ee7d112422997d8 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 18:00:03 +0200 Subject: [PATCH 126/155] Improve tests --- tests/PrefixCacheBootstrapperTest.php | 39 +++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 490b86262..818bdbe7e 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -19,6 +19,7 @@ PrefixCacheTenancyBootstrapper::class ], 'cache.default' => $cacheDriver = 'redis', + 'cache.stores.redis2' => config('cache.stores.redis'), ]); PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; @@ -161,6 +162,7 @@ tenancy()->initialize($tenant1); expect($originalPrefix . $prefixBase . $tenant1->getTenantKey() . ':') + ->toBe(cache()->getPrefix()) ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); }); @@ -195,7 +197,6 @@ test('specific central cache store can be used inside a service', function () { config(['cache.default' => 'redis']); - config(['cache.stores.redis2' => config('cache.stores.redis')]); $cacheStore = 'redis2'; // Name of the non-default, central cache store that we'll use using cache()->store($cacheStore) // Service uses the 'redis2' store which is central/not prefixed (not present in PrefixCacheTenancyBootstrapper::$tenantCacheStores) @@ -226,8 +227,6 @@ }); test('only the stores specified in tenantCacheStores get prefixed', function() { - config(['cache.stores.redis2' => config('cache.stores.redis')]); - // Make the currently used store ('redis') the only store in $tenantCacheStores PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; @@ -304,7 +303,6 @@ return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); }; - config(['cache.stores.redis2' => config('cache.stores.redis')]); // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; @@ -329,25 +327,42 @@ test('cache store prefix generation can be customized', function() { config(['cache.default' => 'redis']); - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; - // Add custom prefix generator for the 'redis' store + // Use custom prefix generator PrefixCacheTenancyBootstrapper::generatePrefixUsing($customPrefixGenerator = function (Tenant $tenant) { return 'redis_tenant_cache_' . $tenant->getTenantKey(); }); expect(PrefixCacheTenancyBootstrapper::$prefixGenerator)->toBe($customPrefixGenerator); + expect(app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant = Tenant::create())) + ->toBe($customPrefixGenerator($tenant)); tenancy()->initialize($tenant = Tenant::create()); // Expect the 'redis' store to use the prefix generated by the custom generator - expect(cache()->store('redis')->getPrefix())->toBe($customPrefixGenerator($tenant) . ':'); + expect($customPrefixGenerator($tenant) . ':') + ->toBe(cache()->getPrefix()) + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); + + config(['cache.default' => 'redis2']); + + PrefixCacheTenancyBootstrapper::generatePrefixUsing($customPrefixGenerator = function (Tenant $tenant) { + return 'redis2_tenant_cache_' . $tenant->getTenantKey(); + }); + + tenancy()->initialize($tenant = Tenant::create()); + + expect($customPrefixGenerator($tenant) . ':') + ->toBe(cache()->getPrefix()) + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); tenancy()->end(); }); -test('stores get prefixed using the default way if the store does not have a corresponding generator', function() { - config(['cache.stores.redis2' => config('cache.stores.redis')]); +test('stores get prefixed using the default way if no prefix generator is specified', function() { // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); $originalPrefix = config('cache.prefix'); @@ -362,9 +377,11 @@ // Let the prefix get created using the default approach tenancy()->initialize($tenant); - expect(cache()->store()->getPrefix())->toBe($defaultPrefix . ':'); // Other stores without a prefix generator use the default generator too - expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix . ':'); + expect($defaultPrefix . ':') + ->toBe(cache()->getPrefix()) + ->toBe(app('cache')->getPrefix()) + ->toBe(app('cache.store')->getPrefix()); tenancy()->end(); }); From ab92f85b51ad8daacda522644b8cf401c6a5d206 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 17 Apr 2023 18:06:29 +0200 Subject: [PATCH 127/155] Add cache manager config key --- assets/config.php | 2 ++ src/TenancyServiceProvider.php | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/assets/config.php b/assets/config.php index e5c1a24b4..81a742582 100644 --- a/assets/config.php +++ b/assets/config.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Stancl\Tenancy\CacheManager; use Stancl\Tenancy\Middleware; use Stancl\Tenancy\Resolvers; @@ -189,6 +190,7 @@ * You can clear cache selectively by specifying the tag. */ 'cache' => [ + 'manager' => CacheManager::class, 'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call. 'prefix_base' => 'tenant_', // This prefix_base, followed by the tenant_id, will form a cache prefix that will be used for every cache key. ], diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index c3a68755e..549507710 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -96,10 +96,6 @@ public function boot(): void return new Commands\MigrateFreshOverride; }); - $this->app->singleton('cache', function ($app) { - return new TenantCacheManager($app); - }); - $this->publishes([ __DIR__ . '/../assets/config.php' => config_path('tenancy.php'), ], 'config'); @@ -138,5 +134,9 @@ public function boot(): void return $instance; }); + + $this->app->singleton('cache', function ($app) { + return new $this->app['config']['tenancy.cache.manager']($app); + }); } } From f12f119ff2141dc74eb27c547d3e3cf152cbd9e2 Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Mon, 17 Apr 2023 16:06:57 +0000 Subject: [PATCH 128/155] Fix code style (php-cs-fixer) --- src/TenancyServiceProvider.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 549507710..b3258c5f5 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -8,7 +8,6 @@ use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Support\ServiceProvider; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; -use Stancl\Tenancy\CacheManager as TenantCacheManager; use Stancl\Tenancy\Contracts\Domain; use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Resolvers\DomainTenantResolver; From 835b169d60fc746d3868434b0ce13880c2e40130 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 08:53:33 +0200 Subject: [PATCH 129/155] Update defaulting test --- tests/PrefixCacheBootstrapperTest.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 818bdbe7e..429782546 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -363,25 +363,22 @@ }); test('stores get prefixed using the default way if no prefix generator is specified', function() { - // Make 'redis2' the default cache driver - config(['cache.default' => 'redis2']); $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); - $tenant = Tenant::create(); $defaultPrefix = $originalPrefix . $prefixBase . $tenant->getTenantKey(); + // Don't specify a prefix generator + // Let the prefix get created using the default approach PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; - // Don't add a generator for 'redis2' - // Let the prefix get created using the default approach tenancy()->initialize($tenant); // Other stores without a prefix generator use the default generator too expect($defaultPrefix . ':') - ->toBe(cache()->getPrefix()) - ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); + ->toBe(app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant) . ':') + ->toBe(cache()->getPrefix()) // Get prefix of the default store ('redis') + ->toBe(cache()->store('redis2')->getPrefix()); tenancy()->end(); }); From effb6a81a1899aa54aa844be8be2ade4d3e1b1bf Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 09:02:38 +0200 Subject: [PATCH 130/155] Add todo --- src/TenancyServiceProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index b3258c5f5..5482b03d6 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -134,6 +134,7 @@ public function boot(): void return $instance; }); + // todo https://discord.com/channels/976506366502006874/976513756576243733/1097778320692740096 $this->app->singleton('cache', function ($app) { return new $this->app['config']['tenancy.cache.manager']($app); }); From e4a4940e590aafec210c74e16e2b7e9c2c6d1910 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 09:25:31 +0200 Subject: [PATCH 131/155] Update comments --- tests/PrefixCacheBootstrapperTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 429782546..7f5a3f650 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -200,6 +200,8 @@ $cacheStore = 'redis2'; // Name of the non-default, central cache store that we'll use using cache()->store($cacheStore) // Service uses the 'redis2' store which is central/not prefixed (not present in PrefixCacheTenancyBootstrapper::$tenantCacheStores) + // The service's handle() method sets the value of the cache key 'key' to the current tenant key + // Or to 'central-value' if tenancy isn't initialized $this->app->singleton(SpecificCacheStoreService::class, function() use ($cacheStore) { return new SpecificCacheStoreService($this->app->make(CacheManager::class), $cacheStore); }); @@ -211,7 +213,8 @@ $tenant2 = Tenant::create(); tenancy()->initialize($tenant1); - // The store isn't prefixed, so the cache isn't separated + // The store isn't prefixed, so the cache isn't separated – the values persist from one context to another + // Also check if the cache key SpecificCacheStoreService sets using the Repository singleton is set correctly expect(cache()->store($cacheStore)->get('key'))->toBe('central-value'); $this->app->make(SpecificCacheStoreService::class)->handle(); expect(cache()->store($cacheStore)->get('key'))->toBe($tenant1->getTenantKey()); From 46f94d15a594f02db8da29d5a7d328df576d3702 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 09:42:43 +0200 Subject: [PATCH 132/155] Extract duplicate assertions into a closure --- tests/PrefixCacheBootstrapperTest.php | 37 +++++++++++---------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 7f5a3f650..c2baf0f08 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -230,13 +230,21 @@ }); test('only the stores specified in tenantCacheStores get prefixed', function() { - // Make the currently used store ('redis') the only store in $tenantCacheStores - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + // Make sure the currently used store ('redis') is the only store in $tenantCacheStores + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$prefixedStore = 'redis']; + $centralValue = 'central-value'; + $assertStoreIsNotPrefixed = function (string $unprefixedStore) use ($prefixedStore, $centralValue) { + // Switch to the unprefixed store + config(['cache.default' => $unprefixedStore]); + expect(cache('key'))->toBe($centralValue); + // Switch back to the prefixed store + config(['cache.default' => $prefixedStore]); + }; $this->app->singleton(CacheService::class); $this->app->make(CacheService::class)->handle(); - expect(cache('key'))->toBe($centralValue = 'central-value'); + expect(cache('key'))->toBe($centralValue); $tenant1 = Tenant::create(); $tenant2 = Tenant::create(); @@ -247,10 +255,7 @@ $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); - // Switch to an unprefixed store - config(['cache.default' => 'redis2']); - expect(cache('key'))->toBe($centralValue); - config(['cache.default' => 'redis']); + $assertStoreIsNotPrefixed('redis2'); tenancy()->initialize($tenant2); @@ -258,11 +263,7 @@ $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); - // Switch to an unprefixed store - config(['cache.default' => 'redis2']); - expect(cache('key'))->toBe($centralValue); - // Switch back to the prefixed store - config(['cache.default' => 'redis']); + $assertStoreIsNotPrefixed('redis2'); tenancy()->end(); expect(cache('key'))->toBe($centralValue); @@ -279,11 +280,7 @@ $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant1->getTenantKey()); - // Switch to an unprefixed store - config(['cache.default' => 'redis2']); - expect(cache('key'))->toBe($centralValue); - // Switch back to the prefixed store - config(['cache.default' => 'redis']); + $assertStoreIsNotPrefixed('redis2'); tenancy()->initialize($tenant2); @@ -291,11 +288,7 @@ $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($tenant2->getTenantKey()); - // Switch to an unprefixed store - config(['cache.default' => 'redis2']); - expect(cache('key'))->toBe($centralValue); - // Switch back to the prefixed store - config(['cache.default' => 'redis']); + $assertStoreIsNotPrefixed('redis2'); tenancy()->end(); expect(cache('key'))->toBe($centralValue); From c0e292690515f8acc1a1f901ee93080c06a7e107 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 09:49:44 +0200 Subject: [PATCH 133/155] Update comment --- tests/PrefixCacheBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index c2baf0f08..adcd95036 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -370,7 +370,7 @@ tenancy()->initialize($tenant); - // Other stores without a prefix generator use the default generator too + // All stores use the default way of generating the prefix when the prefix generator isn't specified expect($defaultPrefix . ':') ->toBe(app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant) . ':') ->toBe(cache()->getPrefix()) // Get prefix of the default store ('redis') From f7c8f226c34fb17a4a62507151b8999c2802b960 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 14:20:21 +0200 Subject: [PATCH 134/155] Add assertions + comment --- tests/PrefixCacheBootstrapperTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index adcd95036..b94caa1a3 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -339,6 +339,7 @@ // Expect the 'redis' store to use the prefix generated by the custom generator expect($customPrefixGenerator($tenant) . ':') ->toBe(cache()->getPrefix()) + ->toBe(cache()->store('redis2')->getPrefix()) // Non-default cache stores are prefixed too (when they're in $tenantCacheStores) ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); @@ -352,6 +353,7 @@ expect($customPrefixGenerator($tenant) . ':') ->toBe(cache()->getPrefix()) + ->toBe(cache()->store('redis')->getPrefix()) ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); From 4b862e2bd69e8b843808448a15256da34f7242ad Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 14:27:57 +0200 Subject: [PATCH 135/155] Delete redundant config put calls --- tests/PrefixCacheBootstrapperTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index b94caa1a3..ed420fd16 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -196,7 +196,6 @@ }); test('specific central cache store can be used inside a service', function () { - config(['cache.default' => 'redis']); $cacheStore = 'redis2'; // Name of the non-default, central cache store that we'll use using cache()->store($cacheStore) // Service uses the 'redis2' store which is central/not prefixed (not present in PrefixCacheTenancyBootstrapper::$tenantCacheStores) @@ -322,7 +321,6 @@ }); test('cache store prefix generation can be customized', function() { - config(['cache.default' => 'redis']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; // Use custom prefix generator From b5abe6ef0f5d418267fa2a12ff6cd2c2c2df3c77 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 14:39:35 +0200 Subject: [PATCH 136/155] Use `tenancy.cache.manager` config instead of `Stancl\Tenancy\CacheManager` --- tests/PrefixCacheBootstrapperTest.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index ed420fd16..9d078db11 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -9,7 +9,6 @@ use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\CacheManager as TenancyCacheManager; use Stancl\Tenancy\Tests\Etc\SpecificCacheStoreService; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; @@ -25,7 +24,7 @@ PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; - TenancyCacheManager::$addTags = false; + config('tenancy.cache.manager')::$addTags = false; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); @@ -37,23 +36,25 @@ }); test('Tenancy overrides CacheManager', function() { - expect(app('cache')::class)->toBe(TenancyCacheManager::class); - expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + $tenancyCacheManager = config('tenancy.cache.manager'); + + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); tenancy()->initialize(Tenant::create(['id' => 'first'])); - expect(app('cache')::class)->toBe(TenancyCacheManager::class); - expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); tenancy()->initialize(Tenant::create(['id' => 'second'])); - expect(app('cache')::class)->toBe(TenancyCacheManager::class); - expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); tenancy()->end(); - expect(app('cache')::class)->toBe(TenancyCacheManager::class); - expect(app(CacheManager::class)::class)->toBe(TenancyCacheManager::class); + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); }); test('correct cache prefix is used in all contexts', function () { From cb07a47f18420e60bb0516c10824c8303b27e746 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 15:05:37 +0200 Subject: [PATCH 137/155] Change setting to assertion, add comment --- tests/BootstrapperTest.php | 1 + tests/PrefixCacheBootstrapperTest.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index fe62a9ae7..4f11e6175 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -93,6 +93,7 @@ }); test('cache data is separated', function (string $bootstrapper) { + // Make sure that the prefixed 'redis' cache driver is used expect(config('cache.default'))->toBe('redis'); config([ diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 9d078db11..939213c91 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -231,7 +231,8 @@ test('only the stores specified in tenantCacheStores get prefixed', function() { // Make sure the currently used store ('redis') is the only store in $tenantCacheStores - PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$prefixedStore = 'redis']; + expect(PrefixCacheTenancyBootstrapper::$tenantCacheStores)->toBe([$prefixedStore = 'redis']); + $centralValue = 'central-value'; $assertStoreIsNotPrefixed = function (string $unprefixedStore) use ($prefixedStore, $centralValue) { // Switch to the unprefixed store From 4d387188c5d00537b1cb35882199a6595a2faa27 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 18 Apr 2023 16:10:47 +0200 Subject: [PATCH 138/155] Inline variable & config key assignment --- tests/PrefixCacheBootstrapperTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 939213c91..41261a52b 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -152,14 +152,13 @@ }); test('cache base prefix is customizable', function () { - $originalPrefix = config('cache.prefix'); - $prefixBase = 'custom_'; - config([ - 'tenancy.cache.prefix_base' => $prefixBase + 'tenancy.cache.prefix_base' => $prefixBase = 'custom_' ]); + $originalPrefix = config('cache.prefix'); $tenant1 = Tenant::create(); + tenancy()->initialize($tenant1); expect($originalPrefix . $prefixBase . $tenant1->getTenantKey() . ':') @@ -339,12 +338,13 @@ // Expect the 'redis' store to use the prefix generated by the custom generator expect($customPrefixGenerator($tenant) . ':') ->toBe(cache()->getPrefix()) - ->toBe(cache()->store('redis2')->getPrefix()) // Non-default cache stores are prefixed too (when they're in $tenantCacheStores) + ->toBe(cache()->store('redis2')->getPrefix()) // Non-default cache stores specified in $tenantCacheStores are prefixed too ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); config(['cache.default' => 'redis2']); + // Use different prefix generator PrefixCacheTenancyBootstrapper::generatePrefixUsing($customPrefixGenerator = function (Tenant $tenant) { return 'redis2_tenant_cache_' . $tenant->getTenantKey(); }); From 1d52096d6e6e52c3c2d56771d3c223d2e1743ed6 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 19 Apr 2023 08:35:36 +0200 Subject: [PATCH 139/155] Delete `cache.default` assertion --- tests/BootstrapperTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 4f11e6175..fe588159b 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -93,9 +93,6 @@ }); test('cache data is separated', function (string $bootstrapper) { - // Make sure that the prefixed 'redis' cache driver is used - expect(config('cache.default'))->toBe('redis'); - config([ 'tenancy.bootstrappers' => [$bootstrapper], ]); From 2171ca9c687c9071f4796a0951b9392e1536dc1b Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 19 Apr 2023 09:37:10 +0200 Subject: [PATCH 140/155] Override cache manager only in CacheTagsBootstrapper --- assets/config.php | 1 - src/Bootstrappers/CacheTagsBootstrapper.php | 44 ++++++++++++++++----- src/CacheManager.php | 26 +++++------- src/TenancyServiceProvider.php | 5 --- tests/BootstrapperTest.php | 2 - tests/GlobalCacheTest.php | 1 - tests/PrefixCacheBootstrapperTest.php | 24 ----------- 7 files changed, 45 insertions(+), 58 deletions(-) diff --git a/assets/config.php b/assets/config.php index 81a742582..3875aca15 100644 --- a/assets/config.php +++ b/assets/config.php @@ -190,7 +190,6 @@ * You can clear cache selectively by specifying the tag. */ 'cache' => [ - 'manager' => CacheManager::class, 'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call. 'prefix_base' => 'tenant_', // This prefix_base, followed by the tenant_id, will form a cache prefix that will be used for every cache key. ], diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 1af367e03..0921af441 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -4,24 +4,50 @@ namespace Stancl\Tenancy\Bootstrappers; -use Stancl\Tenancy\CacheManager; -use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Illuminate\Cache\CacheManager; use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Support\Facades\Cache; +use Illuminate\Contracts\Foundation\Application; +use Stancl\Tenancy\Contracts\TenancyBootstrapper; -/** - * todo name. - * - * Separate tenant cache using tagging. - */ class CacheTagsBootstrapper implements TenancyBootstrapper { + protected ?CacheManager $originalCache = null; + public static string $cacheManagerWithTags = \Stancl\Tenancy\CacheManager::class; + + public function __construct( + protected Application $app + ) { + } + public function bootstrap(Tenant $tenant): void { - CacheManager::$addTags = true; + $this->resetFacadeCache(); + + $this->originalCache ??= $this->app['cache']; + $this->app->extend('cache', function () { + return new static::$cacheManagerWithTags($this->app); + }); } public function revert(): void { - CacheManager::$addTags = false; + $this->resetFacadeCache(); + + $this->app->extend('cache', function () { + return $this->originalCache; + }); + + $this->originalCache = null; + } + + /** + * This wouldn't be necessary, but is needed when a call to the + * facade has been made prior to bootstrapping tenancy. The + * facade has its own cache, separate from the container. + */ + public function resetFacadeCache(): void + { + Cache::clearResolvedInstances(); } } diff --git a/src/CacheManager.php b/src/CacheManager.php index d343ac521..292d98132 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -10,8 +10,6 @@ class CacheManager extends BaseCacheManager { - public static bool $addTags = false; - /** * Add tags and forward the call to the inner cache store. * @@ -20,25 +18,21 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - if (tenancy()->initialized && static::$addTags) { - $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - - if ($method === 'tags') { - $count = count($parameters); + $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - if ($count !== 1) { - throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); - } + if ($method === 'tags') { + $count = count($parameters); - $names = $parameters[0]; - $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items - - return $this->store()->tags(array_merge($tags, $names)); + if ($count !== 1) { + throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); } - return $this->store()->tags($tags)->$method(...$parameters); + $names = $parameters[0]; + $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + + return $this->store()->tags(array_merge($tags, $names)); } - return parent::__call($method, $parameters); + return $this->store()->tags($tags)->$method(...$parameters); } } diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 5482b03d6..bde370556 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -133,10 +133,5 @@ public function boot(): void return $instance; }); - - // todo https://discord.com/channels/976506366502006874/976513756576243733/1097778320692740096 - $this->app->singleton('cache', function ($app) { - return new $this->app['config']['tenancy.cache.manager']($app); - }); } } diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index fe588159b..d74079e79 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -41,7 +41,6 @@ beforeEach(function () { $this->mockConsoleOutput = false; - CacheManager::$addTags = false; config(['cache.default' => $cacheDriver = 'redis']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; @@ -57,7 +56,6 @@ }); afterEach(function () { - CacheManager::$addTags = false; PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; }); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index e7b026283..1ffc2ee18 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -14,7 +14,6 @@ use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; beforeEach(function () { - CacheManager::$addTags = false; config(['cache.default' => $cacheDriver = 'redis']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 41261a52b..3e73b7271 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -24,8 +24,6 @@ PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; - config('tenancy.cache.manager')::$addTags = false; - Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); @@ -35,28 +33,6 @@ PrefixCacheTenancyBootstrapper::$prefixGenerator = null; }); -test('Tenancy overrides CacheManager', function() { - $tenancyCacheManager = config('tenancy.cache.manager'); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); - - tenancy()->initialize(Tenant::create(['id' => 'first'])); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); - - tenancy()->initialize(Tenant::create(['id' => 'second'])); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); - - tenancy()->end(); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); -}); - test('correct cache prefix is used in all contexts', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); From cc45f809215864bccf87264426ae9576f319d7c0 Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Wed, 19 Apr 2023 07:37:43 +0000 Subject: [PATCH 141/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/CacheTagsBootstrapper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 0921af441..2d6bf3dad 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -5,10 +5,10 @@ namespace Stancl\Tenancy\Bootstrappers; use Illuminate\Cache\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; -use Illuminate\Support\Facades\Cache; use Illuminate\Contracts\Foundation\Application; +use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Contracts\Tenant; class CacheTagsBootstrapper implements TenancyBootstrapper { From 52d10d36f96c31be590eb4b9d40163e4ab189cd2 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 19 Apr 2023 10:30:09 +0200 Subject: [PATCH 142/155] Prefix both drivers by default, add assertions for the second driver where missing --- tests/PrefixCacheBootstrapperTest.php | 39 +++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 3e73b7271..89a1cc685 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -18,10 +18,10 @@ PrefixCacheTenancyBootstrapper::class ], 'cache.default' => $cacheDriver = 'redis', - 'cache.stores.redis2' => config('cache.stores.redis'), + 'cache.stores.' . $secondCacheDriver = 'redis2' => config('cache.stores.redis'), ]); - PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver, $secondCacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); @@ -44,7 +44,9 @@ $expectCachePrefixToBe = function (string $prefix) { expect($prefix . ':') // RedisStore suffixes prefix with ':' ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); + ->toBe(app('cache.store')->getPrefix()) + ->toBe(cache()->getPrefix()) + ->toBe(cache()->store('redis2')->getPrefix()); // Non-default cache stores specified in $tenantCacheStores are prefixed too }; $expectCachePrefixToBe($originalPrefix); @@ -139,6 +141,7 @@ expect($originalPrefix . $prefixBase . $tenant1->getTenantKey() . ':') ->toBe(cache()->getPrefix()) + ->toBe(cache()->store('redis2')->getPrefix()) // Non-default store gets prefixed correctly too ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); }); @@ -172,7 +175,10 @@ }); test('specific central cache store can be used inside a service', function () { - $cacheStore = 'redis2'; // Name of the non-default, central cache store that we'll use using cache()->store($cacheStore) + // Make sure 'redis' (the default store) is the only prefixed store + PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis']; + // Name of the non-default, central cache store that we'll use using cache()->store($cacheStore) + $cacheStore = 'redis2'; // Service uses the 'redis2' store which is central/not prefixed (not present in PrefixCacheTenancyBootstrapper::$tenantCacheStores) // The service's handle() method sets the value of the cache key 'key' to the current tenant key @@ -206,7 +212,7 @@ test('only the stores specified in tenantCacheStores get prefixed', function() { // Make sure the currently used store ('redis') is the only store in $tenantCacheStores - expect(PrefixCacheTenancyBootstrapper::$tenantCacheStores)->toBe([$prefixedStore = 'redis']); + PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$prefixedStore = 'redis']; $centralValue = 'central-value'; $assertStoreIsNotPrefixed = function (string $unprefixedStore) use ($prefixedStore, $centralValue) { @@ -271,35 +277,30 @@ }); test('non default stores get prefixed too when specified in tenantCacheStores', function () { - $generatePrefixForTenant = function (Tenant $tenant) { - return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); - }; - + // In beforeEach, we set $tenantCacheStores to ['redis', 'redis2'] // Make 'redis2' the default cache driver config(['cache.default' => 'redis2']); - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; - // The prefix is the same for both drivers in the central context $tenant = Tenant::create(); $defaultPrefix = cache()->store()->getPrefix(); + $generatePrefixForTenant = function (Tenant $tenant) { + return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); + }; + // The prefix is the same for both drivers in the central context expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); tenancy()->initialize($tenant); - $expectedPrefix = $generatePrefixForTenant($tenant); - // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator - expect(cache()->store()->getPrefix())->toBe($expectedPrefix . ':'); - // Non-default store - expect(cache()->store('redis')->getPrefix())->toBe($expectedPrefix . ':'); + expect($generatePrefixForTenant($tenant) . ':') + ->toBe(cache()->getPrefix()) + ->toBe(cache()->store('redis')->getPrefix()); // Non-default store tenancy()->end(); }); test('cache store prefix generation can be customized', function() { - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; - // Use custom prefix generator PrefixCacheTenancyBootstrapper::generatePrefixUsing($customPrefixGenerator = function (Tenant $tenant) { return 'redis_tenant_cache_' . $tenant->getTenantKey(); @@ -344,8 +345,6 @@ // Don't specify a prefix generator // Let the prefix get created using the default approach - PrefixCacheTenancyBootstrapper::$tenantCacheStores = ['redis', 'redis2']; - tenancy()->initialize($tenant); // All stores use the default way of generating the prefix when the prefix generator isn't specified From 53b2181779baa8541400dd014043636e213e6259 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 19 Apr 2023 13:37:06 +0200 Subject: [PATCH 143/155] Clean up global state (static properties) in before/afterEach --- tests/BootstrapperTest.php | 10 +++++++++- tests/BroadcastingTest.php | 7 ++++++- tests/DomainTest.php | 9 ++++++--- tests/GlobalCacheTest.php | 4 ++++ tests/MailTest.php | 5 +++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index d74079e79..9260c9c9b 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -37,12 +37,16 @@ use Stancl\Tenancy\Bootstrappers\BroadcastTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; -use Stancl\Tenancy\CacheManager; beforeEach(function () { $this->mockConsoleOutput = false; + config(['cache.default' => $cacheDriver = 'redis']); PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver]; + // Reset static properties of classes used in this test file to their default values + BroadcastTenancyBootstrapper::$credentialsMap = []; + TenancyBroadcastManager::$tenantBroadcasters = ['pusher', 'ably']; + UrlTenancyBootstrapper::$rootUrlOverride = null; Event::listen( TenantCreated::class, @@ -56,7 +60,11 @@ }); afterEach(function () { + // Reset static properties of classes used in this test file to their default values + UrlTenancyBootstrapper::$rootUrlOverride = null; PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; + TenancyBroadcastManager::$tenantBroadcasters = ['pusher', 'ably']; + BroadcastTenancyBootstrapper::$credentialsMap = []; }); test('database data is separated', function () { diff --git a/tests/BroadcastingTest.php b/tests/BroadcastingTest.php index aeb70de26..9505b5378 100644 --- a/tests/BroadcastingTest.php +++ b/tests/BroadcastingTest.php @@ -13,12 +13,17 @@ use Stancl\Tenancy\Listeners\RevertToCentralContext; use Illuminate\Contracts\Broadcasting\Broadcaster as BroadcasterContract; -beforeEach(function() { +beforeEach(function () { withTenantDatabases(); + TenancyBroadcastManager::$tenantBroadcasters = ['pusher', 'ably']; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +afterEach(function () { + TenancyBroadcastManager::$tenantBroadcasters = ['pusher', 'ably']; +}); + test('bound broadcaster instance is the same before initializing tenancy and after ending it', function() { config(['broadcasting.default' => 'null']); TenancyBroadcastManager::$tenantBroadcasters[] = 'null'; diff --git a/tests/DomainTest.php b/tests/DomainTest.php index 024599144..cb1045327 100644 --- a/tests/DomainTest.php +++ b/tests/DomainTest.php @@ -12,6 +12,8 @@ use Stancl\Tenancy\Resolvers\DomainTenantResolver; beforeEach(function () { + InitializeTenancyByDomain::$onFail = null; + Route::group([ 'middleware' => InitializeTenancyByDomain::class, ], function () { @@ -23,6 +25,10 @@ config(['tenancy.models.tenant' => DomainTenant::class]); }); +afterEach(function () { + InitializeTenancyByDomain::$onFail = null; +}); + test('tenant can be identified using hostname', function () { $tenant = DomainTenant::create(); @@ -89,9 +95,6 @@ }); test('throw correct exception when onFail is null and universal routes are enabled', function () { - // un-define onFail logic - InitializeTenancyByDomain::$onFail = null; - // Enable UniversalRoute feature Route::middlewareGroup('universal', []); diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index 1ffc2ee18..22fc2641f 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -21,6 +21,10 @@ Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +afterEach(function () { + PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; +}); + test('global cache manager stores data in global cache', function (string $bootstrapper) { config(['tenancy.bootstrappers' => [$bootstrapper]]); diff --git a/tests/MailTest.php b/tests/MailTest.php index c530b7e8c..dc48648a6 100644 --- a/tests/MailTest.php +++ b/tests/MailTest.php @@ -12,11 +12,16 @@ beforeEach(function() { config(['mail.default' => 'smtp']); + MailTenancyBootstrapper::$credentialsMap = []; Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); }); +afterEach(function () { + MailTenancyBootstrapper::$credentialsMap = []; +}); + // Initialize tenancy as $tenant and assert that the smtp mailer's transport has the correct password function assertMailerTransportUsesPassword(string|null $password) { $manager = app(MailManager::class); From 0920c6ae1d34ec9eeeca14af424818061e6e4280 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 19 Apr 2023 13:48:22 +0200 Subject: [PATCH 144/155] Add docblock to tags bootstrapper --- src/Bootstrappers/CacheTagsBootstrapper.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 2d6bf3dad..2a2efa32d 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -10,6 +10,11 @@ use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; +/** + * todo name. + * + * Separate tenant cache using tagging. + */ class CacheTagsBootstrapper implements TenancyBootstrapper { protected ?CacheManager $originalCache = null; From 62b596f7a622f83721d96db4ab2c4792a50d7be6 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Wed, 19 Apr 2023 14:26:17 +0200 Subject: [PATCH 145/155] Delete extra dependency --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 1aef91595..99550ad7c 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ "require": { "php": "^8.2", "ext-json": "*", - "illuminate/support": "^10.0", "facade/ignition-contracts": "^1.0.2", "spatie/ignition": "^1.4", "ramsey/uuid": "^4.7.3", From 58e008a67904c1c32e6d6d86d995ff005ae454f3 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 20 Apr 2023 09:27:08 +0200 Subject: [PATCH 146/155] Add `illuminate/support` dependency back --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 99550ad7c..cadd9ee50 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "require": { "php": "^8.2", "ext-json": "*", + "illuminate/support": "^10.1", "facade/ignition-contracts": "^1.0.2", "spatie/ignition": "^1.4", "ramsey/uuid": "^4.7.3", From 8f5a4e4eb64fa2107a0bb65c94dbea0c7de6c473 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 20 Apr 2023 15:49:17 +0200 Subject: [PATCH 147/155] Use `$addTags` approach again --- assets/config.php | 1 + src/Bootstrappers/CacheTagsBootstrapper.php | 39 +++------------------ src/CacheManager.php | 26 ++++++++------ src/TenancyServiceProvider.php | 8 +++++ tests/PrefixCacheBootstrapperTest.php | 27 ++++++++++++++ 5 files changed, 56 insertions(+), 45 deletions(-) diff --git a/assets/config.php b/assets/config.php index 3875aca15..4d1241ba7 100644 --- a/assets/config.php +++ b/assets/config.php @@ -192,6 +192,7 @@ 'cache' => [ 'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call. 'prefix_base' => 'tenant_', // This prefix_base, followed by the tenant_id, will form a cache prefix that will be used for every cache key. + 'override_manager' => false, ], /** diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 2a2efa32d..eb46d9381 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -4,11 +4,9 @@ namespace Stancl\Tenancy\Bootstrappers; -use Illuminate\Cache\CacheManager; -use Illuminate\Contracts\Foundation\Application; -use Illuminate\Support\Facades\Cache; -use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\CacheManager; use Stancl\Tenancy\Contracts\Tenant; +use Stancl\Tenancy\Contracts\TenancyBootstrapper; /** * todo name. @@ -17,42 +15,13 @@ */ class CacheTagsBootstrapper implements TenancyBootstrapper { - protected ?CacheManager $originalCache = null; - public static string $cacheManagerWithTags = \Stancl\Tenancy\CacheManager::class; - - public function __construct( - protected Application $app - ) { - } - public function bootstrap(Tenant $tenant): void { - $this->resetFacadeCache(); - - $this->originalCache ??= $this->app['cache']; - $this->app->extend('cache', function () { - return new static::$cacheManagerWithTags($this->app); - }); + CacheManager::$addTags = true; } public function revert(): void { - $this->resetFacadeCache(); - - $this->app->extend('cache', function () { - return $this->originalCache; - }); - - $this->originalCache = null; - } - - /** - * This wouldn't be necessary, but is needed when a call to the - * facade has been made prior to bootstrapping tenancy. The - * facade has its own cache, separate from the container. - */ - public function resetFacadeCache(): void - { - Cache::clearResolvedInstances(); + CacheManager::$addTags = false; } } diff --git a/src/CacheManager.php b/src/CacheManager.php index 292d98132..d343ac521 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -10,6 +10,8 @@ class CacheManager extends BaseCacheManager { + public static bool $addTags = false; + /** * Add tags and forward the call to the inner cache store. * @@ -18,21 +20,25 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; + if (tenancy()->initialized && static::$addTags) { + $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - if ($method === 'tags') { - $count = count($parameters); + if ($method === 'tags') { + $count = count($parameters); - if ($count !== 1) { - throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); - } + if ($count !== 1) { + throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); + } - $names = $parameters[0]; - $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + $names = $parameters[0]; + $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + + return $this->store()->tags(array_merge($tags, $names)); + } - return $this->store()->tags(array_merge($tags, $names)); + return $this->store()->tags($tags)->$method(...$parameters); } - return $this->store()->tags($tags)->$method(...$parameters); + return parent::__call($method, $parameters); } } diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index bde370556..4e5adabaa 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -8,6 +8,7 @@ use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Support\ServiceProvider; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; +use Stancl\Tenancy\CacheManager as TenancyCacheManager; use Stancl\Tenancy\Contracts\Domain; use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Resolvers\DomainTenantResolver; @@ -133,5 +134,12 @@ public function boot(): void return $instance; }); + + if (! $this->app['config']['tenancy.cache.override_manager']) { + // todo https://discord.com/channels/976506366502006874/976513756576243733/1097778320692740096 + $this->app->singleton('cache', function ($app) { + return new TenancyCacheManager($app); + }); + } } } diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 89a1cc685..7f0eac97a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -11,6 +11,7 @@ use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Tests\Etc\SpecificCacheStoreService; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; +use Stancl\Tenancy\CacheManager as TenancyCacheManager; beforeEach(function () { config([ @@ -21,6 +22,7 @@ 'cache.stores.' . $secondCacheDriver = 'redis2' => config('cache.stores.redis'), ]); + TenancyCacheManager::$addTags = false; PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver, $secondCacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; @@ -29,10 +31,35 @@ }); afterEach(function () { + TenancyCacheManager::$addTags = false; PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; }); +test('Tenancy overrides CacheManager', function () { + // todo Change this to 'Tenancy overrides CacheManager only if configured to do so' after changing TenancyServiceProvider structure + // Since we override the manager in TSP by default, we can't test if the overriding is disabled by changing the override_manager config key + $tenancyCacheManager = TenancyCacheManager::class; + + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); + + tenancy()->initialize(Tenant::create(['id' => 'first'])); + + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); + + tenancy()->initialize(Tenant::create(['id' => 'second'])); + + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); + + tenancy()->end(); + + expect(app('cache')::class)->toBe($tenancyCacheManager); + expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); +}); + test('correct cache prefix is used in all contexts', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); From ea805fa23108f1bc763b4eaf0bbc057090734e09 Mon Sep 17 00:00:00 2001 From: PHP CS Fixer Date: Thu, 20 Apr 2023 13:49:48 +0000 Subject: [PATCH 148/155] Fix code style (php-cs-fixer) --- src/Bootstrappers/CacheTagsBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index eb46d9381..1af367e03 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Bootstrappers; use Stancl\Tenancy\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Contracts\Tenant; /** * todo name. From 55cc89ecf98d22dae92f01f964a5e2be5082a70c Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 20 Apr 2023 16:34:47 +0200 Subject: [PATCH 149/155] Revert "Fix code style (php-cs-fixer)" This reverts commit ea805fa23108f1bc763b4eaf0bbc057090734e09. --- src/Bootstrappers/CacheTagsBootstrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 1af367e03..eb46d9381 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Bootstrappers; use Stancl\Tenancy\CacheManager; -use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; +use Stancl\Tenancy\Contracts\TenancyBootstrapper; /** * todo name. From 8178c91842fbedceb714d98a3c8b850de89fa45a Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 20 Apr 2023 16:35:29 +0200 Subject: [PATCH 150/155] Revert "Use `$addTags` approach again" This reverts commit 8f5a4e4eb64fa2107a0bb65c94dbea0c7de6c473. --- assets/config.php | 1 - src/Bootstrappers/CacheTagsBootstrapper.php | 39 ++++++++++++++++++--- src/CacheManager.php | 26 ++++++-------- src/TenancyServiceProvider.php | 8 ----- tests/PrefixCacheBootstrapperTest.php | 27 -------------- 5 files changed, 45 insertions(+), 56 deletions(-) diff --git a/assets/config.php b/assets/config.php index 4d1241ba7..3875aca15 100644 --- a/assets/config.php +++ b/assets/config.php @@ -192,7 +192,6 @@ 'cache' => [ 'tag_base' => 'tenant', // This tag_base, followed by the tenant_id, will form a tag that will be applied on each cache call. 'prefix_base' => 'tenant_', // This prefix_base, followed by the tenant_id, will form a cache prefix that will be used for every cache key. - 'override_manager' => false, ], /** diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index eb46d9381..2a2efa32d 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -4,9 +4,11 @@ namespace Stancl\Tenancy\Bootstrappers; -use Stancl\Tenancy\CacheManager; -use Stancl\Tenancy\Contracts\Tenant; +use Illuminate\Cache\CacheManager; +use Illuminate\Contracts\Foundation\Application; +use Illuminate\Support\Facades\Cache; use Stancl\Tenancy\Contracts\TenancyBootstrapper; +use Stancl\Tenancy\Contracts\Tenant; /** * todo name. @@ -15,13 +17,42 @@ */ class CacheTagsBootstrapper implements TenancyBootstrapper { + protected ?CacheManager $originalCache = null; + public static string $cacheManagerWithTags = \Stancl\Tenancy\CacheManager::class; + + public function __construct( + protected Application $app + ) { + } + public function bootstrap(Tenant $tenant): void { - CacheManager::$addTags = true; + $this->resetFacadeCache(); + + $this->originalCache ??= $this->app['cache']; + $this->app->extend('cache', function () { + return new static::$cacheManagerWithTags($this->app); + }); } public function revert(): void { - CacheManager::$addTags = false; + $this->resetFacadeCache(); + + $this->app->extend('cache', function () { + return $this->originalCache; + }); + + $this->originalCache = null; + } + + /** + * This wouldn't be necessary, but is needed when a call to the + * facade has been made prior to bootstrapping tenancy. The + * facade has its own cache, separate from the container. + */ + public function resetFacadeCache(): void + { + Cache::clearResolvedInstances(); } } diff --git a/src/CacheManager.php b/src/CacheManager.php index d343ac521..292d98132 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -10,8 +10,6 @@ class CacheManager extends BaseCacheManager { - public static bool $addTags = false; - /** * Add tags and forward the call to the inner cache store. * @@ -20,25 +18,21 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - if (tenancy()->initialized && static::$addTags) { - $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - - if ($method === 'tags') { - $count = count($parameters); + $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; - if ($count !== 1) { - throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); - } + if ($method === 'tags') { + $count = count($parameters); - $names = $parameters[0]; - $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items - - return $this->store()->tags(array_merge($tags, $names)); + if ($count !== 1) { + throw new \Exception("Method tags() takes exactly 1 argument. $count passed."); } - return $this->store()->tags($tags)->$method(...$parameters); + $names = $parameters[0]; + $names = (array) $names; // cache()->tags('foo') https://laravel.com/docs/9.x/cache#removing-tagged-cache-items + + return $this->store()->tags(array_merge($tags, $names)); } - return parent::__call($method, $parameters); + return $this->store()->tags($tags)->$method(...$parameters); } } diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 4e5adabaa..bde370556 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -8,7 +8,6 @@ use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Support\ServiceProvider; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; -use Stancl\Tenancy\CacheManager as TenancyCacheManager; use Stancl\Tenancy\Contracts\Domain; use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Resolvers\DomainTenantResolver; @@ -134,12 +133,5 @@ public function boot(): void return $instance; }); - - if (! $this->app['config']['tenancy.cache.override_manager']) { - // todo https://discord.com/channels/976506366502006874/976513756576243733/1097778320692740096 - $this->app->singleton('cache', function ($app) { - return new TenancyCacheManager($app); - }); - } } } diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 7f0eac97a..89a1cc685 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -11,7 +11,6 @@ use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Tests\Etc\SpecificCacheStoreService; use Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper; -use Stancl\Tenancy\CacheManager as TenancyCacheManager; beforeEach(function () { config([ @@ -22,7 +21,6 @@ 'cache.stores.' . $secondCacheDriver = 'redis2' => config('cache.stores.redis'), ]); - TenancyCacheManager::$addTags = false; PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$cacheDriver, $secondCacheDriver]; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; @@ -31,35 +29,10 @@ }); afterEach(function () { - TenancyCacheManager::$addTags = false; PrefixCacheTenancyBootstrapper::$tenantCacheStores = []; PrefixCacheTenancyBootstrapper::$prefixGenerator = null; }); -test('Tenancy overrides CacheManager', function () { - // todo Change this to 'Tenancy overrides CacheManager only if configured to do so' after changing TenancyServiceProvider structure - // Since we override the manager in TSP by default, we can't test if the overriding is disabled by changing the override_manager config key - $tenancyCacheManager = TenancyCacheManager::class; - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); - - tenancy()->initialize(Tenant::create(['id' => 'first'])); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); - - tenancy()->initialize(Tenant::create(['id' => 'second'])); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); - - tenancy()->end(); - - expect(app('cache')::class)->toBe($tenancyCacheManager); - expect(app(CacheManager::class)::class)->toBe($tenancyCacheManager); -}); - test('correct cache prefix is used in all contexts', function () { $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); From 30567d9650ae131f34c38ea497dfa1f2142f48c1 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 20 Apr 2023 16:55:18 +0200 Subject: [PATCH 151/155] Add commented CacheTagsBootstrapper with info to the bootstrappers config --- assets/config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/config.php b/assets/config.php index 3875aca15..92782858a 100644 --- a/assets/config.php +++ b/assets/config.php @@ -103,6 +103,7 @@ Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper::class, + // Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper::class, // Note: DI won't work properly. PrefixCacheTenancyBootstrapper is the recommended way of separating cache // Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\SessionTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper::class, // Queueing mail requires using QueueTenancyBootstrapper with $forceRefresh set to true From 5a158b953797ec673d005d506b8e16a91a150a7a Mon Sep 17 00:00:00 2001 From: lukinovec Date: Thu, 20 Apr 2023 17:05:18 +0200 Subject: [PATCH 152/155] Delete legacy bootstrapper from the bootstrappers config, add info to the bootstrapper's docblock --- assets/config.php | 1 - src/Bootstrappers/CacheTagsBootstrapper.php | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/config.php b/assets/config.php index 92782858a..3875aca15 100644 --- a/assets/config.php +++ b/assets/config.php @@ -103,7 +103,6 @@ Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper::class, Stancl\Tenancy\Bootstrappers\BatchTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\PrefixCacheTenancyBootstrapper::class, - // Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper::class, // Note: DI won't work properly. PrefixCacheTenancyBootstrapper is the recommended way of separating cache // Stancl\Tenancy\Bootstrappers\UrlTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\SessionTenancyBootstrapper::class, // Stancl\Tenancy\Bootstrappers\MailTenancyBootstrapper::class, // Queueing mail requires using QueueTenancyBootstrapper with $forceRefresh set to true diff --git a/src/Bootstrappers/CacheTagsBootstrapper.php b/src/Bootstrappers/CacheTagsBootstrapper.php index 2a2efa32d..7ab28c960 100644 --- a/src/Bootstrappers/CacheTagsBootstrapper.php +++ b/src/Bootstrappers/CacheTagsBootstrapper.php @@ -14,6 +14,8 @@ * todo name. * * Separate tenant cache using tagging. + * This is the legacy approach. Some things, like dependency injection, won't work properly with this bootstrapper. + * PrefixCacheTenancyBootstrapper is the recommended bootstrapper for cache separation. */ class CacheTagsBootstrapper implements TenancyBootstrapper { From 69d4c321a6b0824cc805f79844e87916c350749c Mon Sep 17 00:00:00 2001 From: lukinovec Date: Mon, 24 Apr 2023 07:54:05 +0200 Subject: [PATCH 153/155] Delete "?" from `tenant()?->getTenantKey() --- src/CacheManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CacheManager.php b/src/CacheManager.php index 292d98132..f28134b83 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -18,7 +18,7 @@ class CacheManager extends BaseCacheManager */ public function __call($method, $parameters) { - $tags = [config('tenancy.cache.tag_base') . tenant()?->getTenantKey()]; + $tags = [config('tenancy.cache.tag_base') . tenant()->getTenantKey()]; if ($method === 'tags') { $count = count($parameters); From 4b4d808e30e0842cce94db9a93dae761d674d106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Mon, 24 Apr 2023 08:06:23 +0200 Subject: [PATCH 154/155] call generatePrefix() on $bootstrapper --- tests/PrefixCacheBootstrapperTest.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 89a1cc685..4fa6b0c9a 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -37,9 +37,7 @@ $originalPrefix = config('cache.prefix'); $prefixBase = config('tenancy.cache.prefix_base'); $getDefaultPrefixForTenant = fn (Tenant $tenant) => $originalPrefix . $prefixBase . $tenant->getTenantKey(); - $generatePrefixForTenant = function (Tenant $tenant) { - return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); - }; + $bootstrapper = app(PrefixCacheTenancyBootstrapper::class); $expectCachePrefixToBe = function (string $prefix) { expect($prefix . ':') // RedisStore suffixes prefix with ':' @@ -56,12 +54,12 @@ tenancy()->initialize($tenant1); cache()->set('key', 'tenantone-value'); - expect($generatePrefixForTenant($tenant1))->toBe($tenantOnePrefix = $getDefaultPrefixForTenant($tenant1)); + expect($bootstrapper->generatePrefix($tenant1))->toBe($tenantOnePrefix = $getDefaultPrefixForTenant($tenant1)); $expectCachePrefixToBe($tenantOnePrefix); tenancy()->initialize($tenant2); cache()->set('key', 'tenanttwo-value'); - expect($generatePrefixForTenant($tenant2))->toBe($tenantTwoPrefix = $getDefaultPrefixForTenant($tenant2)); + expect($bootstrapper->generatePrefix($tenant2))->toBe($tenantTwoPrefix = $getDefaultPrefixForTenant($tenant2)); $expectCachePrefixToBe($tenantTwoPrefix); // Prefix gets reverted to default after ending tenancy @@ -283,9 +281,7 @@ $tenant = Tenant::create(); $defaultPrefix = cache()->store()->getPrefix(); - $generatePrefixForTenant = function (Tenant $tenant) { - return app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant); - }; + $bootstrapper = app(PrefixCacheTenancyBootstrapper::class); // The prefix is the same for both drivers in the central context expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); @@ -293,7 +289,7 @@ tenancy()->initialize($tenant); // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator - expect($generatePrefixForTenant($tenant) . ':') + expect($bootstrapper->generatePrefix($tenant) . ':') ->toBe(cache()->getPrefix()) ->toBe(cache()->store('redis')->getPrefix()); // Non-default store From 07c1d7714803681dcd9d6cb4970a0cd7afd5c08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Mon, 24 Apr 2023 08:36:36 +0200 Subject: [PATCH 155/155] misc improvements --- tests/PrefixCacheBootstrapperTest.php | 65 ++++++++------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/tests/PrefixCacheBootstrapperTest.php b/tests/PrefixCacheBootstrapperTest.php index 4fa6b0c9a..68a9d33c4 100644 --- a/tests/PrefixCacheBootstrapperTest.php +++ b/tests/PrefixCacheBootstrapperTest.php @@ -54,13 +54,15 @@ tenancy()->initialize($tenant1); cache()->set('key', 'tenantone-value'); - expect($bootstrapper->generatePrefix($tenant1))->toBe($tenantOnePrefix = $getDefaultPrefixForTenant($tenant1)); + $tenantOnePrefix = $getDefaultPrefixForTenant($tenant1); $expectCachePrefixToBe($tenantOnePrefix); + expect($bootstrapper->generatePrefix($tenant1))->toBe($tenantOnePrefix); tenancy()->initialize($tenant2); cache()->set('key', 'tenanttwo-value'); - expect($bootstrapper->generatePrefix($tenant2))->toBe($tenantTwoPrefix = $getDefaultPrefixForTenant($tenant2)); + $tenantTwoPrefix = $getDefaultPrefixForTenant($tenant2); $expectCachePrefixToBe($tenantTwoPrefix); + expect($bootstrapper->generatePrefix($tenant2))->toBe($tenantTwoPrefix); // Prefix gets reverted to default after ending tenancy tenancy()->end(); @@ -83,7 +85,7 @@ expect(cache('foo'))->toBe('bar'); tenancy()->initialize($tenant2); - expect(cache('foo'))->not()->toBe('bar'); + expect(cache('foo'))->toBeNull(); tenancy()->end(); tenancy()->initialize($tenant1); @@ -100,7 +102,7 @@ $tenant2 = Tenant::create(); tenancy()->initialize($tenant2); - expect(cache()->get('foo'))->not()->toBe('bar'); + expect(cache()->get('foo'))->toBeNull(); cache()->put('foo', 'xyz'); expect(cache()->get('foo'))->toBe('xyz'); @@ -125,6 +127,10 @@ expect(cache()->get('key'))->toBe('central'); expect(cache()->get('key2'))->toBe('central-two'); + + tenancy()->initialize($tenant1); + expect(cache()->get('key'))->toBe('tenant'); + expect(cache()->get('key2'))->toBeNull(); }); test('cache base prefix is customizable', function () { @@ -193,7 +199,7 @@ tenancy()->initialize($tenant1); // The store isn't prefixed, so the cache isn't separated – the values persist from one context to another - // Also check if the cache key SpecificCacheStoreService sets using the Repository singleton is set correctly + // Also assert that the value of 'key' is set correctly inside SpecificCacheStoreService according to the current context expect(cache()->store($cacheStore)->get('key'))->toBe('central-value'); $this->app->make(SpecificCacheStoreService::class)->handle(); expect(cache()->store($cacheStore)->get('key'))->toBe($tenant1->getTenantKey()); @@ -205,10 +211,11 @@ expect(cache()->store($cacheStore)->get('key'))->toBe($tenant2->getTenantKey()); tenancy()->end(); + // We last executed handle() in tenant2's context, so the value should persist as tenant2's id expect(cache()->store($cacheStore)->get('key'))->toBe($tenant2->getTenantKey()); }); -test('only the stores specified in tenantCacheStores get prefixed', function() { +test('only the stores specified in tenantCacheStores get prefixed', function () { // Make sure the currently used store ('redis') is the only store in $tenantCacheStores PrefixCacheTenancyBootstrapper::$tenantCacheStores = [$prefixedStore = 'redis']; @@ -250,34 +257,12 @@ $this->app->make(CacheService::class)->handle(); expect(cache('key'))->toBe($centralValue); - - $tenant1 = Tenant::create(); - $tenant2 = Tenant::create(); - - tenancy()->initialize($tenant1); - - expect(cache('key'))->toBeNull(); - $this->app->make(CacheService::class)->handle(); - expect(cache('key'))->toBe($tenant1->getTenantKey()); - - $assertStoreIsNotPrefixed('redis2'); - - tenancy()->initialize($tenant2); - - expect(cache('key'))->toBeNull(); - $this->app->make(CacheService::class)->handle(); - expect(cache('key'))->toBe($tenant2->getTenantKey()); - - $assertStoreIsNotPrefixed('redis2'); - - tenancy()->end(); - expect(cache('key'))->toBe($centralValue); }); test('non default stores get prefixed too when specified in tenantCacheStores', function () { // In beforeEach, we set $tenantCacheStores to ['redis', 'redis2'] - // Make 'redis2' the default cache driver - config(['cache.default' => 'redis2']); + // Make 'redis' the default cache driver + config(['cache.default' => 'redis']); $tenant = Tenant::create(); $defaultPrefix = cache()->store()->getPrefix(); @@ -285,13 +270,14 @@ // The prefix is the same for both drivers in the central context expect(cache()->store('redis')->getPrefix())->toBe($defaultPrefix); + expect(cache()->store('redis2')->getPrefix())->toBe($defaultPrefix); tenancy()->initialize($tenant); - // We didn't add a prefix generator for our 'redis' driver, so we expect the prefix to be generated using the 'default' generator + // We didn't add a prefix generator for our 'redis2' driver, so we expect the prefix to be generated using the 'default' generator expect($bootstrapper->generatePrefix($tenant) . ':') ->toBe(cache()->getPrefix()) - ->toBe(cache()->store('redis')->getPrefix()); // Non-default store + ->toBe(cache()->store('redis2')->getPrefix()); // Non-default store tenancy()->end(); }); @@ -315,21 +301,6 @@ ->toBe(app('cache')->getPrefix()) ->toBe(app('cache.store')->getPrefix()); - config(['cache.default' => 'redis2']); - - // Use different prefix generator - PrefixCacheTenancyBootstrapper::generatePrefixUsing($customPrefixGenerator = function (Tenant $tenant) { - return 'redis2_tenant_cache_' . $tenant->getTenantKey(); - }); - - tenancy()->initialize($tenant = Tenant::create()); - - expect($customPrefixGenerator($tenant) . ':') - ->toBe(cache()->getPrefix()) - ->toBe(cache()->store('redis')->getPrefix()) - ->toBe(app('cache')->getPrefix()) - ->toBe(app('cache.store')->getPrefix()); - tenancy()->end(); });