1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 14:34:04 +00:00
This commit is contained in:
Samuel Štancl 2019-02-08 20:27:56 +01:00
commit 39d9c9d51e
12 changed files with 230 additions and 102 deletions

View file

@ -1,14 +0,0 @@
<?php
namespace Stancl\Tenancy\DatabaseCreators;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Interfaces\DatabaseCreator;
class MySQLDatabaseCreator implements DatabaseCreator
{
public function createDatabase(string $name): bool
{
return DB::statement("CREATE DATABASE `$name` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
}
}

View file

@ -1,13 +0,0 @@
<?php
namespace Stancl\Tenancy\DatabaseCreators;
use Stancl\Tenancy\Interfaces\DatabaseCreator;
class SQLiteDatabaseCreator implements DatabaseCreator
{
public function createDatabase(string $name): bool
{
return fclose(fopen(database_path($name), 'w'));
}
}

View file

@ -3,7 +3,8 @@
namespace Stancl\Tenancy;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Jobs\QueuedDatabaseCreator;
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseCreator;
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseDeleter;
use Illuminate\Database\DatabaseManager as BaseDatabaseManager;
class DatabaseManager
@ -36,22 +37,35 @@ class DatabaseManager
$this->createTenantConnection($name);
$driver = $driver ?: $this->getDriver();
$databaseCreators = config('tenancy.database_creators');
$databaseManagers = config('tenancy.database_managers');
if (! array_key_exists($driver, $databaseCreators)) {
throw new \Exception("Database could not be created: no database creator for driver $driver is registered.");
if (! array_key_exists($driver, $databaseManagers)) {
throw new \Exception("Database could not be created: no database manager for driver $driver is registered.");
}
if (config('tenancy.queue_database_creation', false)) {
QueuedDatabaseCreator::dispatch(app($databaseCreators[$driver]), $name);
QueuedTenantDatabaseCreator::dispatch(app($databaseManagers[$driver]), $name, 'create');
} else {
app($databaseCreators[$driver])->createDatabase($name);
app($databaseManagers[$driver])->createDatabase($name);
}
}
public function delete()
public function delete(string $name, string $driver = null)
{
// todo: delete database. similar to create()
$this->createTenantConnection($name);
$driver = $driver ?: $this->getDriver();
$databaseManagers = config('tenancy.database_managers');
if (! array_key_exists($driver, $databaseManagers)) {
throw new \Exception("Database could not be deleted: no database manager for driver $driver is registered.");
}
if (config('tenancy.queue_database_deletion', false)) {
QueuedTenantDatabaseDeleter::dispatch(app($databaseManagers[$driver]), $name, 'delete');
} else {
app($databaseManagers[$driver])->deleteDatabase($name);
}
}
public function getDriver(): ?string

View file

@ -1,14 +0,0 @@
<?php
namespace Stancl\Tenancy\Interfaces;
interface DatabaseCreator
{
/**
* Create a database.
*
* @param string $name Name of the database.
* @return void
*/
public function createDatabase(string $name): bool;
}

View file

@ -0,0 +1,22 @@
<?php
namespace Stancl\Tenancy\Interfaces;
interface TenantDatabaseManager
{
/**
* Create a database.
*
* @param string $name Name of the database.
* @return boolean
*/
public function createDatabase(string $name): bool;
/**
* Delete a database.
*
* @param string $name Name of the database.
* @return boolean
*/
public function deleteDatabase(string $name): bool;
}

View file

@ -7,22 +7,26 @@ use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Stancl\Tenancy\Interfaces\DatabaseCreator;
use Stancl\Tenancy\Interfaces\TenantDatabaseManager;
class QueuedDatabaseCreator implements ShouldQueue
class QueuedTenantDatabaseCreator implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $databaseManager;
protected $databaseName;
/**
* Create a new job instance.
*
* @param DatabaseCreator $databaseCreator
* @param string $databaseName
* @param string $action
* @return void
*/
public function __construct(DatabaseCreator $databaseCreator, string $databaseName)
public function __construct(TenantDatabaseManager $databaseManager, string $databaseName)
{
$this->databaseCreator = $databaseCreator;
$this->databaseManager = $databaseManager;
$this->databaseName = $databaseName;
}
@ -33,6 +37,6 @@ class QueuedDatabaseCreator implements ShouldQueue
*/
public function handle()
{
$this->databaseCreator->createDatabase($databaseName);
$this->databaseManager->createDatabase($databaseName);
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace Stancl\Tenancy\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Stancl\Tenancy\Interfaces\TenantDatabaseManager;
class QueuedTenantDatabaseDeleter implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $databaseManager;
protected $databaseName;
/**
* Create a new job instance.
*
* @param DatabaseCreator $databaseCreator
* @param string $databaseName
* @param string $action
* @return void
*/
public function __construct(TenantDatabaseManager $databaseManager, string $databaseName)
{
$this->databaseManager = $databaseManager;
$this->databaseName = $databaseName;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$this->databaseManager->deleteDatabase($databaseName);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace Stancl\Tenancy\TenantDatabaseManagers;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Interfaces\TenantDatabaseManager;
class MySQLDatabaseManager implements TenantDatabaseManager
{
public function createDatabase(string $name): bool
{
return DB::statement("CREATE DATABASE `$name` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
}
public function deleteDatabase(string $name): bool
{
return DB::statement("DROP DATABASE `$name`");
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Stancl\Tenancy\TenantDatabaseManagers;
use Stancl\Tenancy\Interfaces\TenantDatabaseManager;
class SQLiteDatabaseManager implements TenantDatabaseManager
{
public function createDatabase(string $name): bool
{
try {
return fclose(fopen(database_path($name), 'w'));
} catch (\Throwable $th) {
return false;
}
}
public function deleteDatabase(string $name): bool
{
try {
return unlink(database_path($name));
} catch (\Throwable $th) {
return false;
}
}
}

View file

@ -29,9 +29,10 @@ return [
// 's3',
],
],
'database_creators' => [
'sqlite' => 'Stancl\Tenancy\DatabaseCreators\SQLiteDatabaseCreator',
'mysql' => 'Stancl\Tenancy\DatabaseCreators\MySQLDatabaseCreator',
'database_managers' => [
'sqlite' => 'Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager',
'mysql' => 'Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager',
],
'queue_database_creation' => false,
'queue_database_deletion' => false,
];

View file

@ -1,45 +0,0 @@
<?php
namespace Stancl\Tenancy\Tests;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\DatabaseManager;
use Illuminate\Support\Facades\Queue;
use Stancl\Tenancy\Jobs\QueuedDatabaseCreator;
class DatabaseCreationTest extends TestCase
{
/** @test */
public function sqlite_database_is_created()
{
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
app(DatabaseManager::class)->create($db_name, 'sqlite');
$this->assertFileExists(database_path($db_name));
}
/** @test */
public function mysql_database_is_created()
{
if (! $this->isTravis()) {
$this->markTestSkipped('As to not bloat your MySQL instance with test databases, this test is not run by default.');
}
config()->set('database.default', 'mysql');
$db_name = 'testdatabase' . $this->randomString(10);
app(DatabaseManager::class)->create($db_name, 'mysql');
$this->assertNotEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'"));
}
/** @test */
public function database_creation_can_be_queued()
{
Queue::fake();
config()->set('tenancy.queue_database_creation', true);
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
app(DatabaseManager::class)->create($db_name, 'sqlite');
Queue::assertPushed(QueuedDatabaseCreator::class);
}
}

View file

@ -0,0 +1,86 @@
<?php
namespace Stancl\Tenancy\Tests;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\DatabaseManager;
use Illuminate\Support\Facades\Queue;
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseCreator;
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseDeleter;
class TenantDatabaseManagerTest extends TestCase
{
/** @test */
public function sqlite_database_is_created()
{
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
app(DatabaseManager::class)->create($db_name, 'sqlite');
$this->assertFileExists(database_path($db_name));
}
/** @test */
public function mysql_database_is_created()
{
if (! $this->isTravis()) {
$this->markTestSkipped('As to not bloat your MySQL instance with test databases, this test is not run by default.');
}
config()->set('database.default', 'mysql');
$db_name = 'testdatabase' . $this->randomString(10);
app(DatabaseManager::class)->create($db_name, 'mysql');
$this->assertNotEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'"));
}
/** @test */
public function database_creation_can_be_queued()
{
Queue::fake();
config()->set('tenancy.queue_database_creation', true);
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
app(DatabaseManager::class)->create($db_name, 'sqlite');
Queue::assertPushed(QueuedTenantDatabaseCreator::class);
}
/** @test */
public function sqlite_database_is_deleted()
{
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
app(DatabaseManager::class)->create($db_name, 'sqlite');
$this->assertFileExists(database_path($db_name));
app(DatabaseManager::class)->delete($db_name, 'sqlite');
$this->assertFileNotExists(database_path($db_name));
}
/** @test */
public function mysql_database_is_deleted()
{
if (! $this->isTravis()) {
$this->markTestSkipped('As to not bloat your MySQL instance with test databases, this test is not run by default.');
}
config()->set('database.default', 'mysql');
$db_name = 'testdatabase' . $this->randomString(10);
app(DatabaseManager::class)->create($db_name, 'mysql');
$this->assertNotEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'"));
app(DatabaseManager::class)->delete($db_name, 'mysql');
$this->assertEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'"));
}
/** @test */
public function database_deletion_can_be_queued()
{
Queue::fake();
config()->set('tenancy.queue_database_deletion', true);
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
app(DatabaseManager::class)->delete($db_name, 'sqlite');
Queue::assertPushed(QueuedTenantDatabaseDeleter::class);
}
}