mirror of
https://github.com/archtechx/tenancy.git
synced 2026-06-21 01:54:03 +00:00
Merge ff8f73ec08 into 652bc987ce
This commit is contained in:
commit
6ca9ce9c93
5 changed files with 39 additions and 6 deletions
|
|
@ -16,6 +16,15 @@ use Stancl\Tenancy\Contracts\Tenant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes cache tenant-aware by applying a prefix.
|
* Makes cache tenant-aware by applying a prefix.
|
||||||
|
*
|
||||||
|
* Using this bootstrapper together with DatabaseTenancyBootstrapper
|
||||||
|
* with a database cache store results in double scoping. The store is scoped by
|
||||||
|
* DB connection (entries go into the tenant's database) *and* by the prefix. This is
|
||||||
|
* harmless for most use cases, but can produce unexpected behavior.
|
||||||
|
*
|
||||||
|
* If you're using a database cache store, use DatabaseCacheBootstrapper instead of this one.
|
||||||
|
*
|
||||||
|
* @see Stancl\Tenancy\Bootstrappers\DatabaseCacheBootstrapper
|
||||||
*/
|
*/
|
||||||
class CacheTenancyBootstrapper implements TenancyBootstrapper
|
class CacheTenancyBootstrapper implements TenancyBootstrapper
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,10 @@ use Stancl\Tenancy\TenancyServiceProvider;
|
||||||
*
|
*
|
||||||
* Notably, this bootstrapper sets TenancyServiceProvider::$adjustCacheManagerUsing to a callback
|
* Notably, this bootstrapper sets TenancyServiceProvider::$adjustCacheManagerUsing to a callback
|
||||||
* that ensures all affected stores still use the central connection when accessed via global cache
|
* that ensures all affected stores still use the central connection when accessed via global cache
|
||||||
* (typicaly the GlobalCache facade or global_cache() helper).
|
* (typically the GlobalCache facade or global_cache() helper), even though this bootstrapper explicitly
|
||||||
|
* sets the connection to tenant for all scoped cache stores. Extending database store on the global cache manager
|
||||||
|
* cannot fix globalCache on its own because it reads 'tenant' from config (set by this bootstrapper), not null,
|
||||||
|
* so the callback is still needed to correct the connection to central for globalCache.
|
||||||
*/
|
*/
|
||||||
class DatabaseCacheBootstrapper implements TenancyBootstrapper
|
class DatabaseCacheBootstrapper implements TenancyBootstrapper
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -86,14 +86,33 @@ class TenancyServiceProvider extends ServiceProvider
|
||||||
// This works great for cache stores that are *directly* scoped, like Redis or
|
// 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.
|
// 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,
|
// When DatabaseTenancyBootstrapper is used, it changes the default DB connection
|
||||||
// and therefore the connection of the database store that will be created when
|
// to 'tenant'. A freshly created CacheManager would therefore instantiate database
|
||||||
// this new CacheManager is instantiated again.
|
// stores with the tenant connection.
|
||||||
//
|
//
|
||||||
// For that reason, we also adjust the relevant stores on this new CacheManager
|
// For that reason, we override the 'database' driver creator on this manager so that
|
||||||
// using the callback below. It is set by DatabaseCacheBootstrapper.
|
// database stores are built with the central connection, and we run the
|
||||||
|
// $adjustCacheManagerUsing callback below (set by DatabaseCacheBootstrapper).
|
||||||
$manager = new CacheManager($app);
|
$manager = new CacheManager($app);
|
||||||
|
|
||||||
|
// When DatabaseTenancyBootstrapper is used, database stores whose 'connection'
|
||||||
|
// config is null fall back to the default DB connection ('tenant'). Reset each
|
||||||
|
// such store to its explicitly configured connection, or fall back to central.
|
||||||
|
$centralConnection = $app['config']['tenancy.database.central_connection'];
|
||||||
|
|
||||||
|
$manager->extend('database', function ($app, array $config) use ($centralConnection) {
|
||||||
|
$config['connection'] ??= $centralConnection;
|
||||||
|
|
||||||
|
/** @var CacheManager $this */
|
||||||
|
return $this->createDatabaseDriver($config); // @phpstan-ignore method.protected
|
||||||
|
});
|
||||||
|
|
||||||
|
// DatabaseCacheBootstrapper explicitly writes 'tenant' into each store's 'connection'
|
||||||
|
// config. The database store extend above would then read 'tenant' as the
|
||||||
|
// configured value (not null) and use it directly, so the central connection fallback
|
||||||
|
// wouldn't be used.
|
||||||
|
//
|
||||||
|
// This callback is used to correct those connections back to central for globalCache.
|
||||||
if (static::$adjustCacheManagerUsing !== null) {
|
if (static::$adjustCacheManagerUsing !== null) {
|
||||||
(static::$adjustCacheManagerUsing)($manager);
|
(static::$adjustCacheManagerUsing)($manager);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,7 @@ test('cache is invalidated when tenant is updated from within the tenant context
|
||||||
['redis', [CacheTenancyBootstrapper::class]],
|
['redis', [CacheTenancyBootstrapper::class]],
|
||||||
['redis', [CacheTagsBootstrapper::class]],
|
['redis', [CacheTagsBootstrapper::class]],
|
||||||
['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
|
['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
|
||||||
|
['database', [DatabaseTenancyBootstrapper::class, CacheTenancyBootstrapper::class]],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
test('cache is invalidated when the tenant is deleted', function (string $resolver, bool $configureTenantModelColumn) {
|
test('cache is invalidated when the tenant is deleted', function (string $resolver, bool $configureTenantModelColumn) {
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,7 @@ test('global cache is always central', function (string $store, array $bootstrap
|
||||||
['redis', [CacheTagsBootstrapper::class]],
|
['redis', [CacheTagsBootstrapper::class]],
|
||||||
['redis', [CacheTenancyBootstrapper::class]],
|
['redis', [CacheTenancyBootstrapper::class]],
|
||||||
['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
|
['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
|
||||||
|
['database', [DatabaseTenancyBootstrapper::class, CacheTenancyBootstrapper::class]],
|
||||||
])->with([
|
])->with([
|
||||||
'helper',
|
'helper',
|
||||||
'facade',
|
'facade',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue