From 2ff3dd42831ce20da2a03b621af9ad55eb028248 Mon Sep 17 00:00:00 2001 From: Nuradiyana Date: Mon, 2 Dec 2019 01:54:07 +0700 Subject: [PATCH] Add support for postgres schema --- assets/config.php | 3 + src/DatabaseManager.php | 20 +++++- .../PostgreSQLSchemaManager.php | 35 ++++++++++ tests/DatabaseSchemaManagerTest.php | 69 +++++++++++++++++++ tests/TenantDatabaseManagerTest.php | 2 + 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/TenantDatabaseManagers/PostgreSQLSchemaManager.php create mode 100644 tests/DatabaseSchemaManagerTest.php diff --git a/assets/config.php b/assets/config.php index c08fa0a6..f590b29e 100644 --- a/assets/config.php +++ b/assets/config.php @@ -60,6 +60,7 @@ return [ 'sqlite' => Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager::class, 'mysql' => Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager::class, 'pgsql' => Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager::class, + 'schema' => Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager::class ], 'database_manager_connections' => [ // Connections used by TenantDatabaseManagers. This tells, for example, the @@ -67,7 +68,9 @@ return [ 'sqlite' => 'sqlite', 'mysql' => 'mysql', 'pgsql' => 'pgsql', + 'schema' => 'pgsql' ], + 'using_schema_connection' => false, // Only work with pgsql connection 'bootstrappers' => [ // Tenancy bootstrappers are executed when tenancy is initialized. // Their responsibility is making Laravel features tenant-aware. diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php index 151a9455..cd52e19a 100644 --- a/src/DatabaseManager.php +++ b/src/DatabaseManager.php @@ -100,7 +100,12 @@ class DatabaseManager // Change database name. $databaseName = $this->getDriver($connectionName) === 'sqlite' ? database_path($databaseName) : $databaseName; - $this->app['config']["database.connections.$connectionName.database"] = $databaseName; + + if ($this->isUsingSchema($connectionName)) { + $this->app['config']["database.connections.$connectionName.schema"] = $databaseName; + } else { + $this->app['config']["database.connections.$connectionName.database"] = $databaseName; + } } /** @@ -226,7 +231,7 @@ class DatabaseManager */ public function getTenantDatabaseManager(Tenant $tenant): TenantDatabaseManager { - $driver = $this->getDriver($this->getBaseConnection($tenant->getConnectionName())); + $driver = $this->isUsingSchema($tenant->getConnectionName()) ? 'schema' : $this->getDriver($this->getBaseConnection($tenant->getConnectionName())); $databaseManagers = $this->app['config']['tenancy.database_managers']; @@ -236,4 +241,15 @@ class DatabaseManager return $this->app[$databaseManagers[$driver]]; } + + /** + * Check if using schema connection + * + * @param string $connectionName + * @return bool + */ + protected function isUsingSchema(string $connectionName): bool + { + return $this->getDriver($this->getBaseConnection($connectionName)) === 'pgsql' && $this->app['config']['tenancy.using_schema_connection']; + } } diff --git a/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php new file mode 100644 index 00000000..c255a081 --- /dev/null +++ b/src/TenantDatabaseManagers/PostgreSQLSchemaManager.php @@ -0,0 +1,35 @@ +database = $databaseManager->connection($config['tenancy.database_manager_connections.schema']); + } + + public function createDatabase(string $name): bool + { + return $this->database->statement("CREATE SCHEMA \"$name\""); + } + + public function deleteDatabase(string $name): bool + { + return $this->database->statement("DROP SCHEMA \"$name\""); + } + + public function databaseExists(string $name): bool + { + return (bool) $this->database->select("SELECT schema_name FROM information_schema.schemata WHERE schema_name = '$name'"); + } +} diff --git a/tests/DatabaseSchemaManagerTest.php b/tests/DatabaseSchemaManagerTest.php new file mode 100644 index 00000000..5581232f --- /dev/null +++ b/tests/DatabaseSchemaManagerTest.php @@ -0,0 +1,69 @@ +set('database.default', 'pgsql'); + $app['config']->set('tenancy.database.based_on', null); + $app['config']->set('tenancy.database.suffix', ''); + $app['config']->set('tenancy.using_schema_connection', true); + } + + /** @test */ + public function reconnect_method_works() + { + $old_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName(); + + tenancy()->init('test.localhost'); + + app(\Stancl\Tenancy\DatabaseManager::class)->reconnect(); + + $new_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName(); + + // $this->assertSame($old_connection_name, $new_connection_name); + $this->assertNotEquals('tenant', $new_connection_name); + } + + /** @test */ + public function the_default_db_is_used_when_based_on_is_null() + { + config(['database.default' => 'pgsql']); + + $this->assertSame('pgsql', config('database.default')); + config([ + 'database.connections.pgsql.foo' => 'bar', + 'tenancy.database.based_on' => null, + ]); + + tenancy()->init('test.localhost'); + + $this->assertSame('tenant', config('database.default')); + $this->assertSame('bar', config('database.connections.' . config('database.default') . '.foo')); + } + + /** @test */ + public function make_sure_using_schema_connection() + { + $tenant = tenancy()->create(['schema.localhost']); + tenancy()->init('schema.localhost'); + + $this->assertSame($tenant->getDatabaseName(), config('database.connections.' . config('database.default') . '.schema')); + } +} diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index fc3c34f4..eea7bc48 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -11,6 +11,7 @@ use Stancl\Tenancy\Tenant; use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager; use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager; use Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager; +use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager; class TenantDatabaseManagerTest extends TestCase { @@ -78,6 +79,7 @@ class TenantDatabaseManagerTest extends TestCase ['mysql', MySQLDatabaseManager::class], ['sqlite', SQLiteDatabaseManager::class], ['pgsql', PostgreSQLDatabaseManager::class], + ['schema', PostgreSQLSchemaManager::class] ]; }