1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-08-06 04:54:04 +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
{
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 $originalCacheLockPaths = [];
public string|null $originalAssetUrl;
public string $originalStoragePath;
@ -46,7 +33,6 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
$this->storagePath($suffix);
$this->assetHelper($suffix);
$this->forgetDisks();
$this->storeOriginalCachePaths();
$this->scopeCache($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
{
if (! $this->app['config']['tenancy.filesystem.scope_cache']) {
return;
}
foreach ($this->fileCacheStores() as $name) {
if (! isset($this->originalCachePaths[$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.
foreach ($this->app['config']['tenancy.cache.stores'] as $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.
if ($store === null || $store['driver'] !== 'file') {
continue;
}
$path = $this->scopeCachePath($this->originalCachePaths[$name]['path'], $suffix);
$lockPath = $this->originalCachePaths[$name]['lock_path'];
if ($lockPath !== 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
// configure a separate lock_path doesn't end up with one.
$lockPath = $this->scopeCachePath($lockPath, $suffix);
if ($suffix !== false && ! isset($this->originalCachePaths[$name])) {
$this->originalCachePaths[$name] = $store['path'];
$this->originalCacheLockPaths[$name] = $store['lock_path'] ?? null;
}
// 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.
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;
@ -268,32 +233,20 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
}
}
/**
* Return a configured path ($configuredPath is e.g. storage_path('framework/cache/data')),
* 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
/** Scope a configured cache path (path or lock_path) to the tenant identified by $suffix. */
protected function tenantCachePath(string $configuredPath, string $suffix): string
{
if ($suffix === false) {
return $configuredPath;
}
if (str_starts_with($configuredPath, $this->originalStoragePath . '/')) {
// Swap the central storage path prefix for the tenant's.
// For example, storage_path('framework/cache/data') becomes storage_path('tenant1/framework/cache/data').
$scopedPath = str($configuredPath)
return str($configuredPath)
->after($this->originalStoragePath . '/')
->prepend($this->tenantStoragePath($suffix) . '/')
->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

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 () {
// $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.
// 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.