Skip to content

Commit 4b823fc

Browse files
committed
Configure globalCache's DB stores to use central connection instead of default connection every time it's reinstantiated
1 parent f5e03bf commit 4b823fc

3 files changed

Lines changed: 48 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ jobs:
1616
strategy:
1717
matrix:
1818
include:
19-
- laravel: "^12.0"
19+
- laravel: "dev-dbstore-setconnection" # todo0 revert along with require (8 lines below)
2020
php: "8.4"
2121

2222
steps:
2323
- name: Checkout
2424
uses: actions/checkout@v2
2525
- name: Install Composer dependencies
2626
run: |
27-
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
27+
composer require "stancl/framework:${{ matrix.laravel }}" --no-interaction --no-update
2828
composer update --prefer-dist --no-interaction
2929
- name: Run tests
3030
if: ${{ ! env.ACT }}

src/Bootstrappers/DatabaseCacheBootstrapper.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
use Exception;
88
use Illuminate\Cache\CacheManager;
99
use Illuminate\Config\Repository;
10+
use Illuminate\Support\Facades\DB;
1011
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
1112
use Stancl\Tenancy\Contracts\Tenant;
13+
use Stancl\Tenancy\TenancyServiceProvider;
1214

1315
/**
1416
* This bootstrapper allows cache to be stored in the tenant databases by switching
@@ -55,6 +57,22 @@ public function bootstrap(Tenant $tenant): void
5557

5658
$this->cache->purge($storeName);
5759
}
60+
61+
// Preferably we'd try to respect the original value of this static property -- store it in a variable,
62+
// pull it into the closure, and execute it there. But such a naive approach would lead to existing callbacks
63+
// *from here* being executed repeatedly in a loop on reinitialization. For that reason we do not do that
64+
// (this is our only use of $adjustCacheManagerUsing anyway) but ideally at some point we'd have a better solution.
65+
TenancyServiceProvider::$adjustCacheManagerUsing = function (CacheManager $manager) use ($stores) {
66+
foreach ($stores as $storeName) {
67+
$manager->store($storeName)->getStore()->setConnection(
68+
DB::connection($this->originalConnections[$storeName] ?? config('tenancy.database.central_connection'))
69+
);
70+
71+
$manager->store($storeName)->getStore()->setLockConnection(
72+
DB::connection($this->originalLockConnections[$storeName] ?? config('tenancy.database.central_connection'))
73+
);
74+
}
75+
};
5876
}
5977

6078
public function revert(): void

src/TenancyServiceProvider.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ class TenancyServiceProvider extends ServiceProvider
2323
public static bool $registerForgetTenantParameterListener = true;
2424
public static bool $migrateFreshOverride = true;
2525

26+
/** @internal */
27+
public static Closure|null $adjustCacheManagerUsing = null;
28+
2629
/* Register services. */
2730
public function register(): void
2831
{
@@ -80,8 +83,32 @@ public function register(): void
8083
return new Commands\Seed($app['db']);
8184
});
8285

86+
// todo0 check how the caching in the facade affects our logic here
87+
// todo0 check what happens if globalCache is injected - it may be
88+
// problematic if it's injected before adjustCacheManagerUsing
89+
// was used
90+
8391
$this->app->bind('globalCache', function ($app) {
84-
return new CacheManager($app);
92+
// We create a separate CacheManager to be used for "global" cache -- cache that
93+
// is always central, regardless of the current context.
94+
//
95+
// Importantly, we use a regular binding here, not a singleton. Thanks to that,
96+
// any time we resolve this cache manager, we get a *fresh* instance -- an instance
97+
// that was not affected by any scoping logic.
98+
//
99+
// This works great for cache stores that are *directly* scoped, like Redis or
100+
// any other tagged or prefixed stores, but it doesn't work for the database driver.
101+
//
102+
// When we use the DatabaseTenancyBootstrapper, it changes the default connection,
103+
// and therefore the connection of the database store that will be created when
104+
// this new CacheManager is instantiated again.
105+
$manager = new CacheManager($app);
106+
107+
if (static::$adjustCacheManagerUsing !== null) {
108+
(static::$adjustCacheManagerUsing)($manager);
109+
}
110+
111+
return $manager;
85112
});
86113
}
87114

0 commit comments

Comments
 (0)