1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-07 02:24:03 +00:00

Merge branch 'master' into add-log-bootstrapper

This commit is contained in:
Samuel Štancl 2026-04-12 14:02:39 +02:00 committed by GitHub
commit 39fc72bea5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 1127 additions and 221 deletions

View file

@ -15,7 +15,7 @@ use Stancl\Tenancy\Overrides\TenancyBroadcastManager;
class BroadcastingConfigBootstrapper implements TenancyBootstrapper
{
/**
* Tenant properties to be mapped to config (similarly to the TenantConfig feature).
* Tenant properties to be mapped to config (similarly to the TenantConfigBootstrapper).
*
* For example:
* [

View file

@ -102,14 +102,7 @@ class CacheTenancyBootstrapper implements TenancyBootstrapper
if ($this->config->get('tenancy.cache.scope_sessions', true)) {
// These are the only cache driven session backends (see Laravel's config/session.php)
if (! in_array($this->config->get('session.driver'), ['redis', 'memcached', 'dynamodb', 'apc'], true)) {
if (app()->environment('production')) {
// We only throw this exception in prod to make configuration a little easier. Developers
// may have scope_sessions set to true while using different session drivers e.g. in tests.
// Previously we just silently ignored this, however since session scoping is of high importance
// in production, we make sure to notify the developer, by throwing an exception, that session
// scoping isn't happening as expected/configured due to an incompatible session driver.
throw new Exception('Session driver [' . $this->config->get('session.driver') . '] cannot be scoped by tenancy.cache.scope_session');
}
throw new Exception('Session driver [' . $this->config->get('session.driver') . '] cannot be scoped by tenancy.cache.scope_sessions');
} else {
// Scoping sessions using this bootstrapper implicitly adds the session store to $names
$names[] = $this->getSessionCacheStoreName();

View file

@ -63,13 +63,17 @@ class DatabaseCacheBootstrapper implements TenancyBootstrapper
$stores = $this->scopedStoreNames();
foreach ($stores as $storeName) {
$this->originalConnections[$storeName] = $this->config->get("cache.stores.{$storeName}.connection");
$this->originalLockConnections[$storeName] = $this->config->get("cache.stores.{$storeName}.lock_connection");
$this->originalConnections[$storeName] = $this->config->get("cache.stores.{$storeName}.connection") ?? config('tenancy.database.central_connection');
$this->originalLockConnections[$storeName] = $this->config->get("cache.stores.{$storeName}.lock_connection") ?? config('tenancy.database.central_connection');
$this->config->set("cache.stores.{$storeName}.connection", 'tenant');
$this->config->set("cache.stores.{$storeName}.lock_connection", 'tenant');
$this->cache->purge($storeName);
/** @var DatabaseStore $store */
$store = $this->cache->store($storeName)->getStore();
$store->setConnection(DB::connection('tenant'));
$store->setLockConnection(DB::connection('tenant'));
}
if (static::$adjustGlobalCacheManager) {
@ -78,8 +82,8 @@ class DatabaseCacheBootstrapper implements TenancyBootstrapper
// *from here* being executed repeatedly in a loop on reinitialization. For that reason we do not do that
// (this is our only use of $adjustCacheManagerUsing anyway) but ideally at some point we'd have a better solution.
$originalConnections = array_combine($stores, array_map(fn (string $storeName) => [
'connection' => $this->originalConnections[$storeName] ?? config('tenancy.database.central_connection'),
'lockConnection' => $this->originalLockConnections[$storeName] ?? config('tenancy.database.central_connection'),
'connection' => $this->originalConnections[$storeName],
'lockConnection' => $this->originalLockConnections[$storeName],
], $stores));
TenancyServiceProvider::$adjustCacheManagerUsing = static function (CacheManager $manager) use ($originalConnections) {
@ -100,7 +104,11 @@ class DatabaseCacheBootstrapper implements TenancyBootstrapper
$this->config->set("cache.stores.{$storeName}.connection", $originalConnection);
$this->config->set("cache.stores.{$storeName}.lock_connection", $this->originalLockConnections[$storeName]);
$this->cache->purge($storeName);
/** @var DatabaseStore $store */
$store = $this->cache->store($storeName)->getStore();
$store->setConnection(DB::connection($this->originalConnections[$storeName]));
$store->setLockConnection(DB::connection($this->originalLockConnections[$storeName]));
}
TenancyServiceProvider::$adjustCacheManagerUsing = null;

View file

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Bootstrappers;
use Illuminate\Foundation\Application;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Session\FileSessionHandler;
use Illuminate\Support\Facades\Storage;
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
@ -22,13 +21,6 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
) {
$this->originalAssetUrl = $this->app['config']['app.asset_url'];
$this->originalStoragePath = $app->storagePath();
$this->app['url']->macro('setAssetRoot', function ($root) {
/** @var UrlGenerator $this */
$this->assetRoot = $root;
return $this;
});
}
public function bootstrap(Tenant $tenant): void
@ -78,6 +70,15 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
return;
}
$path = $suffix
? $this->tenantStoragePath($suffix) . '/framework/cache'
: $this->originalStoragePath . '/framework/cache';
if (! is_dir($path)) {
// Create tenant framework/cache directory if it does not exist
mkdir($path, 0750, true);
}
if ($suffix === false) {
$this->app->useStoragePath($this->originalStoragePath);
} else {
@ -98,22 +99,33 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
if ($suffix === false) {
$this->app['config']['app.asset_url'] = $this->originalAssetUrl;
$this->app['url']->setAssetRoot($this->originalAssetUrl);
$this->app['url']->useAssetOrigin($this->originalAssetUrl);
return;
}
if ($this->originalAssetUrl) {
$this->app['config']['app.asset_url'] = $this->originalAssetUrl . "/$suffix";
$this->app['url']->setAssetRoot($this->app['config']['app.asset_url']);
$this->app['url']->useAssetOrigin($this->app['config']['app.asset_url']);
} else {
$this->app['url']->setAssetRoot($this->app['url']->route('stancl.tenancy.asset', ['path' => '']));
$this->app['url']->useAssetOrigin($this->app['url']->route('stancl.tenancy.asset', ['path' => '']));
}
}
protected function forgetDisks(): void
{
Storage::forgetDisk($this->app['config']['tenancy.filesystem.disks']);
$tenantDisks = $this->app['config']['tenancy.filesystem.disks'];
$scopedDisks = [];
foreach ($this->app['config']['filesystems.disks'] as $name => $disk) {
if (isset($disk['driver'], $disk['disk'])
&& $disk['driver'] === 'scoped'
&& in_array($disk['disk'], $tenantDisks, true)) {
$scopedDisks[] = $name;
}
}
Storage::forgetDisk(array_merge($tenantDisks, $scopedDisks));
}
protected function diskRoot(string $disk, Tenant|false $tenant): void
@ -211,7 +223,7 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
if (! is_dir($path)) {
// Create tenant framework/sessions directory if it does not exist
mkdir($path, 0755, true);
mkdir($path, 0750, true);
}
$this->app['config']['session.files'] = $path;

View file

@ -12,7 +12,7 @@ use Stancl\Tenancy\Contracts\Tenant;
class MailConfigBootstrapper implements TenancyBootstrapper
{
/**
* Tenant properties to be mapped to config (similarly to the TenantConfig feature).
* Tenant properties to be mapped to config (similarly to the TenantConfigBootstrapper).
*
* For example:
* [

View file

@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Bootstrappers;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant;
use Stancl\Tenancy\Overrides\TenancyUrlGenerator;
@ -78,6 +79,10 @@ class UrlGeneratorBootstrapper implements TenancyBootstrapper
}
}
// Inherit scheme (http/https) from the original generator
$originalScheme = Str::before($this->originalUrlGenerator->formatScheme(), '://');
$newGenerator->forceScheme($originalScheme);
$newGenerator->defaults($defaultParameters);
$newGenerator->setSessionResolver(function () {