diff --git a/assets/TenancyServiceProvider.stub.php b/assets/TenancyServiceProvider.stub.php index 87209bd8..d2366fb5 100644 --- a/assets/TenancyServiceProvider.stub.php +++ b/assets/TenancyServiceProvider.stub.php @@ -2,11 +2,12 @@ namespace App\Providers; -use Stancl\Tenancy\Contracts\Tenant; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; -use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator; +use Stancl\Tenancy\Listeners\JobPipeline; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Events\DatabaseCreated; use Stancl\Tenancy\Events\DatabaseDeleted; use Stancl\Tenancy\Events\DatabaseMigrated; @@ -20,7 +21,6 @@ use Stancl\Tenancy\Events\RevertedToCentralContext; use Stancl\Tenancy\Events\TenancyBootstrapped; use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Events\TenancyInitialized; -use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Events\TenantDeleted; use Stancl\Tenancy\Events\TenantSaved; @@ -29,9 +29,6 @@ use Stancl\Tenancy\Jobs\CreateDatabase; use Stancl\Tenancy\Jobs\DeleteDatabase; use Stancl\Tenancy\Jobs\MigrateDatabase; use Stancl\Tenancy\Jobs\SeedDatabase; -use Stancl\Tenancy\Listeners\BootstrapTenancy; -use Stancl\Tenancy\Listeners\RevertToCentralContext; -use Stancl\Tenancy\Tenancy; class TenancyServiceProvider extends ServiceProvider { @@ -49,7 +46,7 @@ class TenancyServiceProvider extends ServiceProvider ])->send(function (TenantCreated $event) { return $event->tenant; - })->queue(false), // `false` by default, but you probably want to make this `true` for production. + })->shouldBeQueued(false), // `false` by default, but you probably want to make this `true` for production. ], TenantSaved::class => [], TenantUpdated::class => [], @@ -58,7 +55,7 @@ class TenancyServiceProvider extends ServiceProvider DeleteDatabase::class, ])->send(function (TenantDeleted $event) { return $event->tenant; - })->queue(false), // `false` by default, but you probably want to make this `true` for production. + })->shouldBeQueued(false), // `false` by default, but you probably want to make this `true` for production. ], DomainCreated::class => [], @@ -87,30 +84,7 @@ class TenancyServiceProvider extends ServiceProvider public function register() { - // Make sure Tenancy is stateful. - $this->app->singleton(Tenancy::class); - - // Make sure features are bootstrapped as soon as Tenancy is instantiated. - $this->app->extend(Tenancy::class, function (Tenancy $tenancy) { - foreach ($this->app['config']['tenancy.features'] as $feature) { - $this->app[$feature]->bootstrap($tenancy); - } - - return $tenancy; - }); - - // Make it possible to inject the current tenant by typehinting the Tenant contract. - $this->app->bind(Tenant::class, function ($app) { - return $app[Tenancy::class]->tenant; - }); - - // Make sure bootstrappers are stateful (singletons). - foreach ($this->app['config']['tenancy.bootstrappers'] as $bootstrapper) { - $this->app->singleton($bootstrapper); - } - - // Bind the class in the tenancy.id_generator config to the UniqueIdentifierGenerator abstract. - $this->app->bind(UniqueIdentifierGenerator::class, $this->app['config']['tenancy.id_generator']); + // } public function boot() @@ -138,8 +112,7 @@ class TenancyServiceProvider extends ServiceProvider { $this->app->booted(function () { if (file_exists(base_path('routes/tenant.php'))) { - Route::middleware(['web']) - ->namespace($this->app['config']['tenancy.tenant_route_namespace'] ?? 'App\Http\Controllers') + Route::namespace($this->app['config']['tenancy.tenant_route_namespace'] ?? 'App\Http\Controllers') ->group(base_path('routes/tenant.php')); } }); diff --git a/assets/tenant_routes.php.stub b/assets/tenant_routes.php.stub index 022c8827..4e501123 100644 --- a/assets/tenant_routes.php.stub +++ b/assets/tenant_routes.php.stub @@ -1,5 +1,7 @@ InitializeTenancyByDomain::class, + 'middleware' => ['web', InitializeTenancyByDomain::class], 'prefix' => '/app', ], function () { Route::get('/', function () { diff --git a/src/Commands/Install.php b/src/Commands/Install.php index c108ce31..ad27c10f 100644 --- a/src/Commands/Install.php +++ b/src/Commands/Install.php @@ -43,7 +43,11 @@ class Install extends Command $this->info('Found routes/tenant.php.'); } - // todo tenancy SP stub + $this->callSilent('vendor:publish', [ + '--provider' => 'Stancl\Tenancy\TenancyServiceProvider', + '--tag' => 'provider', + ]); + $this->info('✔️ Created TenancyServiceProvider.php'); $this->callSilent('vendor:publish', [ '--provider' => 'Stancl\Tenancy\TenancyServiceProvider', diff --git a/src/Database/Concerns/HasADataColumn.php b/src/Database/Concerns/HasDataColumn.php similarity index 95% rename from src/Database/Concerns/HasADataColumn.php rename to src/Database/Concerns/HasDataColumn.php index 7895def4..d59d944f 100644 --- a/src/Database/Concerns/HasADataColumn.php +++ b/src/Database/Concerns/HasDataColumn.php @@ -2,7 +2,7 @@ namespace Stancl\Tenancy\Database\Concerns; -trait HasADataColumn +trait HasDataColumn { public static $priorityListeners = []; @@ -13,9 +13,9 @@ trait HasADataColumn * * @var string */ - public $dataEncodingStatus = 'decoded'; // todo write tests for this + public $dataEncodingStatus = 'decoded'; - public static function bootHasADataColumn() + public static function bootHasDataColumn() { $encode = function (self $model) { if ($model->dataEncodingStatus === 'encoded') { diff --git a/src/Database/Concerns/HasDatabase.php b/src/Database/Concerns/HasDatabase.php new file mode 100644 index 00000000..56efbcea --- /dev/null +++ b/src/Database/Concerns/HasDatabase.php @@ -0,0 +1,16 @@ +tenant->setInternal('db_username', $this->getUsername() ?? (static::$usernameGenerator)($this->tenant)); $this->tenant->setInternal('db_password', $this->getPassword() ?? (static::$passwordGenerator)($this->tenant)); } + + if ($this->tenant->exists) { + $this->tenant->save(); + } } public function getTemplateConnectionName(): string diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php index 795ab107..a8b7ac97 100644 --- a/src/DatabaseManager.php +++ b/src/DatabaseManager.php @@ -83,7 +83,7 @@ class DatabaseManager * @throws DatabaseManagerNotRegisteredException * @throws TenantDatabaseAlreadyExistsException */ - public function ensureTenantCanBeCreated(TenantWithDatabase $tenant): void // todo do we need this? + public function ensureTenantCanBeCreated(TenantWithDatabase $tenant): void { if ($tenant->database()->manager()->databaseExists($database = $tenant->database()->getName())) { throw new TenantDatabaseAlreadyExistsException($database); diff --git a/src/Jobs/CreateDatabase.php b/src/Jobs/CreateDatabase.php index f873765c..f4fd4f60 100644 --- a/src/Jobs/CreateDatabase.php +++ b/src/Jobs/CreateDatabase.php @@ -12,6 +12,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Stancl\Tenancy\Contracts\TenantWithDatabase; use Stancl\Tenancy\Contracts\Tenant; +use Stancl\Tenancy\DatabaseManager; use Stancl\Tenancy\Events\DatabaseCreated; class CreateDatabase implements ShouldQueue @@ -26,9 +27,10 @@ class CreateDatabase implements ShouldQueue $this->tenant = $tenant; } - public function handle() + public function handle(DatabaseManager $databaseManager) { if ($this->tenant->getInternal('create_database') !== false) { + $databaseManager->ensureTenantCanBeCreated($this->tenant); $this->tenant->database()->makeCredentials(); $this->tenant->database()->manager()->createDatabase($this->tenant); diff --git a/src/Listeners/JobPipeline.php b/src/Listeners/JobPipeline.php index e90595e9..a0ed489f 100644 --- a/src/Listeners/JobPipeline.php +++ b/src/Listeners/JobPipeline.php @@ -8,7 +8,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; class JobPipeline implements ShouldQueue { /** @var bool */ - public static $queueByDefault = false; + public static $shouldBeQueuedByDefault = false; /** @var callable[]|string[] */ public $jobs; @@ -22,16 +22,16 @@ class JobPipeline implements ShouldQueue public $passable; /** @var bool */ - public $queue; + public $shouldBeQueued; - public function __construct($jobs, callable $send = null, bool $queue = null) + public function __construct($jobs, callable $send = null, bool $shouldBeQueued = null) { $this->jobs = $jobs; $this->send = $send ?? function ($event) { // If no $send callback is set, we'll just pass the event through the jobs. return $event; }; - $this->queue = $queue ?? static::$queueByDefault; + $this->shouldBeQueued = $shouldBeQueued ?? static::$shouldBeQueuedByDefault; } /** @param callable[]|string[] $jobs */ @@ -47,9 +47,9 @@ class JobPipeline implements ShouldQueue return $this; } - public function queue(bool $queue) + public function shouldBeQueued(bool $shouldBeQueued) { - $this->queue = $queue; + $this->shouldBeQueued = $shouldBeQueued; return $this; } @@ -69,7 +69,7 @@ class JobPipeline implements ShouldQueue return function (...$args) { $executable = $this->executable($args); - if ($this->queue) { + if ($this->shouldBeQueued) { dispatch($executable); } else { dispatch_now($executable); diff --git a/src/TenancyServiceProvider.php b/src/TenancyServiceProvider.php index 17cfed14..848ea665 100644 --- a/src/TenancyServiceProvider.php +++ b/src/TenancyServiceProvider.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Stancl\Tenancy; use Illuminate\Cache\CacheManager; -use Illuminate\Queue\Events\JobProcessing; use Illuminate\Support\ServiceProvider; use Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper; use Stancl\Tenancy\Contracts\Tenant; @@ -23,6 +22,31 @@ class TenancyServiceProvider extends ServiceProvider $this->app->singleton(DatabaseManager::class); + // Make sure Tenancy is stateful. + $this->app->singleton(Tenancy::class); + + // Make sure features are bootstrapped as soon as Tenancy is instantiated. + $this->app->extend(Tenancy::class, function (Tenancy $tenancy) { + foreach ($this->app['config']['tenancy.features'] as $feature) { + $this->app[$feature]->bootstrap($tenancy); + } + + return $tenancy; + }); + + // Make it possible to inject the current tenant by typehinting the Tenant contract. + $this->app->bind(Tenant::class, function ($app) { + return $app[Tenancy::class]->tenant; + }); + + // Make sure bootstrappers are stateful (singletons). + foreach ($this->app['config']['tenancy.bootstrappers'] as $bootstrapper) { + $this->app->singleton($bootstrapper); + } + + // Bind the class in the tenancy.id_generator config to the UniqueIdentifierGenerator abstract. + $this->app->bind(Contracts\UniqueIdentifierGenerator::class, $this->app['config']['tenancy.id_generator']); + $this->app->singleton(Commands\Migrate::class, function ($app) { return new Commands\Migrate($app['migrator'], $app[DatabaseManager::class]); }); @@ -63,6 +87,10 @@ class TenancyServiceProvider extends ServiceProvider __DIR__ . '/../assets/migrations/' => database_path('migrations'), ], 'migrations'); + $this->publishes([ + __DIR__ . '/../assets/TenancyServiceProvider.stub.php' => app_path('Providers/TenancyServiceProvider.php'), + ], 'migrations'); + $this->loadRoutesFrom(__DIR__ . '/routes.php'); $this->app->singleton('globalUrl', function ($app) { diff --git a/src/TenantDatabaseManagers/SQLiteDatabaseManager.php b/src/TenantDatabaseManagers/SQLiteDatabaseManager.php index 7101f5e6..f4bdc85a 100644 --- a/src/TenantDatabaseManagers/SQLiteDatabaseManager.php +++ b/src/TenantDatabaseManagers/SQLiteDatabaseManager.php @@ -12,7 +12,7 @@ class SQLiteDatabaseManager implements TenantDatabaseManager public function createDatabase(TenantWithDatabase $tenant): bool { try { - return fclose(fopen(database_path($tenant->database()->getName()), 'w')); + return file_put_contents(database_path($tenant->database()->getName()), ''); } catch (\Throwable $th) { return false; } diff --git a/tests/AutomaticModeTest.php b/tests/AutomaticModeTest.php index a4d94c80..344df129 100644 --- a/tests/AutomaticModeTest.php +++ b/tests/AutomaticModeTest.php @@ -4,7 +4,7 @@ namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; use Stancl\Tenancy\Contracts\TenancyBootstrapper; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Events\TenancyEnded; @@ -74,12 +74,12 @@ class AutomaticModeTest extends TestCase class MyBootstrapper implements TenancyBootstrapper { - public function start(\Stancl\Tenancy\Contracts\Tenant $tenant) + public function bootstrap(\Stancl\Tenancy\Contracts\Tenant $tenant) { app()->instance('tenancy_initialized_for_tenant', $tenant->getTenantKey()); } - public function end() + public function revert() { app()->instance('tenancy_ended', true); } diff --git a/tests/BootstrapperTest.php b/tests/BootstrapperTest.php index 14a0220b..f90182cb 100644 --- a/tests/BootstrapperTest.php +++ b/tests/BootstrapperTest.php @@ -7,7 +7,7 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Listeners\RevertToCentralContext; diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index 56e6cc3b..7f303d68 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper; diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index 97846dad..26539169 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -9,7 +9,7 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; use Stancl\Tenancy\Tests\Etc\ExampleSeeder; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Listeners\RevertToCentralContext; @@ -154,6 +154,7 @@ class CommandsTest extends TestCase $this->artisan('tenancy:install'); $this->assertFileExists(base_path('routes/tenant.php')); $this->assertFileExists(base_path('config/tenancy.php')); + $this->assertFileExists(app_path('Providers/TenancyServiceProvider.php')); $this->assertFileExists(database_path('migrations/2019_09_15_000010_create_tenants_table.php')); $this->assertFileExists(database_path('migrations/2019_09_15_000020_create_domains_table.php')); $this->assertDirectoryExists(database_path('migrations/tenant')); diff --git a/tests/DatabasePreparationTest.php b/tests/DatabasePreparationTest.php index 02a06016..da311b3a 100644 --- a/tests/DatabasePreparationTest.php +++ b/tests/DatabasePreparationTest.php @@ -7,7 +7,7 @@ use Illuminate\Foundation\Auth\User as Authenticable; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Jobs\CreateDatabase; diff --git a/tests/DatabaseUsersTest.php b/tests/DatabaseUsersTest.php index 0f2f5c32..0d0f69f3 100644 --- a/tests/DatabaseUsersTest.php +++ b/tests/DatabaseUsersTest.php @@ -11,7 +11,7 @@ use Stancl\Tenancy\Contracts\ManagesDatabaseUsers; use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException; use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager; use Stancl\Tenancy\TenantDatabaseManagers\PermissionControlledMySQLDatabaseManager; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Events\TenantCreated; diff --git a/tests/Etc/Tenant.php b/tests/Etc/Tenant.php new file mode 100644 index 00000000..7d4cb420 --- /dev/null +++ b/tests/Etc/Tenant.php @@ -0,0 +1,13 @@ +send(function () { return $this->valuestore; - })->queue(true)->toListener()); + })->shouldBeQueued(true)->toListener()); Queue::assertNothingPushed(); @@ -70,7 +70,7 @@ class JobPipelineTest extends TestCase FooJob::class, ])->send(function () { return $this->valuestore; - })->queue(true)->toListener()); + })->shouldBeQueued(true)->toListener()); $this->assertFalse($this->valuestore->has('foo')); Tenant::create(); diff --git a/tests/PathIdentificationTest.php b/tests/PathIdentificationTest.php index 5ecc8fa9..f1db1f24 100644 --- a/tests/PathIdentificationTest.php +++ b/tests/PathIdentificationTest.php @@ -3,7 +3,7 @@ namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Route; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Exceptions\RouteIsMissingTenantParameterException; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException; use Stancl\Tenancy\Middleware\InitializeTenancyByPath; diff --git a/tests/QueueTest.php b/tests/QueueTest.php index 2d25c96b..4c4eba2f 100644 --- a/tests/QueueTest.php +++ b/tests/QueueTest.php @@ -10,7 +10,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Event; use Spatie\Valuestore\Valuestore; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\TenancyBootstrappers\QueueTenancyBootstrapper; diff --git a/tests/RequestDataIdentificationTest.php b/tests/RequestDataIdentificationTest.php index 7128c3b4..0007d26e 100644 --- a/tests/RequestDataIdentificationTest.php +++ b/tests/RequestDataIdentificationTest.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Route; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData; use Stancl\Tenancy\Tests\TestCase; diff --git a/tests/ResourceSyncingTest.php b/tests/ResourceSyncingTest.php index 9ccc3122..3ab5b6d9 100644 --- a/tests/ResourceSyncingTest.php +++ b/tests/ResourceSyncingTest.php @@ -11,8 +11,8 @@ use Stancl\Tenancy\Contracts\Syncable; use Stancl\Tenancy\Contracts\SyncMaster; use Stancl\Tenancy\Database\Concerns\CentralConnection; use Stancl\Tenancy\Database\Concerns\ResourceSyncing; -use Stancl\Tenancy\Database\Models; use Stancl\Tenancy\Database\Models\TenantPivot; +use Stancl\Tenancy\DatabaseConfig; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Listeners\RevertToCentralContext; @@ -25,7 +25,9 @@ use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Exceptions\ModelNotSyncMaster; use Stancl\Tenancy\Jobs\CreateDatabase; use Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Tests\TestCase; +use Illuminate\Support\Str; class ResourceSyncingTest extends TestCase { @@ -41,6 +43,10 @@ class ResourceSyncingTest extends TestCase return $event->tenant; })->toListener()); + DatabaseConfig::generateDatabaseNamesUsing(function () { + return 'db' . Str::random(16); + }); + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); @@ -568,7 +574,7 @@ class ResourceSyncingTest extends TestCase } } -class ResourceTenant extends Models\Tenant +class ResourceTenant extends Tenant { public function users() { diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php index 8f876834..4a89f582 100644 --- a/tests/TenantAssetTest.php +++ b/tests/TenantAssetTest.php @@ -5,9 +5,10 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Storage; use Stancl\Tenancy\Controllers\TenantAssetsController; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Middleware\InitializeTenancyByDomain; @@ -17,6 +18,19 @@ use Stancl\Tenancy\Tests\TestCase; class TenantAssetTest extends TestCase { + public function getEnvironmentSetUp($app) + { + parent::getEnvironmentSetUp($app); + + $app->booted(function () { + if (file_exists(base_path('routes/tenant.php'))) { + Route::middleware(['web']) + ->namespace($this->app['config']['tenancy.tenant_route_namespace'] ?? 'App\Http\Controllers') + ->group(base_path('routes/tenant.php')); + } + }); + } + public function setUp(): void { parent::setUp(); diff --git a/tests/TenantAwareCommandTest.php b/tests/TenantAwareCommandTest.php index c36fee96..0e62a1c7 100644 --- a/tests/TenantAwareCommandTest.php +++ b/tests/TenantAwareCommandTest.php @@ -6,7 +6,7 @@ namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\DB; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Tests\TestCase; class TenantAwareCommandTest extends TestCase diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index 742ce4c4..ce1c6e59 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -5,12 +5,13 @@ declare(strict_types=1); namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Event; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\DatabaseManager; use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\JobPipeline; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Events\TenantCreated; +use Stancl\Tenancy\Exceptions\TenantDatabaseAlreadyExistsException; use Stancl\Tenancy\Jobs\CreateDatabase; use Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper; use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager; @@ -19,6 +20,7 @@ use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager; use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager; use Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager; use Stancl\Tenancy\Tests\TestCase; +use Illuminate\Support\Str; class TenantDatabaseManagerTest extends TestCase { @@ -60,8 +62,7 @@ class TenantDatabaseManagerTest extends TestCase return $event->tenant; })->toListener()); - // todo if the prefix is _tenancy_, this blows up. write a tenantmodel test that the prefix can be _tenancy_ - config(['tenancy.internal_prefix' => 'tenancy_',]); + config(['tenancy.internal_prefix' => 'tenancy_']); $database = 'db' . $this->randomString(); @@ -141,4 +142,25 @@ class TenantDatabaseManagerTest extends TestCase $this->assertSame($tenant->database()->getName(), config('database.connections.' . config('database.default') . '.schema')); $this->assertSame($originalDatabaseName, config(['database.connections.pgsql.database'])); } + + /** @test */ + public function a_tenants_database_cannot_be_created_when_the_database_already_exists() + { + Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { + return $event->tenant; + })->toListener()); + + $name = 'foo' . Str::random(8); + $tenant = Tenant::create([ + 'tenancy_db_name' => $name, + ]); + + $manager = $tenant->database()->manager(); + $this->assertTrue($manager->databaseExists($tenant->database()->getName())); + + $this->expectException(TenantDatabaseAlreadyExistsException::class); + $tenant2 = Tenant::create([ + 'tenancy_db_name' => $name, + ]); + } } diff --git a/tests/TenantModelTest.php b/tests/TenantModelTest.php index 33383070..2eea16f4 100644 --- a/tests/TenantModelTest.php +++ b/tests/TenantModelTest.php @@ -7,12 +7,18 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; -use Stancl\Tenancy\Database\Models\Tenant; +use Stancl\Tenancy\Tests\Etc\Tenant; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Tests\TestCase; use Stancl\Tenancy\UniqueIDGenerators\UUIDGenerator; use Stancl\Tenancy\Contracts; use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator; +use Stancl\Tenancy\Events\TenancyInitialized; +use Stancl\Tenancy\Jobs\CreateDatabase; +use Stancl\Tenancy\Listeners\BootstrapTenancy; +use Stancl\Tenancy\Listeners\JobPipeline; +use Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper; +use Illuminate\Support\Str; class TenantModelTest extends TestCase { @@ -132,7 +138,40 @@ class TenantModelTest extends TestCase $this->assertTrue(tenant() instanceof AnotherTenant); } - // todo test that tenant can be created even in another DB context - that the central trait works + /** @test */ + public function tenant_can_be_created_even_when_we_are_in_another_tenants_context() + { + config(['tenancy.bootstrappers' => [ + DatabaseTenancyBootstrapper::class + ]]); + + Event::listen(TenancyInitialized::class, BootstrapTenancy::class); + Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function ($event) { + return $event->tenant; + })->toListener()); + + $tenant1 = Tenant::create([ + 'id' => 'foo', + 'tenancy_db_name' => 'db' . Str::random(16), + ]); + + tenancy()->initialize($tenant1); + + $tenant2 = Tenant::create([ + 'id' => 'bar', + 'tenancy_db_name' => 'db' . Str::random(16), + ]); + + tenancy()->end(); + + $this->assertSame(2, Tenant::count()); + } + + /** @test */ + public function data_is_never_encoded_or_decoded_twice() + { + // todo. tests for registerPriorityListener + } } class MyTenant extends Tenant diff --git a/tests/TestCase.php b/tests/TestCase.php index 01eb58f6..6d245e4c 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Redis; use Illuminate\Testing\Assert as PHPUnit; use Illuminate\Testing\TestResponse; +use Stancl\Tenancy\Tests\Etc\Tenant; abstract class TestCase extends \Orchestra\Testbench\TestCase { @@ -83,6 +84,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase 'central' => true, ], 'tenancy.seeder_parameters' => [], + 'tenancy.tenant_model' => Tenant::class, // Use test tenant w/ DBs & domains ]); $app->singleton(\Stancl\Tenancy\TenancyBootstrappers\RedisTenancyBootstrapper::class);