app = $app; $this->database = $database; $this->originalDefaultConnectionName = $app['config']['database.default']; } /** * Connect to a tenant's database. * * @param Tenant $tenant * @return void */ public function connect(Tenant $tenant) { $this->createTenantConnection($tenant->getDatabaseName(), $tenant->getConnectionName()); $this->switchConnection($tenant->getConnectionName()); } /** * Reconnect to the default non-tenant connection. * * @return void */ public function reconnect() { $this->switchConnection($this->originalDefaultConnectionName); } /** * Create the tenant database connection. * * @param string $databaseName * @param string $connectionName * @return void */ public function createTenantConnection($databaseName, $connectionName) { // Create the database connection. $based_on = $this->getBaseConnection($connectionName); $this->app['config']["database.connections.$connectionName"] = $this->app['config']['database.connections.' . $based_on]; // todo don't overwrite database.connections.$connectionName // Change database name. // todo tenant-specific connections without any DB name changes? $databaseName = $this->getDriver($connectionName) === 'sqlite' ? database_path($databaseName) : $databaseName; $this->app['config']["database.connections.$connectionName.database"] = $databaseName; } /** * Get the name of the connection that $connectionName should be based on * * @param string $connectionName * @return string */ public function getBaseConnection(string $connectionName): string { return $connectionName ?? $this->app['config']['tenancy.database.based_on'] ?? $this->originalDefaultConnectionName; // tenancy.database.based_on === null => use the default connection } /** * Get the driver of a database connection. * * @param string $connectionName * @return string */ public function getDriver(string $connectionName): string { return $this->app['config']["database.connections.$connectionName.driver"]; } /** * Switch the application's connection. * * @param string $connection * @return void */ public function switchConnection(string $connection) { $this->app['config']['database.default'] = $connection; $this->database->purge(); $this->database->reconnect($connection); $this->database->setDefaultConnection($connection); } /** * Check if a tenant can be created. * * @param Tenant $tenant * @return void * @throws TenantCannotBeCreatedException */ public function ensureTenantCanBeCreated(Tenant $tenant): void { if ($this->getTenantDatabaseManager($tenant)->databaseExists($database = $tenant->getDatabaseName())) { throw new TenantDatabaseAlreadyExistsException($database); } } /** * Create a database for a tenant. * * @param Tenant $tenant * @return void */ public function createDatabase(Tenant $tenant) { $database = $tenant->getDatabaseName(); $manager = $this->getTenantDatabaseManager($tenant); if ($this->app['config']['tenancy.queue_database_creation'] ?? false) { QueuedTenantDatabaseCreator::dispatch($manager, $database); } else { $manager->createDatabase($database); } } /** * Delete a tenant's database. * * @param Tenant $tenant * @return void */ public function deleteDatabase(Tenant $tenant) { $database = $tenant->getDatabaseName(); $manager = $this->getTenantDatabaseManager($tenant); if ($this->app['config']['tenancy.queue_database_deletion'] ?? false) { QueuedTenantDatabaseDeleter::dispatch($manager, $database); } else { $manager->deleteDatabase($database); } } /** * Get the TenantDatabaseManager for a tenant's database connection. * * @param Tenant $tenant * @return TenantDatabaseManager */ protected function getTenantDatabaseManager(Tenant $tenant): TenantDatabaseManager { $driver = $this->getDriver($this->getBaseConnection($tenant->getConnectionName())); $databaseManagers = $this->app['config']['tenancy.database_managers']; if (! array_key_exists($driver, $databaseManagers)) { throw new DatabaseManagerNotRegisteredException($driver); } return $this->app[$databaseManagers[$driver]]; } }