From 4c7e6c0e063c40ebb1b52149d6e0e9dbb51774a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= <33033094+stancl@users.noreply.github.com> Date: Sun, 3 Mar 2019 17:04:17 +0100 Subject: [PATCH 01/10] Make snippet syntactically correct --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6506de85..6f2e3977 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ Open `app/Http/Kernel.php` and make the middleware top priority, so that it gets ```php protected $middlewarePriority = [ \Stancl\Tenancy\Middleware\InitializeTenancy::class, + // ... +]; ``` When a tenant route is visited, but the tenant can't be identified, an exception is thrown. If you want to change this behavior, to a redirect for example, add this to your `app/Providers/AppServiceProvider.php`'s `boot()` method. From ddc0e6fb1ee6a8bd61faca70c5561c6414995673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= <33033094+stancl@users.noreply.github.com> Date: Mon, 4 Mar 2019 22:19:38 +0100 Subject: [PATCH 02/10] Remove support for onFail without arguments to improve performance --- src/Middleware/InitializeTenancy.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Middleware/InitializeTenancy.php b/src/Middleware/InitializeTenancy.php index cd6383a5..3c37360a 100644 --- a/src/Middleware/InitializeTenancy.php +++ b/src/Middleware/InitializeTenancy.php @@ -25,13 +25,7 @@ class InitializeTenancy try { tenancy()->init(); } catch (\Exception $e) { - // Pass the exception to the onFail function if it takes any parameters. - $callback = $this->onFail; - if ((new \ReflectionFunction($callback))->getNumberOfParameters() > 0) { - $callback($e); - } else { - $callback(); - } + ($this->onFail)($e); } return $next($request); From 9bc9b92d8daf9dfdaaee1ebf0708b5595bfcd143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 23 Apr 2019 17:09:32 +0200 Subject: [PATCH 03/10] [breaking fix] Add array return types to StorageDriver interface --- src/Interfaces/StorageDriver.php | 4 ++-- src/TenantManager.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Interfaces/StorageDriver.php b/src/Interfaces/StorageDriver.php index 730c9c4d..fbb2d77c 100644 --- a/src/Interfaces/StorageDriver.php +++ b/src/Interfaces/StorageDriver.php @@ -11,7 +11,7 @@ interface StorageDriver public function createTenant(string $domain, string $uuid): array; public function deleteTenant(string $uuid): bool; public function get(string $uuid, string $key); - public function getMany(string $uuid, array $keys); - public function put(string $uuid, string $key, $value); + public function getMany(string $uuid, array $keys): array; + public function put(string $uuid, string $key, $value): array; public function putMany(string $uuid, array $values); // todo better argument name than "values" for kv pairs? } diff --git a/src/TenantManager.php b/src/TenantManager.php index f9e4c76b..254eaa9d 100644 --- a/src/TenantManager.php +++ b/src/TenantManager.php @@ -78,7 +78,7 @@ class TenantManager throw new \Exception("Domain $domain is already occupied by tenant $id."); } - $tenant = $this->jsonDecodeArrayValues($this->storage->createTenant($domain, \Webpatser\Uuid\Uuid::generate(1, $domain))); + $tenant = $this->jsonDecodeArrayValues($this->storage->createTenant($domain, (string) \Webpatser\Uuid\Uuid::generate(1, $domain))); $this->database->create($this->getDatabaseName($tenant)); return $tenant; From 9e4849439f24bd7fecea02d389d2d92e0fa295f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 23 Apr 2019 17:11:05 +0200 Subject: [PATCH 04/10] Update RedisStorageDriver with the interface change --- src/StorageDrivers/RedisStorageDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StorageDrivers/RedisStorageDriver.php b/src/StorageDrivers/RedisStorageDriver.php index 4e605b31..bb24550c 100644 --- a/src/StorageDrivers/RedisStorageDriver.php +++ b/src/StorageDrivers/RedisStorageDriver.php @@ -83,7 +83,7 @@ class RedisStorageDriver implements StorageDriver return $this->redis->hget("tenants:$uuid", $key); } - public function getMany(string $uuid, array $keys) + public function getMany(string $uuid, array $keys): array { return $this->redis->hmget("tenants:$uuid", $keys); } @@ -94,7 +94,7 @@ class RedisStorageDriver implements StorageDriver return $value; } - public function putMany(string $uuid, array $values) + public function putMany(string $uuid, array $values): array { $this->redis->hmset("tenants:$uuid", $values); return $values; From b20f62ecfa7461560800b9e1acf3f3bd432b905e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 23 Apr 2019 17:11:46 +0200 Subject: [PATCH 05/10] putMany() should return array, not put() --- src/Interfaces/StorageDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Interfaces/StorageDriver.php b/src/Interfaces/StorageDriver.php index fbb2d77c..eb2c15ed 100644 --- a/src/Interfaces/StorageDriver.php +++ b/src/Interfaces/StorageDriver.php @@ -12,6 +12,6 @@ interface StorageDriver public function deleteTenant(string $uuid): bool; public function get(string $uuid, string $key); public function getMany(string $uuid, array $keys): array; - public function put(string $uuid, string $key, $value): array; - public function putMany(string $uuid, array $values); // todo better argument name than "values" for kv pairs? + public function put(string $uuid, string $key, $value); + public function putMany(string $uuid, array $values): array; // todo better argument name than "values" for kv pairs? } From edea513edf382ee1b4f91809cafa45a3cf02a4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 23 Apr 2019 17:56:54 +0200 Subject: [PATCH 06/10] Test jobs' handle() (#40) * Test jobs' handle() * Switch (fix) method names --- tests/TenantDatabaseManagerTest.php | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index 3c16378f..8d25913a 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -21,6 +21,22 @@ class TenantDatabaseManagerTest extends TestCase $this->assertFileNotExists(database_path($db_name)); } + /** @test */ + public function sqlite_database_can_be_created_and_deleted_using_queued_commands() + { + $db_name = 'testdatabase' . $this->randomString(10) . '.sqlite'; + + $databaseManagers = config('tenancy.database_managers'); + $job = new QueuedTenantDatabaseCreator(app($databaseManagers['sqlite']), $db_name); + $job->handle(); + + $this->assertFileExists(database_path($db_name)); + + $job = new QueuedTenantDatabaseDeleter(app($databaseManagers['sqlite']), $db_name); + $job->handle(); + $this->assertFileNotExists(database_path($db_name)); + } + /** @test */ public function mysql_database_can_be_created_and_deleted() { @@ -38,6 +54,30 @@ class TenantDatabaseManagerTest extends TestCase $this->assertEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'")); } + /** @test */ + public function mysql_database_can_be_created_and_deleted_using_queued_commands() + { + 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); + + $databaseManagers = config('tenancy.database_managers'); + $job = new QueuedTenantDatabaseCreator(app($databaseManagers['mysql']), $db_name); + $job->handle(); + + $this->assertNotEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'")); + + $databaseManagers = config('tenancy.database_managers'); + $job = new QueuedTenantDatabaseDeleter(app($databaseManagers['mysql']), $db_name); + $job->handle(); + + $this->assertEmpty(DB::select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$db_name'")); + } + /** @test */ public function database_creation_can_be_queued() { From c0a83e70f1617f87a12503970881d1e2614c8dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 23 Apr 2019 17:57:05 +0200 Subject: [PATCH 07/10] Fix classes in the Jobs namespace (#38) --- src/Jobs/QueuedTenantDatabaseCreator.php | 2 +- src/Jobs/QueuedTenantDatabaseDeleter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Jobs/QueuedTenantDatabaseCreator.php b/src/Jobs/QueuedTenantDatabaseCreator.php index b668f730..a18ddb85 100644 --- a/src/Jobs/QueuedTenantDatabaseCreator.php +++ b/src/Jobs/QueuedTenantDatabaseCreator.php @@ -37,6 +37,6 @@ class QueuedTenantDatabaseCreator implements ShouldQueue */ public function handle() { - $this->databaseManager->createDatabase($databaseName); + $this->databaseManager->createDatabase($this->databaseName); } } diff --git a/src/Jobs/QueuedTenantDatabaseDeleter.php b/src/Jobs/QueuedTenantDatabaseDeleter.php index 4dbdf4bc..5cb5d35a 100644 --- a/src/Jobs/QueuedTenantDatabaseDeleter.php +++ b/src/Jobs/QueuedTenantDatabaseDeleter.php @@ -37,6 +37,6 @@ class QueuedTenantDatabaseDeleter implements ShouldQueue */ public function handle() { - $this->databaseManager->deleteDatabase($databaseName); + $this->databaseManager->deleteDatabase($this->databaseName); } } From 5d5417cf11e46af4c2e1f00bb627e3b3acc02257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Tue, 23 Apr 2019 18:03:40 +0200 Subject: [PATCH 08/10] Fix Jobs' docblocks (fix #39) --- src/Jobs/QueuedTenantDatabaseCreator.php | 3 +-- src/Jobs/QueuedTenantDatabaseDeleter.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Jobs/QueuedTenantDatabaseCreator.php b/src/Jobs/QueuedTenantDatabaseCreator.php index a18ddb85..f23f6442 100644 --- a/src/Jobs/QueuedTenantDatabaseCreator.php +++ b/src/Jobs/QueuedTenantDatabaseCreator.php @@ -19,9 +19,8 @@ class QueuedTenantDatabaseCreator implements ShouldQueue /** * Create a new job instance. * - * @param DatabaseCreator $databaseCreator + * @param TenantDatabaseManager $databaseManager * @param string $databaseName - * @param string $action * @return void */ public function __construct(TenantDatabaseManager $databaseManager, string $databaseName) diff --git a/src/Jobs/QueuedTenantDatabaseDeleter.php b/src/Jobs/QueuedTenantDatabaseDeleter.php index 5cb5d35a..ba3e5bc7 100644 --- a/src/Jobs/QueuedTenantDatabaseDeleter.php +++ b/src/Jobs/QueuedTenantDatabaseDeleter.php @@ -19,9 +19,8 @@ class QueuedTenantDatabaseDeleter implements ShouldQueue /** * Create a new job instance. * - * @param DatabaseCreator $databaseCreator + * @param TenantDatabaseManager $databaseManager * @param string $databaseName - * @param string $action * @return void */ public function __construct(TenantDatabaseManager $databaseManager, string $databaseName) From beb9a0a9035acb102cfdf3f7e9cd6652ada2ac36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 24 Apr 2019 09:22:12 +0200 Subject: [PATCH 09/10] Move todos to issues (#45) * Remove todo * Remove todo --- src/Interfaces/StorageDriver.php | 2 +- tests/TenantStorageTest.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Interfaces/StorageDriver.php b/src/Interfaces/StorageDriver.php index eb2c15ed..8dbcf91e 100644 --- a/src/Interfaces/StorageDriver.php +++ b/src/Interfaces/StorageDriver.php @@ -13,5 +13,5 @@ interface StorageDriver public function get(string $uuid, string $key); public function getMany(string $uuid, array $keys): array; public function put(string $uuid, string $key, $value); - public function putMany(string $uuid, array $values): array; // todo better argument name than "values" for kv pairs? + public function putMany(string $uuid, array $values): array; } diff --git a/tests/TenantStorageTest.php b/tests/TenantStorageTest.php index 69388b38..bfbfa368 100644 --- a/tests/TenantStorageTest.php +++ b/tests/TenantStorageTest.php @@ -6,8 +6,6 @@ use Stancl\Tenancy\Interfaces\StorageDriver; class TenantStorageTest extends TestCase { - // todo find a way to run this for each storage driver (once there are more of them) - /** @test */ public function deleting_a_tenant_works() { From 35abb6191d230311c905ca25a0e6c5073e6bc9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 24 Apr 2019 16:53:43 +0200 Subject: [PATCH 10/10] Fix Redis scan for 5.8 (#46) * Fix Redis scan for 5.8 * Add comments [ci skip] --- src/StorageDrivers/RedisStorageDriver.php | 11 +++++++++-- src/TenantManager.php | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/StorageDrivers/RedisStorageDriver.php b/src/StorageDrivers/RedisStorageDriver.php index bb24550c..699950e6 100644 --- a/src/StorageDrivers/RedisStorageDriver.php +++ b/src/StorageDrivers/RedisStorageDriver.php @@ -71,9 +71,16 @@ class RedisStorageDriver implements StorageDriver return "tenants:{$hash}"; }, $uuids); - $hashes = $hashes ?: $this->redis->scan(null, 'tenants:*'); + // Apparently, the PREFIX is applied to all functions except scan() + $redis_prefix = $this->redis->getOption($this->redis->client()::OPT_PREFIX); + $hashes = $hashes ?: $this->redis->scan(null, $redis_prefix.'tenants:*'); + + return array_map(function ($tenant) use ($redis_prefix) { + // Left strip $redis_prefix from $tenant + if (substr($tenant, 0, strlen($redis_prefix)) == $redis_prefix) { + $tenant = substr($tenant, strlen($redis_prefix)); + } - return array_map(function ($tenant) { return $this->redis->hgetall($tenant); }, $hashes); } diff --git a/src/TenantManager.php b/src/TenantManager.php index 254eaa9d..1e105c1f 100644 --- a/src/TenantManager.php +++ b/src/TenantManager.php @@ -202,7 +202,7 @@ class TenantManager */ public function all($uuids = []) { - $uuid = (array) $uuids; + $uuids = (array) $uuids; return collect(array_map(function ($tenant_array) { return $this->jsonDecodeArrayValues($tenant_array);