From ba4c80c615a87c317f7a61f9cac0d971095c7bb1 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 2 Jun 2026 12:53:53 +0200 Subject: [PATCH] Revert "Merge branch 'fix-cache-invalidation' into boilerplate-dev" This reverts commit 32fa4cca203b2cb1857076016c0189278f24f7c9, reversing changes made to 2dfbbef0f3357e2754e0a2a604a4ceefb85d3abc. --- docker-compose.yml | 4 +- src/Database/Concerns/PendingScope.php | 2 +- src/Database/ParentModelScope.php | 2 +- src/Database/TenantScope.php | 2 +- src/Jobs/DeleteDatabase.php | 26 +-------- src/TenancyServiceProvider.php | 39 ------------- tests/CachedTenantResolverTest.php | 1 - tests/DatabasePreparationTest.php | 77 -------------------------- tests/GlobalCacheTest.php | 1 - 9 files changed, 7 insertions(+), 147 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6cc03e12..70a68019 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,8 +80,8 @@ services: mssql: image: mcr.microsoft.com/mssql/server:2022-latest environment: - ACCEPT_EULA: "Y" - SA_PASSWORD: "P@ssword" # must be the same as TENANCY_TEST_SQLSRV_PASSWORD + - ACCEPT_EULA=Y + - SA_PASSWORD=P@ssword # must be the same as TENANCY_TEST_SQLSRV_PASSWORD healthcheck: # https://github.com/Microsoft/mssql-docker/issues/133#issuecomment-1995615432 test: timeout 2 bash -c 'cat < /dev/null > /dev/tcp/127.0.0.1/1433' interval: 10s diff --git a/src/Database/Concerns/PendingScope.php b/src/Database/Concerns/PendingScope.php index e8805d8a..99a5ef59 100644 --- a/src/Database/Concerns/PendingScope.php +++ b/src/Database/Concerns/PendingScope.php @@ -14,7 +14,7 @@ class PendingScope implements Scope /** * Apply the scope to a given Eloquent query builder. * - * @param Builder $builder + * @param Builder $builder * * @return void */ diff --git a/src/Database/ParentModelScope.php b/src/Database/ParentModelScope.php index 9268fea9..44f4ac12 100644 --- a/src/Database/ParentModelScope.php +++ b/src/Database/ParentModelScope.php @@ -12,7 +12,7 @@ use Illuminate\Database\Eloquent\Scope; class ParentModelScope implements Scope { /** - * @param Builder $builder + * @param Builder $builder */ public function apply(Builder $builder, Model $model): void { diff --git a/src/Database/TenantScope.php b/src/Database/TenantScope.php index c6ce5f09..94ff4572 100644 --- a/src/Database/TenantScope.php +++ b/src/Database/TenantScope.php @@ -13,7 +13,7 @@ use Stancl\Tenancy\Tenancy; class TenantScope implements Scope { /** - * @param Builder $builder + * @param Builder $builder */ public function apply(Builder $builder, Model $model) { diff --git a/src/Jobs/DeleteDatabase.php b/src/Jobs/DeleteDatabase.php index ad022fda..b59a1c05 100644 --- a/src/Jobs/DeleteDatabase.php +++ b/src/Jobs/DeleteDatabase.php @@ -22,34 +22,12 @@ class DeleteDatabase implements ShouldQueue protected TenantWithDatabase&Model $tenant, ) {} - /** Skip database deletion if the create_database internal attribute is false. */ - public static bool $skipWhenCreateDatabaseIsFalse = true; - - /** Ignore exceptions thrown during database deletion and continue execution. */ - public static bool $ignoreFailures = false; - public function handle(): void { - if (static::$skipWhenCreateDatabaseIsFalse && $this->tenant->getInternal('create_database') === false) { - // If database creation was skipped, we presume deletion should also be skipped. - // To avoid this skip, either unset the `create_database` attribute (or make it true), or - // set the $skipWhenCreateDatabaseIsFalse static property to false. - return; - } - event(new DeletingDatabase($this->tenant)); - $deleted = false; + $this->tenant->database()->manager()->deleteDatabase($this->tenant); - try { - $this->tenant->database()->manager()->deleteDatabase($this->tenant); - $deleted = true; - } catch (\Throwable $e) { - if (! static::$ignoreFailures) { - throw $e; - } - } - - if ($deleted) event(new DatabaseDeleted($this->tenant)); + event(new DatabaseDeleted($this->tenant)); } } diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index aeaa0855..afd20fb6 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -6,11 +6,9 @@ namespace Stancl\Tenancy; use Closure; use Illuminate\Cache\CacheManager; -use Illuminate\Cache\DatabaseStore; use Illuminate\Contracts\Container\Container; use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Routing\Events\RouteMatched; -use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; @@ -96,15 +94,6 @@ class TenancyServiceProvider extends ServiceProvider // using the callback below. It is set by DatabaseCacheBootstrapper. $manager = new CacheManager($app); - // Make globalCache use either the configured non-null connection, - // or fall back to the central connection. - $this->makeDatabaseCacheStoresCentral($manager); - - // If a bootstrapper (like DatabaseCacheBootstrapper) makes the - // cache connection tenant explicitly, the makeDatabaseCacheStoresCentral() - // call ends up setting the tenant connection rather than the central one, - // and the $adjustCacheManagerUsing callback is needed to - // make globalCache use the central connection. if (static::$adjustCacheManagerUsing !== null) { (static::$adjustCacheManagerUsing)($manager); } @@ -113,34 +102,6 @@ class TenancyServiceProvider extends ServiceProvider }); } - /** - * Ensure globalCache uses the central connection for database cache stores. - * - * A freshly built CacheManager creates database stores using the current default connection, which - * DatabaseTenancyBootstrapper switches to the tenant connection. Since global cache should always be - * central, reset those stores back to their configured connection, falling back to the central one. - */ - protected function makeDatabaseCacheStoresCentral(CacheManager $manager): void - { - $centralConnection = $this->app['config']['tenancy.database.central_connection']; - - foreach ($this->app['config']['cache.stores'] ?? [] as $name => $store) { - $notAValidDatabaseStore = ! is_array($store) || ($store['driver'] ?? null) !== 'database'; - - if ($notAValidDatabaseStore) { - continue; - } - - /** @var DatabaseStore $databaseStore */ - $databaseStore = $manager->store($name)->getStore(); - - // If $store['connection'] is null, it defaults to the default DB connection (which may be tenant). - // Fall back to the central connection to keep the global cache central. - $databaseStore->setConnection(DB::connection($store['connection'] ?? $centralConnection)); - $databaseStore->setLockConnection(DB::connection($store['lock_connection'] ?? $store['connection'] ?? $centralConnection)); - } - } - /* Bootstrap services. */ public function boot(): void { diff --git a/tests/CachedTenantResolverTest.php b/tests/CachedTenantResolverTest.php index fc6cfb79..920c95a1 100644 --- a/tests/CachedTenantResolverTest.php +++ b/tests/CachedTenantResolverTest.php @@ -165,7 +165,6 @@ test('cache is invalidated when tenant is updated from within the tenant context ['redis', [CacheTenancyBootstrapper::class]], ['redis', [CacheTagsBootstrapper::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) { diff --git a/tests/DatabasePreparationTest.php b/tests/DatabasePreparationTest.php index ccf7eb2e..1f3a4f09 100644 --- a/tests/DatabasePreparationTest.php +++ b/tests/DatabasePreparationTest.php @@ -2,27 +2,17 @@ declare(strict_types=1); -use Illuminate\Database\QueryException; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; use Stancl\JobPipeline\JobPipeline; use Stancl\Tenancy\Events\TenantCreated; -use Stancl\Tenancy\Events\TenantDeleted; use Stancl\Tenancy\Jobs\CreateDatabase; -use Stancl\Tenancy\Jobs\DeleteDatabase; use Stancl\Tenancy\Jobs\MigrateDatabase; use Stancl\Tenancy\Jobs\SeedDatabase; use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Foundation\Auth\User as Authenticable; use Stancl\Tenancy\Tests\Etc\TestSeeder; -beforeEach($cleanup = function () { - DeleteDatabase::$ignoreFailures = false; - DeleteDatabase::$skipWhenCreateDatabaseIsFalse = true; -}); - -afterEach($cleanup); - test('database can be created after tenant creation', function () { config(['tenancy.database.template_tenant_connection' => 'mysql']); @@ -92,73 +82,6 @@ test('custom job can be added to the pipeline', function () { }); }); -test('database can be deleted after tenant deletion', function () { - Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { - return $event->tenant; - })->toListener()); - - Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { - return $event->tenant; - })->toListener()); - - $tenant = Tenant::create(); - $manager = $tenant->database()->manager(); - - expect($manager->databaseExists($tenant->database()->getName()))->toBeTrue(); - - $tenant->delete(); - - expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); -}); - -test('database deletion is skipped when create_database is false', function (bool $skipWhenCreateDatabaseIsFalse) { - Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { - return $event->tenant; - })->toListener()); - - // create_database=false means no DB is created (e.g. tenant uses a pre-existing DB) - // On deletion, DeleteDatabase should skip rather than attempting DROP DATABASE on a non-existent DB - $tenant = Tenant::create(['tenancy_create_database' => false, 'tenancy_db_name' => 'non_existing_db']); - - $manager = $tenant->database()->manager(); - expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); - - DeleteDatabase::$skipWhenCreateDatabaseIsFalse = $skipWhenCreateDatabaseIsFalse; - - if ($skipWhenCreateDatabaseIsFalse) { - $tenant->delete(); // no exception - } else { - expect(fn () => $tenant->delete())->toThrow(QueryException::class, "database doesn't exist"); - } - - expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); -})->with([true, false]); - -test('database deletion failure is ignored when ignoreFailures is true', function (bool $ignoreFailures) { - Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { - return $event->tenant; - })->toListener()); - - Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { - return $event->tenant; - })->toListener()); - - DeleteDatabase::$ignoreFailures = $ignoreFailures; - - $tenant = Tenant::create(); - $manager = $tenant->database()->manager(); - expect($manager->databaseExists($tenant->database()->getName()))->toBeTrue(); - - $manager->deleteDatabase($tenant); // manually delete so the job fails - expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); - - if ($ignoreFailures) { - $tenant->delete(); // no exception - } else { - expect(fn () => $tenant->delete())->toThrow(QueryException::class, "database doesn't exist"); - } -})->with([true, false]); - class User extends Authenticable { protected $guarded = []; diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index 4cda8b74..016ad2a4 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -165,7 +165,6 @@ test('global cache is always central', function (string $store, array $bootstrap ['redis', [CacheTagsBootstrapper::class]], ['redis', [CacheTenancyBootstrapper::class]], ['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]], - ['database', [DatabaseTenancyBootstrapper::class, CacheTenancyBootstrapper::class]], ])->with([ 'helper', 'facade',