1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-08-06 05:54:03 +00:00

Handle tenancy.cache.stores changes during revert

Also add a separate test ('scopeCache ignores changes to tenancy.cache.stores made in tenant context' ) -- the 'central cache is not lost when tenancy ends' covered the skipping mechanism partially, but having a separate test for the tenancy.cache.stores mid-tenant context changes is definitely cleaner and makes more sense.
This commit is contained in:
lukinovec 2026-08-04 18:21:21 +02:00
parent 597e48ec90
commit 8244e56618
2 changed files with 57 additions and 21 deletions

View file

@ -193,7 +193,14 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
return; return;
} }
foreach ($this->app['config']['tenancy.cache.stores'] as $name) { // On revert, restore exactly the stores captured during bootstrap -- not the current
// (possibly mutated) tenancy.cache.stores. Otherwise, removing a store from that
// config in tenant context would make revert() skip it (so the store would be stuck with a tenant-scoped path).
$stores = $suffix !== false
? $this->app['config']['tenancy.cache.stores']
: array_keys($this->originalCachePaths);
foreach ($stores as $name) {
$store = $this->app['config']["cache.stores.{$name}"]; $store = $this->app['config']["cache.stores.{$name}"];
// Only file stores have a path to scope. Skip stores that don't exist (null) or use another driver. // Only file stores have a path to scope. Skip stores that don't exist (null) or use another driver.

View file

@ -366,11 +366,9 @@ test('file cache stores are separated per tenant', function () {
test('central cache is not lost when tenancy ends', function () { test('central cache is not lost when tenancy ends', function () {
$path = storage_path('framework/cache/foo_file'); $path = storage_path('framework/cache/foo_file');
$barPath = storage_path('framework/cache/bar_file');
File::deleteDirectory($path); File::deleteDirectory($path);
File::deleteDirectory($barPath);
// Use a separate 'foo' store rather than reconfiguring 'file'. // Use a separate 'foo_file' store rather than reconfiguring 'file'.
// TestCase::setUp() calls `cache:clear file`, which resolves the 'file' store and leaves it // TestCase::setUp() calls `cache:clear file`, which resolves the 'file' store and leaves it
// in the CacheManager with the default path. A later config() call can't mutate that, so a test // in the CacheManager with the default path. A later config() call can't mutate that, so a test
// reconfiguring 'file' would keep using storage/framework/cache/data and pass either way. // reconfiguring 'file' would keep using storage/framework/cache/data and pass either way.
@ -384,36 +382,67 @@ test('central cache is not lost when tenancy ends', function () {
'path' => $path, 'path' => $path,
'lock_path' => $path, 'lock_path' => $path,
], ],
'cache.stores.bar_file' => [
'driver' => 'file',
'path' => $barPath,
'lock_path' => $barPath,
],
// Only include foo_file in tenancy.cache.stores,
// leave bar_file excluded (= not scoped by FilesystemTenancyBootstrapper) for now.
'tenancy.cache.stores' => ['foo_file'], 'tenancy.cache.stores' => ['foo_file'],
]); ]);
$tenant = Tenant::create();
Cache::store('foo_file')->put('foo', 'central'); Cache::store('foo_file')->put('foo', 'central');
// Just initialize and revert tenancy to trigger FilesystemTenancyBootstrapper // Just initialize and revert tenancy to trigger FilesystemTenancyBootstrapper
tenancy()->initialize($tenant); tenancy()->initialize(Tenant::create());
// bar_file wasn't in tenancy.cache.stores during bootstrap, so no original path was stored for it,
// and it's left with its configured path (not scoped).
config(['tenancy.cache.stores' => ['foo_file', 'bar_file']]);
Cache::store('bar_file')->put('bar', 'not scoped');
tenancy()->end(); tenancy()->end();
// Nothing deleted the 'foo' entry, so its value should stay 'central' even after reverting tenancy. // Nothing deleted the 'foo' entry, so its value should stay 'central' even after reverting tenancy.
// FilesystemTenancyBootstrapper::revert() makes the store use its original configured path. // FilesystemTenancyBootstrapper::revert() makes the store use its original configured path.
expect(Cache::store('foo_file')->get('foo'))->toBe('central'); expect(Cache::store('foo_file')->get('foo'))->toBe('central');
expect(Cache::store('bar_file')->get('bar'))->toBe('not scoped');
File::deleteDirectory($path); File::deleteDirectory($path);
});
test('scopeCache ignores changes to tenancy.cache.stores made in tenant context', function () {
$fooPath = storage_path('framework/cache/foo_file');
$barPath = storage_path('framework/cache/bar_file');
File::deleteDirectory($fooPath);
File::deleteDirectory($barPath);
config([
'tenancy.bootstrappers' => [
FilesystemTenancyBootstrapper::class,
],
'cache.stores.foo_file' => [
'driver' => 'file',
'path' => $fooPath,
'lock_path' => $fooPath,
],
'cache.stores.bar_file' => [
'driver' => 'file',
'path' => $barPath,
'lock_path' => $barPath,
],
// Only foo_file is scoped at bootstrap()
'tenancy.cache.stores' => ['foo_file'],
]);
Cache::store('foo_file')->put('key', 'central');
Cache::store('bar_file')->put('key', 'central');
tenancy()->initialize(Tenant::create());
Cache::store('foo_file')->put('key', 'tenant');
// bar_file wasn't in tenancy.cache.stores during bootstrap, so no original path was captured for it,
// and it uses its configured path (central, not scoped).
config(['tenancy.cache.stores' => ['foo_file', 'bar_file']]);
expect(Cache::store('bar_file')->get('key'))->toBe('central');
// Remove foo_file from tenancy.cache.stores (original path was captured during bootstrap) in tenant context
config(['tenancy.cache.stores' => ['bar_file']]);
tenancy()->end();
// revert() still restores foo_file to its central path
expect(Cache::store('foo_file')->get('key'))->toBe('central');
File::deleteDirectory($fooPath);
File::deleteDirectory($barPath); File::deleteDirectory($barPath);
}); });