1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 20:14:03 +00:00

Configure globalCache's DB stores to use central connection instead of default connection every time it's reinstantiated

This commit is contained in:
Samuel Štancl 2025-08-05 21:00:56 +02:00
parent f5e03bff62
commit 4b823fca7d
3 changed files with 48 additions and 3 deletions

View file

@ -16,7 +16,7 @@ jobs:
strategy: strategy:
matrix: matrix:
include: include:
- laravel: "^12.0" - laravel: "dev-dbstore-setconnection" # todo0 revert along with require (8 lines below)
php: "8.4" php: "8.4"
steps: steps:
@ -24,7 +24,7 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Install Composer dependencies - name: Install Composer dependencies
run: | run: |
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update composer require "stancl/framework:${{ matrix.laravel }}" --no-interaction --no-update
composer update --prefer-dist --no-interaction composer update --prefer-dist --no-interaction
- name: Run tests - name: Run tests
if: ${{ ! env.ACT }} if: ${{ ! env.ACT }}

View file

@ -7,8 +7,10 @@ namespace Stancl\Tenancy\Bootstrappers;
use Exception; use Exception;
use Illuminate\Cache\CacheManager; use Illuminate\Cache\CacheManager;
use Illuminate\Config\Repository; use Illuminate\Config\Repository;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
use Stancl\Tenancy\TenancyServiceProvider;
/** /**
* This bootstrapper allows cache to be stored in the tenant databases by switching * This bootstrapper allows cache to be stored in the tenant databases by switching
@ -55,6 +57,22 @@ class DatabaseCacheBootstrapper implements TenancyBootstrapper
$this->cache->purge($storeName); $this->cache->purge($storeName);
} }
// Preferably we'd try to respect the original value of this static property -- store it in a variable,
// pull it into the closure, and execute it there. But such a naive approach would lead to existing callbacks
// *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.
TenancyServiceProvider::$adjustCacheManagerUsing = function (CacheManager $manager) use ($stores) {
foreach ($stores as $storeName) {
$manager->store($storeName)->getStore()->setConnection(
DB::connection($this->originalConnections[$storeName] ?? config('tenancy.database.central_connection'))
);
$manager->store($storeName)->getStore()->setLockConnection(
DB::connection($this->originalLockConnections[$storeName] ?? config('tenancy.database.central_connection'))
);
}
};
} }
public function revert(): void public function revert(): void

View file

@ -23,6 +23,9 @@ class TenancyServiceProvider extends ServiceProvider
public static bool $registerForgetTenantParameterListener = true; public static bool $registerForgetTenantParameterListener = true;
public static bool $migrateFreshOverride = true; public static bool $migrateFreshOverride = true;
/** @internal */
public static Closure|null $adjustCacheManagerUsing = null;
/* Register services. */ /* Register services. */
public function register(): void public function register(): void
{ {
@ -80,8 +83,32 @@ class TenancyServiceProvider extends ServiceProvider
return new Commands\Seed($app['db']); return new Commands\Seed($app['db']);
}); });
// todo0 check how the caching in the facade affects our logic here
// todo0 check what happens if globalCache is injected - it may be
// problematic if it's injected before adjustCacheManagerUsing
// was used
$this->app->bind('globalCache', function ($app) { $this->app->bind('globalCache', function ($app) {
return new CacheManager($app); // We create a separate CacheManager to be used for "global" cache -- cache that
// is always central, regardless of the current context.
//
// Importantly, we use a regular binding here, not a singleton. Thanks to that,
// any time we resolve this cache manager, we get a *fresh* instance -- an instance
// that was not affected by any scoping logic.
//
// This works great for cache stores that are *directly* scoped, like Redis or
// any other tagged or prefixed stores, but it doesn't work for the database driver.
//
// When we use the DatabaseTenancyBootstrapper, it changes the default connection,
// and therefore the connection of the database store that will be created when
// this new CacheManager is instantiated again.
$manager = new CacheManager($app);
if (static::$adjustCacheManagerUsing !== null) {
(static::$adjustCacheManagerUsing)($manager);
}
return $manager;
}); });
} }