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

simplify code

This commit is contained in:
Samuel Stancl 2026-08-03 23:45:10 -07:00
parent 6b6279832e
commit 0765bfc757
No known key found for this signature in database
GPG key ID: BA146259A1E16C57
2 changed files with 32 additions and 79 deletions

View file

@ -14,21 +14,8 @@ use Stancl\Tenancy\Contracts\Tenant;
class FilesystemTenancyBootstrapper implements TenancyBootstrapper class FilesystemTenancyBootstrapper implements TenancyBootstrapper
{ {
public array $originalDisks = []; public array $originalDisks = [];
/**
* The path and lock_path each file cache store had in the central context, keyed by store name.
*
* For example:
* [
* 'file' => [
* 'path' => storage_path('framework/cache/data'),
* 'lock_path' => storage_path('framework/cache/data'),
* ],
* ]
*
* Used to scope the store to a tenant, and to restore it back to this when tenancy ends.
*/
protected array $originalCachePaths = []; protected array $originalCachePaths = [];
protected array $originalCacheLockPaths = [];
public string|null $originalAssetUrl; public string|null $originalAssetUrl;
public string $originalStoragePath; public string $originalStoragePath;
@ -46,7 +33,6 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
$this->storagePath($suffix); $this->storagePath($suffix);
$this->assetHelper($suffix); $this->assetHelper($suffix);
$this->forgetDisks(); $this->forgetDisks();
$this->storeOriginalCachePaths();
$this->scopeCache($suffix); $this->scopeCache($suffix);
$this->scopeSessions($suffix); $this->scopeSessions($suffix);
@ -201,61 +187,40 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
} }
} }
/** Returns the names of the file-driver stores listed in tenancy.cache.stores. */
protected function fileCacheStores(): array
{
return array_filter($this->app['config']['tenancy.cache.stores'], function ($name) {
$store = $this->app['config']["cache.stores.{$name}"];
if ($store === null) {
return false;
}
return $store['driver'] === 'file';
});
}
/**
* Store the original configured cache paths, so that they can be properly scoped
* to a tenant and restored back to the central context when tenancy ends.
*/
protected function storeOriginalCachePaths(): void
{
if (! $this->app['config']['tenancy.filesystem.scope_cache']) {
return;
}
foreach ($this->fileCacheStores() as $name) {
// Capture the paths only once. The config holds the central values on the first
// bootstrap, but not necessarily later (if an earlier bootstrap threw, revert() didn't run).
$this->originalCachePaths[$name] ??= [
'path' => $this->app['config']["cache.stores.{$name}.path"],
'lock_path' => $this->app['config']["cache.stores.{$name}.lock_path"],
];
}
}
public function scopeCache(string|false $suffix): void public function scopeCache(string|false $suffix): void
{ {
if (! $this->app['config']['tenancy.filesystem.scope_cache']) { if (! $this->app['config']['tenancy.filesystem.scope_cache']) {
return; return;
} }
foreach ($this->fileCacheStores() as $name) { foreach ($this->app['config']['tenancy.cache.stores'] as $name) {
if (! isset($this->originalCachePaths[$name])) { $store = $this->app['config']["cache.stores.{$name}"];
// Only scope stores captured during bootstrap. If one was added to tenancy.cache.stores
// mid-request, it has no original path here -- reading it would throw when tenancy ends. // Only file stores have a path to scope. Skip stores that don't exist (null) or use another driver.
if ($store === null || $store['driver'] !== 'file') {
continue; continue;
} }
$path = $this->scopeCachePath($this->originalCachePaths[$name]['path'], $suffix); if ($suffix !== false && ! isset($this->originalCachePaths[$name])) {
$lockPath = $this->originalCachePaths[$name]['lock_path']; $this->originalCachePaths[$name] = $store['path'];
if ($lockPath !== null) { $this->originalCacheLockPaths[$name] = $store['lock_path'] ?? null;
// Unlike path, lock_path is optional -- if it's not set, FileStore::lock() falls }
// back to path itself (see `$this->lockDirectory ?? $this->directory` in FileStore).
// Leave it null here rather than hardcoding it to $path ourselves, so a store that didn't // Only scope stores captured during bootstrap. If one was added to tenancy.cache.stores
// configure a separate lock_path doesn't end up with one. // mid-request, it has no original path here -- reading it would throw when tenancy ends.
$lockPath = $this->scopeCachePath($lockPath, $suffix); if (! isset($this->originalCachePaths[$name])) {
continue;
}
$path = $suffix ? $this->tenantCachePath($this->originalCachePaths[$name], $suffix) : $this->originalCachePaths[$name];
// Unlike path, lock_path is optional -- if it's not set, FileStore::lock() falls back to path
// itself (see `$this->lockDirectory ?? $this->directory` in FileStore). Leave it null here rather
// than hardcoding it to $path ourselves, so a store that didn't configure a separate lock_path
// doesn't end up with one.
$lockPath = $this->originalCacheLockPaths[$name];
if ($suffix && $lockPath !== null) {
$lockPath = $this->tenantCachePath($lockPath, $suffix);
} }
$this->app['config']["cache.stores.{$name}.path"] = $path; $this->app['config']["cache.stores.{$name}.path"] = $path;
@ -268,32 +233,20 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
} }
} }
/** /** Scope a configured cache path (path or lock_path) to the tenant identified by $suffix. */
* Return a configured path ($configuredPath is e.g. storage_path('framework/cache/data')), protected function tenantCachePath(string $configuredPath, string $suffix): string
* scoped to the current tenant when called from bootstrap(),
* or unchanged when called from revert() (= when $suffix is false).
*/
protected function scopeCachePath(string $configuredPath, string|false $suffix): string
{ {
if ($suffix === false) {
return $configuredPath;
}
if (str_starts_with($configuredPath, $this->originalStoragePath . '/')) { if (str_starts_with($configuredPath, $this->originalStoragePath . '/')) {
// Swap the central storage path prefix for the tenant's. // Swap the central storage path prefix for the tenant's.
// For example, storage_path('framework/cache/data') becomes storage_path('tenant1/framework/cache/data'). // For example, storage_path('framework/cache/data') becomes storage_path('tenant1/framework/cache/data').
$scopedPath = str($configuredPath) return str($configuredPath)
->after($this->originalStoragePath . '/') ->after($this->originalStoragePath . '/')
->prepend($this->tenantStoragePath($suffix) . '/') ->prepend($this->tenantStoragePath($suffix) . '/')
->toString(); ->toString();
} else {
// Append the tenant suffix so tenants don't share the same cache directory. $configuredPath
// isn't guaranteed to be storage_path()-based (e.g. it could point to a shared network
// mount used to keep the file cache off each server's local disk in a multi-server setup).
$scopedPath = rtrim($configuredPath, '/') . '/' . $suffix;
} }
return $scopedPath; // Otherwise $configuredPath isn't necessarily storage_path()-based, so just append the suffix directly.
return rtrim($configuredPath, '/') . '/' . $suffix;
} }
public function scopeSessions(string|false $suffix): void public function scopeSessions(string|false $suffix): void

View file

@ -500,7 +500,7 @@ test('a cache store without a configured lock_path is scoped without error', fun
}); });
test('a cache store using a path not based on storage_path() is suffixed in place, not moved under the tenant storage path', function () { test('a cache store using a path not based on storage_path() is suffixed in place, not moved under the tenant storage path', function () {
// $path below doesn't start with the central storage path, so scopeCachePath() has no storage // $path below doesn't start with the central storage path, so tenantCachePath() has no storage
// path prefix to swap for the tenant's -- it appends the tenant suffix directly to $path instead. // path prefix to swap for the tenant's -- it appends the tenant suffix directly to $path instead.
// Check that tenant isolation still works for a store configured like this, and that its cache // Check that tenant isolation still works for a store configured like this, and that its cache
// ends up at $path itself, not under the tenant's storage path. // ends up at $path itself, not under the tenant's storage path.