1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-05 18:34:04 +00:00

Use database transactions for creating users & granting permissions

This commit is contained in:
Samuel Štancl 2020-04-30 22:22:18 +02:00
parent 70e6679678
commit 65ebc043dc
12 changed files with 66 additions and 48 deletions

View file

@ -8,7 +8,7 @@ use Stancl\Tenancy\DatabaseConfig;
interface ManagesDatabaseUsers
{
public function createUser(DatabaseConfig $databaseConfig): void;
public function createUser(DatabaseConfig $databaseConfig): bool;
public function deleteUser(DatabaseConfig $databaseConfig): void;
public function deleteUser(DatabaseConfig $databaseConfig): bool;
}

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Contracts;
use Stancl\Tenancy\Tenant;
interface TenantDatabaseManager
{
/**
@ -15,19 +17,13 @@ interface TenantDatabaseManager
/**
* Create a database.
*
* @param string $name Name of the database.
* @return bool
*/
public function createDatabase(string $name): bool;
public function createDatabase(Tenant $tenant): bool;
/**
* Delete a database.
*
* @param string $name Name of the database.
* @return bool
*/
public function deleteDatabase(string $name): bool;
public function deleteDatabase(Tenant $tenant): bool;
/**
* Does a database exist.

View file

@ -153,11 +153,7 @@ class DatabaseManager
protected function createDatabaseSynchronously(Tenant $tenant, array $afterCreating)
{
$manager = $tenant->database()->manager();
$manager->createDatabase($tenant->database()->getName());
if ($manager instanceof ManagesDatabaseUsers) {
$manager->createUser($tenant->database());
}
$manager->createDatabase($tenant);
foreach ($afterCreating as $item) {
if (is_object($item) && ! $item instanceof Closure) {
@ -183,10 +179,7 @@ class DatabaseManager
if ($this->app['config']['tenancy.queue_database_deletion'] ?? false) {
QueuedTenantDatabaseDeleter::dispatch($manager, $tenant);
} else {
$manager->deleteDatabase($database);
if ($manager instanceof ManagesDatabaseUsers) {
$manager->deleteUser($tenant->database());
}
$manager->deleteDatabase($tenant);
}
$this->tenancy->event('database.deleted', $database, $tenant);

View file

@ -36,10 +36,6 @@ class QueuedTenantDatabaseCreator implements ShouldQueue
*/
public function handle()
{
$this->databaseManager->createDatabase($this->databaseName);
if ($this->databaseManager instanceof ManagesDatabaseUsers) {
$this->databaseManager->createUser($this->tenant->database());
}
$this->databaseManager->createDatabase($this->tenant);
}
}

View file

@ -36,9 +36,6 @@ class QueuedTenantDatabaseDeleter implements ShouldQueue
*/
public function handle()
{
$this->databaseManager->deleteDatabase($this->tenant->database()->getName());
if ($this->databaseManager instanceof ManagesDatabaseUsers) {
$this->databaseManager->deleteUser($this->tenant->database());
}
$this->databaseManager->deleteDatabase($this->tenant);
}
}

View file

@ -9,6 +9,7 @@ use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Contracts\Future\CanSetConnection;
use Stancl\Tenancy\Contracts\TenantDatabaseManager;
use Stancl\Tenancy\Tenant;
class MySQLDatabaseManager implements TenantDatabaseManager, CanSetConnection
{
@ -35,17 +36,18 @@ class MySQLDatabaseManager implements TenantDatabaseManager, CanSetConnection
$this->connection = $connection;
}
public function createDatabase(string $name): bool
public function createDatabase(Tenant $tenant): bool
{
$database = $tenant->database()->getName();
$charset = $this->database()->getConfig('charset');
$collation = $this->database()->getConfig('collation');
return $this->database()->statement("CREATE DATABASE `$name` CHARACTER SET `$charset` COLLATE `$collation`");
return $this->database()->statement("CREATE DATABASE `{$database}` CHARACTER SET `$charset` COLLATE `$collation`");
}
public function deleteDatabase(string $name): bool
public function deleteDatabase(Tenant $tenant): bool
{
return $this->database()->statement("DROP DATABASE `$name`");
return $this->database()->statement("DROP DATABASE `{$tenant->database()->getName()}`");
}
public function databaseExists(string $name): bool

View file

@ -6,16 +6,19 @@ namespace Stancl\Tenancy\TenantDatabaseManagers;
use Stancl\Tenancy\Contracts\ManagesDatabaseUsers;
use Stancl\Tenancy\DatabaseConfig;
use Stancl\Tenancy\Traits\CreatesDatabaseUsers;
class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager implements ManagesDatabaseUsers
{
use CreatesDatabaseUsers;
public static $grants = [
'ALTER', 'ALTER ROUTINE', 'CREATE', 'CREATE ROUTINE', 'CREATE TEMPORARY TABLES', 'CREATE VIEW',
'DELETE', 'DROP', 'EVENT', 'EXECUTE', 'INDEX', 'INSERT', 'LOCK TABLES', 'REFERENCES', 'SELECT',
'SHOW VIEW', 'TRIGGER', 'UPDATE',
];
public function createUser(DatabaseConfig $databaseConfig): void
public function createUser(DatabaseConfig $databaseConfig): bool
{
$database = $databaseConfig->getName();
$username = $databaseConfig->getUsername();
@ -32,7 +35,7 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl
$grantQuery = "GRANT $grants ON $database.* TO `$username`@`$hostname` IDENTIFIED BY '$password'";
}
$this->database()->statement($grantQuery);
return $this->database()->statement($grantQuery);
}
protected function isVersion8(): bool
@ -42,8 +45,8 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl
return version_compare($version, '8.0.0') >= 0;
}
public function deleteUser(DatabaseConfig $databaseConfig): void
public function deleteUser(DatabaseConfig $databaseConfig): bool
{
$this->database()->statement("DROP USER IF EXISTS '{$databaseConfig->username}'");
return $this->database()->statement("DROP USER IF EXISTS '{$databaseConfig->username}'");
}
}

