From 0fc105487bfcb6c1b49c269d495f6b7a7af8522e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Thu, 12 Sep 2024 18:34:45 +0200 Subject: [PATCH] Tenant DB manager database() -> connection() --- src/Commands/CreateUserWithRLSPolicies.php | 2 +- .../Concerns/ManagesPostgresUsers.php | 20 +++++++++---------- .../StatefulTenantDatabaseManager.php | 2 +- .../MicrosoftSQLDatabaseManager.php | 10 +++++----- .../MySQLDatabaseManager.php | 10 +++++----- ...olledMicrosoftSQLServerDatabaseManager.php | 10 +++++----- ...rmissionControlledMySQLDatabaseManager.php | 12 +++++------ ...ionControlledPostgreSQLDatabaseManager.php | 14 ++++++------- ...ssionControlledPostgreSQLSchemaManager.php | 14 ++++++------- .../PostgreSQLDatabaseManager.php | 6 +++--- .../PostgreSQLSchemaManager.php | 6 +++--- .../TenantDatabaseManager.php | 2 +- tests/TenantDatabaseManagerTest.php | 12 +++++------ 13 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/Commands/CreateUserWithRLSPolicies.php b/src/Commands/CreateUserWithRLSPolicies.php index 45b25278..3ad83a86 100644 --- a/src/Commands/CreateUserWithRLSPolicies.php +++ b/src/Commands/CreateUserWithRLSPolicies.php @@ -83,7 +83,7 @@ class CreateUserWithRLSPolicies extends Command $manager->setConnection($tenantModel->database()->getTenantHostConnectionName()); // Set the database name (= central schema name/search_path in this case), username, and password - $tenantModel->setInternal('db_name', $manager->database()->getConfig('search_path')); + $tenantModel->setInternal('db_name', $manager->connection()->getConfig('search_path')); $tenantModel->setInternal('db_username', $username); $tenantModel->setInternal('db_password', $password); diff --git a/src/Database/Concerns/ManagesPostgresUsers.php b/src/Database/Concerns/ManagesPostgresUsers.php index f73bac1c..c798fe13 100644 --- a/src/Database/Concerns/ManagesPostgresUsers.php +++ b/src/Database/Concerns/ManagesPostgresUsers.php @@ -30,7 +30,7 @@ trait ManagesPostgresUsers $createUser = ! $this->userExists($username); if ($createUser) { - $this->database()->statement("CREATE USER \"{$username}\" LOGIN PASSWORD '{$password}'"); + $this->connection()->statement("CREATE USER \"{$username}\" LOGIN PASSWORD '{$password}'"); } $this->grantPermissions($databaseConfig); @@ -46,38 +46,38 @@ trait ManagesPostgresUsers $username = $databaseConfig->getUsername(); // Tenant host connection config - $connectionName = $this->database()->getConfig('name'); - $centralDatabase = $this->database()->getConfig('database'); + $connectionName = $this->connection()->getConfig('name'); + $centralDatabase = $this->connection()->getConfig('database'); // Set the DB/schema name to the tenant DB/schema name config()->set( "database.connections.{$connectionName}", - $this->makeConnectionConfig($this->database()->getConfig(), $databaseConfig->getName()), + $this->makeConnectionConfig($this->connection()->getConfig(), $databaseConfig->getName()), ); // Connect to the tenant DB/schema - $this->database()->reconnect(); + $this->connection()->reconnect(); // Delete all database objects owned by the user (privileges, tables, views, etc.) // Postgres users cannot be deleted unless we delete all objects owned by it first - $this->database()->statement("DROP OWNED BY \"{$username}\""); + $this->connection()->statement("DROP OWNED BY \"{$username}\""); // Delete the user - $userDeleted = $this->database()->statement("DROP USER \"{$username}\""); + $userDeleted = $this->connection()->statement("DROP USER \"{$username}\""); config()->set( "database.connections.{$connectionName}", - $this->makeConnectionConfig($this->database()->getConfig(), $centralDatabase), + $this->makeConnectionConfig($this->connection()->getConfig(), $centralDatabase), ); // Reconnect to the central database - $this->database()->reconnect(); + $this->connection()->reconnect(); return $userDeleted; } public function userExists(string $username): bool { - return (bool) $this->database()->selectOne("SELECT usename FROM pg_user WHERE usename = '{$username}'"); + return (bool) $this->connection()->selectOne("SELECT usename FROM pg_user WHERE usename = '{$username}'"); } } diff --git a/src/Database/Contracts/StatefulTenantDatabaseManager.php b/src/Database/Contracts/StatefulTenantDatabaseManager.php index 6716e9eb..9bda3de2 100644 --- a/src/Database/Contracts/StatefulTenantDatabaseManager.php +++ b/src/Database/Contracts/StatefulTenantDatabaseManager.php @@ -13,7 +13,7 @@ use Stancl\Tenancy\Database\Exceptions\NoConnectionSetException; interface StatefulTenantDatabaseManager extends TenantDatabaseManager { /** Get the DB connection used by the tenant database manager. */ - public function database(): Connection; // todo@dbRefactor rename to connection() + public function connection(): Connection; /** * Set the DB connection that should be used by the tenant database manager. diff --git a/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php index 65950baa..1e5426ea 100644 --- a/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/MicrosoftSQLDatabaseManager.php @@ -11,19 +11,19 @@ class MicrosoftSQLDatabaseManager extends TenantDatabaseManager public function createDatabase(TenantWithDatabase $tenant): bool { $database = $tenant->database()->getName(); - $charset = $this->database()->getConfig('charset'); - $collation = $this->database()->getConfig('collation'); // todo check why these are not used + $charset = $this->connection()->getConfig('charset'); + $collation = $this->connection()->getConfig('collation'); // todo check why these are not used - return $this->database()->statement("CREATE DATABASE [{$database}]"); + return $this->connection()->statement("CREATE DATABASE [{$database}]"); } public function deleteDatabase(TenantWithDatabase $tenant): bool { - return $this->database()->statement("DROP DATABASE [{$tenant->database()->getName()}]"); + return $this->connection()->statement("DROP DATABASE [{$tenant->database()->getName()}]"); } public function databaseExists(string $name): bool { - return (bool) $this->database()->select("SELECT name FROM master.sys.databases WHERE name = '$name'"); + return (bool) $this->connection()->select("SELECT name FROM master.sys.databases WHERE name = '$name'"); } } diff --git a/src/Database/TenantDatabaseManagers/MySQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/MySQLDatabaseManager.php index c96c162b..b86faef2 100644 --- a/src/Database/TenantDatabaseManagers/MySQLDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/MySQLDatabaseManager.php @@ -11,19 +11,19 @@ class MySQLDatabaseManager extends TenantDatabaseManager public function createDatabase(TenantWithDatabase $tenant): bool { $database = $tenant->database()->getName(); - $charset = $this->database()->getConfig('charset'); - $collation = $this->database()->getConfig('collation'); + $charset = $this->connection()->getConfig('charset'); + $collation = $this->connection()->getConfig('collation'); - return $this->database()->statement("CREATE DATABASE `{$database}` CHARACTER SET `$charset` COLLATE `$collation`"); + return $this->connection()->statement("CREATE DATABASE `{$database}` CHARACTER SET `$charset` COLLATE `$collation`"); } public function deleteDatabase(TenantWithDatabase $tenant): bool { - return $this->database()->statement("DROP DATABASE `{$tenant->database()->getName()}`"); + return $this->connection()->statement("DROP DATABASE `{$tenant->database()->getName()}`"); } public function databaseExists(string $name): bool { - return (bool) $this->database()->select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$name'"); + return (bool) $this->connection()->select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$name'"); } } diff --git a/src/Database/TenantDatabaseManagers/PermissionControlledMicrosoftSQLServerDatabaseManager.php b/src/Database/TenantDatabaseManagers/PermissionControlledMicrosoftSQLServerDatabaseManager.php index aec43d46..b373f41e 100644 --- a/src/Database/TenantDatabaseManagers/PermissionControlledMicrosoftSQLServerDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/PermissionControlledMicrosoftSQLServerDatabaseManager.php @@ -25,24 +25,24 @@ class PermissionControlledMicrosoftSQLServerDatabaseManager extends MicrosoftSQL $password = $databaseConfig->getPassword(); // Create login - $this->database()->statement("CREATE LOGIN [$username] WITH PASSWORD = '$password'"); + $this->connection()->statement("CREATE LOGIN [$username] WITH PASSWORD = '$password'"); // Create user in the database // Grant the user permissions specified in the $grants array // The 'CONNECT' permission is granted automatically $grants = implode(', ', static::$grants); - return $this->database()->statement("USE [$database]; CREATE USER [$username] FOR LOGIN [$username]; GRANT $grants TO [$username]"); + return $this->connection()->statement("USE [$database]; CREATE USER [$username] FOR LOGIN [$username]; GRANT $grants TO [$username]"); } public function deleteUser(DatabaseConfig $databaseConfig): bool { - return $this->database()->statement("DROP LOGIN [{$databaseConfig->getUsername()}]"); + return $this->connection()->statement("DROP LOGIN [{$databaseConfig->getUsername()}]"); } public function userExists(string $username): bool { - return (bool) $this->database()->select("SELECT sp.name as username FROM sys.server_principals sp WHERE sp.name = '{$username}'"); + return (bool) $this->connection()->select("SELECT sp.name as username FROM sys.server_principals sp WHERE sp.name = '{$username}'"); } public function makeConnectionConfig(array $baseConfig, string $databaseName): array @@ -58,7 +58,7 @@ class PermissionControlledMicrosoftSQLServerDatabaseManager extends MicrosoftSQL // Set the database to SINGLE_USER mode to ensure that // No other connections are using the database while we're trying to delete it // Rollback all active transactions - $this->database()->statement("ALTER DATABASE [{$tenant->database()->getName()}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;"); + $this->connection()->statement("ALTER DATABASE [{$tenant->database()->getName()}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;"); return parent::deleteDatabase($tenant); } diff --git a/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php index 308d8786..8ea3e631 100644 --- a/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php @@ -26,7 +26,7 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl $hostname = $databaseConfig->connection()['host']; $password = $databaseConfig->getPassword(); - $this->database()->statement("CREATE USER `{$username}`@`%` IDENTIFIED BY '{$password}'"); + $this->connection()->statement("CREATE USER `{$username}`@`%` IDENTIFIED BY '{$password}'"); $grants = implode(', ', static::$grants); @@ -36,24 +36,24 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl $grantQuery = "GRANT $grants ON `$database`.* TO `$username`@`%` IDENTIFIED BY '$password'"; } - return $this->database()->statement($grantQuery); + return $this->connection()->statement($grantQuery); } protected function isVersion8(): bool { - $versionSelect = (string) $this->database()->raw('select version()')->getValue($this->database()->getQueryGrammar()); - $version = $this->database()->select($versionSelect)[0]->{'version()'}; + $versionSelect = (string) $this->connection()->raw('select version()')->getValue($this->connection()->getQueryGrammar()); + $version = $this->connection()->select($versionSelect)[0]->{'version()'}; return version_compare($version, '8.0.0') >= 0; } public function deleteUser(DatabaseConfig $databaseConfig): bool { - return $this->database()->statement("DROP USER IF EXISTS '{$databaseConfig->getUsername()}'"); + return $this->connection()->statement("DROP USER IF EXISTS '{$databaseConfig->getUsername()}'"); } public function userExists(string $username): bool { - return (bool) $this->database()->select("SELECT count(*) FROM mysql.user WHERE user = '$username'")[0]->{'count(*)'}; + return (bool) $this->connection()->select("SELECT count(*) FROM mysql.user WHERE user = '$username'")[0]->{'count(*)'}; } } diff --git a/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLDatabaseManager.php index 982ea4d6..1522234e 100644 --- a/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLDatabaseManager.php @@ -21,26 +21,26 @@ class PermissionControlledPostgreSQLDatabaseManager extends PostgreSQLDatabaseMa $schema = $databaseConfig->connection()['search_path']; // Host config - $connectionName = $this->database()->getConfig('name'); - $centralDatabase = $this->database()->getConfig('database'); + $connectionName = $this->connection()->getConfig('name'); + $centralDatabase = $this->connection()->getConfig('database'); - $this->database()->statement("GRANT CONNECT ON DATABASE \"{$database}\" TO \"{$username}\""); + $this->connection()->statement("GRANT CONNECT ON DATABASE \"{$database}\" TO \"{$username}\""); // Connect to tenant database config(["database.connections.{$connectionName}.database" => $database]); - $this->database()->reconnect(); + $this->connection()->reconnect(); // Grant permissions to create and use tables in the configured schema ("public" by default) to the user - $this->database()->statement("GRANT USAGE, CREATE ON SCHEMA {$schema} TO \"{$username}\""); + $this->connection()->statement("GRANT USAGE, CREATE ON SCHEMA {$schema} TO \"{$username}\""); // Grant permissions to use sequences in the current schema to the user - $this->database()->statement("GRANT USAGE ON ALL SEQUENCES IN SCHEMA {$schema} TO \"{$username}\""); + $this->connection()->statement("GRANT USAGE ON ALL SEQUENCES IN SCHEMA {$schema} TO \"{$username}\""); // Reconnect to central database config(["database.connections.{$connectionName}.database" => $centralDatabase]); - $this->database()->reconnect(); + $this->connection()->reconnect(); return true; } diff --git a/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php b/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php index 96693cae..fda4a836 100644 --- a/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php +++ b/src/Database/TenantDatabaseManagers/PermissionControlledPostgreSQLSchemaManager.php @@ -23,11 +23,11 @@ class PermissionControlledPostgreSQLSchemaManager extends PostgreSQLSchemaManage // Central database name $database = DB::connection(config('tenancy.database.central_connection'))->getDatabaseName(); - $this->database()->statement("GRANT CONNECT ON DATABASE {$database} TO \"{$username}\""); - $this->database()->statement("GRANT USAGE, CREATE ON SCHEMA \"{$schema}\" TO \"{$username}\""); - $this->database()->statement("GRANT USAGE ON ALL SEQUENCES IN SCHEMA \"{$schema}\" TO \"{$username}\""); + $this->connection()->statement("GRANT CONNECT ON DATABASE {$database} TO \"{$username}\""); + $this->connection()->statement("GRANT USAGE, CREATE ON SCHEMA \"{$schema}\" TO \"{$username}\""); + $this->connection()->statement("GRANT USAGE ON ALL SEQUENCES IN SCHEMA \"{$schema}\" TO \"{$username}\""); - $tables = $this->database()->select("SELECT table_name FROM information_schema.tables WHERE table_schema = '{$schema}'"); + $tables = $this->connection()->select("SELECT table_name FROM information_schema.tables WHERE table_schema = '{$schema}'"); // Grant permissions to any existing tables. This is used with RLS // todo@samuel refactor this along with the todo in TenantDatabaseManager @@ -36,7 +36,7 @@ class PermissionControlledPostgreSQLSchemaManager extends PostgreSQLSchemaManage $tableName = $table->table_name; /** @var string $primaryKey */ - $primaryKey = $this->database()->selectOne(<<connection()->selectOne(<<column_name; // Grant all permissions for all existing tables - $this->database()->statement("GRANT ALL ON \"{$schema}\".\"{$tableName}\" TO \"{$username}\""); + $this->connection()->statement("GRANT ALL ON \"{$schema}\".\"{$tableName}\" TO \"{$username}\""); // Grant permission to reference the primary key for the table // The previous query doesn't grant the references privilege, so it has to be granted here - $this->database()->statement("GRANT REFERENCES (\"{$primaryKey}\") ON \"{$schema}\".\"{$tableName}\" TO \"{$username}\""); + $this->connection()->statement("GRANT REFERENCES (\"{$primaryKey}\") ON \"{$schema}\".\"{$tableName}\" TO \"{$username}\""); } return true; diff --git a/src/Database/TenantDatabaseManagers/PostgreSQLDatabaseManager.php b/src/Database/TenantDatabaseManagers/PostgreSQLDatabaseManager.php index 88f1c78c..4fff7202 100644 --- a/src/Database/TenantDatabaseManagers/PostgreSQLDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/PostgreSQLDatabaseManager.php @@ -10,16 +10,16 @@ class PostgreSQLDatabaseManager extends TenantDatabaseManager { public function createDatabase(TenantWithDatabase $tenant): bool { - return $this->database()->statement("CREATE DATABASE \"{$tenant->database()->getName()}\" WITH TEMPLATE=template0"); + return $this->connection()->statement("CREATE DATABASE \"{$tenant->database()->getName()}\" WITH TEMPLATE=template0"); } public function deleteDatabase(TenantWithDatabase $tenant): bool { - return $this->database()->statement("DROP DATABASE \"{$tenant->database()->getName()}\""); + return $this->connection()->statement("DROP DATABASE \"{$tenant->database()->getName()}\""); } public function databaseExists(string $name): bool { - return (bool) $this->database()->selectOne("SELECT datname FROM pg_database WHERE datname = '$name'"); + return (bool) $this->connection()->selectOne("SELECT datname FROM pg_database WHERE datname = '$name'"); } } diff --git a/src/Database/TenantDatabaseManagers/PostgreSQLSchemaManager.php b/src/Database/TenantDatabaseManagers/PostgreSQLSchemaManager.php index a7558e1b..d0fb0337 100644 --- a/src/Database/TenantDatabaseManagers/PostgreSQLSchemaManager.php +++ b/src/Database/TenantDatabaseManagers/PostgreSQLSchemaManager.php @@ -10,17 +10,17 @@ class PostgreSQLSchemaManager extends TenantDatabaseManager { public function createDatabase(TenantWithDatabase $tenant): bool { - return $this->database()->statement("CREATE SCHEMA \"{$tenant->database()->getName()}\""); + return $this->connection()->statement("CREATE SCHEMA \"{$tenant->database()->getName()}\""); } public function deleteDatabase(TenantWithDatabase $tenant): bool { - return $this->database()->statement("DROP SCHEMA \"{$tenant->database()->getName()}\" CASCADE"); + return $this->connection()->statement("DROP SCHEMA \"{$tenant->database()->getName()}\" CASCADE"); } public function databaseExists(string $name): bool { - return (bool) $this->database()->select("SELECT schema_name FROM information_schema.schemata WHERE schema_name = '$name'"); + return (bool) $this->connection()->select("SELECT schema_name FROM information_schema.schemata WHERE schema_name = '$name'"); } public function makeConnectionConfig(array $baseConfig, string $databaseName): array diff --git a/src/Database/TenantDatabaseManagers/TenantDatabaseManager.php b/src/Database/TenantDatabaseManagers/TenantDatabaseManager.php index 87916088..3d8d7610 100644 --- a/src/Database/TenantDatabaseManagers/TenantDatabaseManager.php +++ b/src/Database/TenantDatabaseManagers/TenantDatabaseManager.php @@ -14,7 +14,7 @@ abstract class TenantDatabaseManager implements StatefulTenantDatabaseManager /** The database connection to the server. */ protected string $connection; - public function database(): Connection + public function connection(): Connection { if (! isset($this->connection)) { throw new NoConnectionSetException(static::class); diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index 43196ec2..559b40b5 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -332,7 +332,7 @@ test('database credentials can be provided to PermissionControlledMySQLDatabaseM /** @var PermissionControlledMySQLDatabaseManager $manager */ $manager = $tenant->database()->manager(); - expect($manager->database()->getConfig('username'))->toBe($username); // user created for the HOST connection + expect($manager->connection()->getConfig('username'))->toBe($username); // user created for the HOST connection expect($manager->userExists($usernameForNewDB))->toBeTrue(); expect($manager->databaseExists($name))->toBeTrue(); }); @@ -371,7 +371,7 @@ test('tenant database can be created by using the username and password from ten /** @var MySQLDatabaseManager $manager */ $manager = $tenant->database()->manager(); - expect($manager->database()->getConfig('username'))->toBe($username); // user created for the HOST connection + expect($manager->connection()->getConfig('username'))->toBe($username); // user created for the HOST connection expect($manager->databaseExists($name))->toBeTrue(); }); @@ -417,7 +417,7 @@ test('the tenant connection template can be specified either by name or as a con /** @var MySQLDatabaseManager $manager */ $manager = $tenant->database()->manager(); expect($manager->databaseExists($name))->toBeTrue(); - expect($manager->database()->getConfig('host'))->toBe('mysql'); + expect($manager->connection()->getConfig('host'))->toBe('mysql'); config([ 'tenancy.database.template_tenant_connection' => [ @@ -446,7 +446,7 @@ test('the tenant connection template can be specified either by name or as a con /** @var MySQLDatabaseManager $manager */ $manager = $tenant->database()->manager(); expect($manager->databaseExists($name))->toBeTrue(); // tenant connection works - expect($manager->database()->getConfig('host'))->toBe('mysql2'); + expect($manager->connection()->getConfig('host'))->toBe('mysql2'); }); test('partial tenant connection templates get merged into the central connection template', function () { @@ -471,8 +471,8 @@ test('partial tenant connection templates get merged into the central connection /** @var MySQLDatabaseManager $manager */ $manager = $tenant->database()->manager(); expect($manager->databaseExists($name))->toBeTrue(); // tenant connection works - expect($manager->database()->getConfig('host'))->toBe('mysql2'); - expect($manager->database()->getConfig('url'))->toBeNull(); + expect($manager->connection()->getConfig('host'))->toBe('mysql2'); + expect($manager->connection()->getConfig('url'))->toBeNull(); }); // Datasets