1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 19:14: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; namespace Stancl\Tenancy;
use Illuminate\Support\Facades\DB; 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; use Illuminate\Database\DatabaseManager as BaseDatabaseManager;
class DatabaseManager class DatabaseManager
@ -36,22 +37,35 @@ class DatabaseManager
$this->createTenantConnection($name); $this->createTenantConnection($name);
$driver = $driver ?: $this->getDriver(); $driver = $driver ?: $this->getDriver();
$databaseCreators = config('tenancy.database_creators'); $databaseManagers = config('tenancy.database_managers');
if (! array_key_exists($driver, $databaseCreators)) { if (! array_key_exists($driver, $databaseManagers)) {
throw new \Exception("Database could not be created: no database creator for driver $driver is registered."); throw new \Exception("Database could not be created: no database manager for driver $driver is registered.");
} }
if (config('tenancy.queue_database_creation', false)) { if (config('tenancy.queue_database_creation', false)) {
QueuedDatabaseCreator::dispatch(app($databaseCreators[$driver]), $name); QueuedTenantDatabaseCreator::dispatch(app($databaseManagers[$driver]), $name, 'create');
} else { } 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 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\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue; 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; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $databaseManager;
protected $databaseName;
/** /**
* Create a new job instance. * Create a new job instance.
* *
* @param DatabaseCreator $databaseCreator * @param DatabaseCreator $databaseCreator
* @param string $databaseName * @param string $databaseName
* @param string $action
* @return void * @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; $this->databaseName = $databaseName;
} }
@ -33,6 +37,6 @@ class QueuedDatabaseCreator implements ShouldQueue
*/ */
public function handle() 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', // 's3',
], ],
], ],
'database_creators' => [ 'database_managers' => [
'sqlite' => 'Stancl\Tenancy\DatabaseCreators\SQLiteDatabaseCreator', 'sqlite' => 'Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager',
'mysql' => 'Stancl\Tenancy\DatabaseCreators\MySQLDatabaseCreator', 'mysql' => 'Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager',
], ],
'queue_database_creation' => false, '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);
}
}