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. diff --git a/src/Interfaces/StorageDriver.php b/src/Interfaces/StorageDriver.php index 730c9c4d..8dbcf91e 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 getMany(string $uuid, array $keys): array; public function put(string $uuid, string $key, $value); - public function putMany(string $uuid, array $values); // todo better argument name than "values" for kv pairs? + public function putMany(string $uuid, array $values): array; } diff --git a/src/Jobs/QueuedTenantDatabaseCreator.php b/src/Jobs/QueuedTenantDatabaseCreator.php index b668f730..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) @@ -37,6 +36,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..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) @@ -37,6 +36,6 @@ class QueuedTenantDatabaseDeleter implements ShouldQueue */ public function handle() { - $this->databaseManager->deleteDatabase($databaseName); + $this->databaseManager->deleteDatabase($this->databaseName); } } diff --git a/src/Middleware/InitializeTenancy.php b/src/Middleware/InitializeTenancy.php index aed02fbc..64455baf 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); diff --git a/src/StorageDrivers/RedisStorageDriver.php b/src/StorageDrivers/RedisStorageDriver.php index 221e2edf..57b2b1f7 100644 --- a/src/StorageDrivers/RedisStorageDriver.php +++ b/src/StorageDrivers/RedisStorageDriver.php @@ -71,9 +71,20 @@ 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)); + } +<<<<<<< HEAD return \array_map(function ($tenant) { +======= +>>>>>>> 1.x return $this->redis->hgetall($tenant); }, $hashes); } @@ -83,7 +94,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 +105,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; diff --git a/src/TenantManager.php b/src/TenantManager.php index 6b058af5..eb32eeb0 100644 --- a/src/TenantManager.php +++ b/src/TenantManager.php @@ -77,7 +77,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; @@ -201,7 +201,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); 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() { 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() {