diff --git a/assets/config.php b/assets/config.php index 6130bade..cd0a6c42 100644 --- a/assets/config.php +++ b/assets/config.php @@ -116,18 +116,21 @@ return [ 'pgsql' => Stancl\Tenancy\Database\TenantDatabaseManagers\PostgreSQLDatabaseManager::class, 'sqlsrv' => Stancl\Tenancy\Database\TenantDatabaseManagers\MicrosoftSQLDatabaseManager::class, - /** - * Use this database manager for MySQL to have a DB user created for each tenant database. - * You can customize the grants given to these users by changing the $grants property. - */ + /** + * Use this database manager for MySQL to have a DB user created for each tenant database. + * You can customize the grants given to these users by changing the $grants property. + */ // 'mysql' => Stancl\Tenancy\Database\TenantDatabaseManagers\PermissionControlledMySQLDatabaseManager::class, - /** - * Disable the pgsql manager above, and enable the one below if you - * want to separate tenant DBs by schemas rather than databases. - */ + /** + * Disable the pgsql manager above, and enable the one below if you + * want to separate tenant DBs by schemas rather than databases. + */ // 'pgsql' => Stancl\Tenancy\Database\TenantDatabaseManagers\PostgreSQLSchemaManager::class, // Separate by schema instead of database ], + + // todo docblock + 'drop_tenant_databases_on_migrate_fresh' => false, ], /** diff --git a/composer.json b/composer.json index 0dc9df09..b30ea94c 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "doctrine/dbal": "^2.10", "spatie/valuestore": "^1.2.5", "pestphp/pest": "^1.21", - "nunomaduro/larastan": "^1.0" + "nunomaduro/larastan": "^1.0", + "spatie/invade": "^1.1" }, "autoload": { "psr-4": { diff --git a/phpstan.neon b/phpstan.neon index 3e9ba51d..0567d5ff 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,6 @@ includes: - ./vendor/nunomaduro/larastan/extension.neon + - ./vendor/spatie/invade/phpstan-extension.neon parameters: paths: diff --git a/src/Commands/MigrateFreshOverride.php b/src/Commands/MigrateFreshOverride.php new file mode 100644 index 00000000..88e9e21e --- /dev/null +++ b/src/Commands/MigrateFreshOverride.php @@ -0,0 +1,19 @@ +model()::cursor()->each->delete(); + } + + return parent::handle(); + } +} diff --git a/src/Events/Contracts/TenantEvent.php b/src/Events/Contracts/TenantEvent.php index 951fabfc..e07708b7 100644 --- a/src/Events/Contracts/TenantEvent.php +++ b/src/Events/Contracts/TenantEvent.php @@ -7,7 +7,7 @@ namespace Stancl\Tenancy\Events\Contracts; use Illuminate\Queue\SerializesModels; use Stancl\Tenancy\Contracts\Tenant; -abstract class TenantEvent +abstract class TenantEvent // todo we could add a feature to JobPipeline that automatically gets data for the send() from here { use SerializesModels; diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 7e12a857..63a22a11 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Stancl\Tenancy; use Illuminate\Cache\CacheManager; +use Illuminate\Database\Console\Migrations\FreshCommand; use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper; @@ -90,6 +91,10 @@ class TenancyServiceProvider extends ServiceProvider Commands\Up::class, ]); + $this->app->extend(FreshCommand::class, function () { + return new Commands\MigrateFreshOverride; + }); + $this->publishes([ __DIR__ . '/../assets/config.php' => config_path('tenancy.php'), ], 'config'); diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index 219d87b4..bac5005d 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -2,24 +2,28 @@ declare(strict_types=1); -use Illuminate\Database\DatabaseManager; -use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\DB; +use Stancl\Tenancy\Tests\Etc\User; +use Stancl\JobPipeline\JobPipeline; +use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; -use Stancl\JobPipeline\JobPipeline; -use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; +use Stancl\Tenancy\Jobs\DeleteDomains; +use Illuminate\Support\Facades\Artisan; use Stancl\Tenancy\Events\TenancyEnded; -use Stancl\Tenancy\Events\TenancyInitialized; -use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Jobs\CreateDatabase; +use Stancl\Tenancy\Jobs\DeleteDatabase; +use Illuminate\Database\DatabaseManager; +use Stancl\Tenancy\Events\TenantCreated; +use Stancl\Tenancy\Events\TenantDeleted; +use Stancl\Tenancy\Tests\Etc\TestSeeder; +use Stancl\Tenancy\Events\DeletingTenant; +use Stancl\Tenancy\Tests\Etc\ExampleSeeder; +use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Tests\Etc\ExampleSeeder; -use Stancl\Tenancy\Tests\Etc\Tenant; -use Stancl\Tenancy\Tests\Etc\TestSeeder; -use Stancl\Tenancy\Tests\Etc\User; +use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; + beforeEach(function () { Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { @@ -267,6 +271,47 @@ test('run command works when sub command asks questions and accepts arguments', expect($user->email)->toBe('email@localhost'); }); +test('migrate fresh command only deletes tenant databases if drop_tenant_databases_on_migrate_fresh is true', function (bool $dropTenantDBsOnMigrateFresh) { + Event::listen(DeletingTenant::class, + JobPipeline::make([DeleteDomains::class])->send(function (DeletingTenant $event) { + return $event->tenant; + })->shouldBeQueued(false)->toListener() + ); + + Event::listen( + TenantDeleted::class, + JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { + return $event->tenant; + })->shouldBeQueued(false)->toListener() + ); + + config(['tenancy.database.drop_tenant_databases_on_migrate_fresh' => $dropTenantDBsOnMigrateFresh]); + $shouldHaveDBAfterMigrateFresh = ! $dropTenantDBsOnMigrateFresh; + + /** @var Tenant[] $tenants */ + $tenants = [ + Tenant::create(), + Tenant::create(), + Tenant::create(), + ]; + + $tenantHasDatabase = fn (Tenant $tenant) => $tenant->database()->manager()->databaseExists($tenant->database()->getName()); + + foreach ($tenants as $tenant) { + expect($tenantHasDatabase($tenant))->toBeTrue(); + } + + pest()->artisan('migrate:fresh', [ + '--force' => true, + '--path' => __DIR__ . '/../assets/migrations', + '--realpath' => true, + ]); + + foreach ($tenants as $tenant) { + expect($tenantHasDatabase($tenant))->toBe($shouldHaveDBAfterMigrateFresh); + } +})->with([true, false]); + // todo@tests function runCommandWorks(): void {