View file

@ -9,6 +9,7 @@ use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Contracts\Future\CanSetConnection;
use Stancl\Tenancy\Contracts\TenantDatabaseManager;
use Stancl\Tenancy\Tenant;
class PostgreSQLDatabaseManager implements TenantDatabaseManager, CanSetConnection
{
@ -35,14 +36,14 @@ class PostgreSQLDatabaseManager implements TenantDatabaseManager, CanSetConnecti
$this->connection = $connection;
}
public function createDatabase(string $name): bool
public function createDatabase(Tenant $tenant): bool
{
return $this->database()->statement("CREATE DATABASE \"$name\" WITH TEMPLATE=template0");
return $this->database()->statement("CREATE DATABASE \"{$tenant->database()->getName()}\" WITH TEMPLATE=template0");
}
public function deleteDatabase(string $name): bool
public function deleteDatabase(Tenant $tenant): bool
{
return $this->database()->statement("DROP DATABASE \"$name\"");
return $this->database()->statement("DROP DATABASE \"{$tenant->database()->getName()}\"");
}
public function databaseExists(string $name): bool

View file

@ -9,6 +9,7 @@ use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Contracts\Future\CanSetConnection;
use Stancl\Tenancy\Contracts\TenantDatabaseManager;
use Stancl\Tenancy\Tenant;
class PostgreSQLSchemaManager implements TenantDatabaseManager, CanSetConnection
{
@ -35,14 +36,14 @@ class PostgreSQLSchemaManager implements TenantDatabaseManager, CanSetConnection
$this->connection = $connection;
}
public function createDatabase(string $name): bool
public function createDatabase(Tenant $tenant): bool
{
return $this->database()->statement("CREATE SCHEMA \"$name\"");
return $this->database()->statement("CREATE SCHEMA \"{$tenant->database()->getName()}\"");
}
public function deleteDatabase(string $name): bool
public function deleteDatabase(Tenant $tenant): bool
{
return $this->database()->statement("DROP SCHEMA \"$name\"");
return $this->database()->statement("DROP SCHEMA \"{$tenant->database()->getName()}\"");
}
public function databaseExists(string $name): bool

View file

@ -6,6 +6,7 @@ namespace Stancl\Tenancy\TenantDatabaseManagers;
use Stancl\Tenancy\Contracts\ModifiesDatabaseNameForConnection;
use Stancl\Tenancy\Contracts\TenantDatabaseManager;
use Stancl\Tenancy\Tenant;
class SQLiteDatabaseManager implements TenantDatabaseManager, ModifiesDatabaseNameForConnection
{
@ -14,19 +15,19 @@ class SQLiteDatabaseManager implements TenantDatabaseManager, ModifiesDatabaseNa
return 'database';
}
public function createDatabase(string $name): bool
public function createDatabase(Tenant $tenant): bool
{
try {
return fclose(fopen(database_path($name), 'w'));
return fclose(fopen(database_path($tenant->database()->getName()), 'w'));
} catch (\Throwable $th) {
return false;
}
}
public function deleteDatabase(string $name): bool
public function deleteDatabase(Tenant $tenant): bool
{
try {
return unlink(database_path($name));
return unlink(database_path($tenant->database()->getName()));
} catch (\Throwable $th) {
return false;
}

View file

@ -0,0 +1,26 @@
<?php
namespace Stancl\Tenancy\Traits;
use Stancl\Tenancy\Tenant;
trait CreatesDatabaseUsers
{
public function createDatabase(Tenant $tenant): bool
{
return $this->database()->transaction(function () use ($tenant) {
parent::createDatabase($tenant);
return $this->createUser($tenant->database());
});
}
public function deleteDatabase(Tenant $tenant): bool
{
return $this->database()->transaction(function () use ($tenant) {
parent::deleteDatabase($tenant);
return $this->deleteUser($tenant->database());
});
}
}

View file

@ -9,6 +9,7 @@ use Stancl\Tenancy\Jobs\QueuedTenantDatabaseCreator;
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseDeleter;
use Stancl\Tenancy\Tenant;
use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager;
use Stancl\Tenancy\TenantDatabaseManagers\PermissionControlledMySQLDatabaseManager;
use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager;
use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager;
use Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager;
@ -77,6 +78,7 @@ class TenantDatabaseManagerTest extends TestCase
{
return [
['mysql', MySQLDatabaseManager::class],
['mysql', PermissionControlledMySQLDatabaseManager::class],
['sqlite', SQLiteDatabaseManager::class],
['pgsql', PostgreSQLDatabaseManager::class],
['pgsql', PostgreSQLSchemaManager::class],