diff --git a/src/StorageDrivers/Database/DatabaseStorageDriver.php b/src/StorageDrivers/Database/DatabaseStorageDriver.php index 553f3303..383cb890 100644 --- a/src/StorageDrivers/Database/DatabaseStorageDriver.php +++ b/src/StorageDrivers/Database/DatabaseStorageDriver.php @@ -9,6 +9,7 @@ use Illuminate\Database\Connection; use Illuminate\Foundation\Application; use Illuminate\Support\Facades\DB; use Stancl\Tenancy\Contracts\Future\CanDeleteKeys; +use Stancl\Tenancy\Contracts\Future\CanFindByAnyKey; use Stancl\Tenancy\Contracts\StorageDriver; use Stancl\Tenancy\DatabaseManager; use Stancl\Tenancy\Exceptions\DomainsOccupiedByOtherTenantException; @@ -17,7 +18,7 @@ use Stancl\Tenancy\Exceptions\TenantDoesNotExistException; use Stancl\Tenancy\Exceptions\TenantWithThisIdAlreadyExistsException; use Stancl\Tenancy\Tenant; -class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys +class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys, CanFindByAnyKey { /** @var Application */ protected $app; @@ -89,15 +90,14 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys */ public function findBy(string $key, $value): Tenant { - // The key has to be a custom column. It's recommended to set up an index // TODO can we query JSON? - $tenant = $this->tenants->where($key, $value)->first()->toArray(); + $tenant = $this->tenants->findBy($key, $value); if (! $tenant) { throw new TenantDoesNotExistException($value, $key); } - return Tenant::fromStorage($tenant->decoded()) - ->withDomains($this->domains->getTenantDomains($tenant->id)); + return Tenant::fromStorage($this->tenants->decodeData($tenant)) + ->withDomains($this->domains->getTenantDomains($tenant['id'])); } public function ensureTenantCanBeCreated(Tenant $tenant): void diff --git a/src/StorageDrivers/Database/TenantRepository.php b/src/StorageDrivers/Database/TenantRepository.php index 11c36a95..478b4f49 100644 --- a/src/StorageDrivers/Database/TenantRepository.php +++ b/src/StorageDrivers/Database/TenantRepository.php @@ -30,6 +30,18 @@ class TenantRepository extends Repository ); } + public function findBy(string $key, $value) + { + if (in_array($key, static::customColumns())) { + return (array) $this->table()->where($key, $value)->first(); + } + + return (array) $this->table()->where( + static::dataColumn() . '->' . $key, + $value + )->first(); + } + public function updateTenant(Tenant $tenant) { $this->putMany($tenant->data, $tenant); @@ -98,11 +110,11 @@ class TenantRepository extends Repository $data = []; $jsonData = json_decode($record->first(static::dataColumn())->data, true); - foreach ($keys as $key => $key) { + foreach ($keys as $key) { if (in_array($key, static::customColumns())) { $data[$key] = null; - return; + continue; } else { unset($jsonData[$key]); } diff --git a/src/StorageDrivers/RedisStorageDriver.php b/src/StorageDrivers/RedisStorageDriver.php index 453bd030..79852f8c 100644 --- a/src/StorageDrivers/RedisStorageDriver.php +++ b/src/StorageDrivers/RedisStorageDriver.php @@ -236,6 +236,6 @@ class RedisStorageDriver implements StorageDriver, CanDeleteKeys { $tenant = $tenant ?? $this->tenant(); - $this->redis->hdel("tenants:{$tenant->id}", $keys); + $this->redis->hdel("tenants:{$tenant->id}", ...$keys); } } diff --git a/src/Tenant.php b/src/Tenant.php index 253438eb..30a4981a 100644 --- a/src/Tenant.php +++ b/src/Tenant.php @@ -351,24 +351,34 @@ class Tenant implements ArrayAccess return $this->put($key, $value); } - // todo also deleteKey()? + /** + * Delete a key from the tenant's storage. + * + * @param string $key + * @return self + */ + public function deleteKey(string $key): self + { + return $this->deleteKeys([$key]); + } /** * Delete keys from the tenant's storage. * - * @param string|string[] $keys + * @param string[] $keys * @return self */ - public function deleteKeys($keys): self + public function deleteKeys(array $keys): self { - $keys = (array) $keys; - if (! $this->storage instanceof CanDeleteKeys) { throw new NotImplementedException(get_class($this->storage), 'deleteMany', 'This method was added to storage drivers provided by the package in 2.2.0 and will be part of the StorageDriver contract in 3.0.0.' ); } else { $this->storage->deleteMany($keys); + foreach ($keys as $key) { + unset($this->data[$key]); + } } return $this; diff --git a/src/TenantManager.php b/src/TenantManager.php index 688d3cca..7d5c61c2 100644 --- a/src/TenantManager.php +++ b/src/TenantManager.php @@ -10,7 +10,7 @@ use Illuminate\Foundation\Application; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; -use Stancl\Tenancy\Contracts\Future\CanFindByAnyKeys; +use Stancl\Tenancy\Contracts\Future\CanFindByAnyKey; use Stancl\Tenancy\Contracts\TenantCannotBeCreatedException; use Stancl\Tenancy\Exceptions\NotImplementedException; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedException; @@ -232,7 +232,7 @@ class TenantManager throw new Exception('No value supplied.'); } - if (! $this->storage instanceof CanFindByAnyKeys) { + if (! $this->storage instanceof CanFindByAnyKey) { throw new NotImplementedException(get_class($this->storage), 'findBy', 'This method was added to the DB storage driver provided by the package in 2.2.0 and might be part of the StorageDriver contract in 3.0.0.' ); diff --git a/tests/FutureTest.php b/tests/FutureTest.php new file mode 100644 index 00000000..6a44a80e --- /dev/null +++ b/tests/FutureTest.php @@ -0,0 +1,45 @@ +withData(['email' => 'foo@example.com', 'role' => 'admin'])->save(); + + $this->assertArrayHasKey('email', $tenant->data); + $tenant->deleteKey('email'); + $this->assertArrayNotHasKey('email', $tenant->data); + $this->assertArrayNotHasKey('email', tenancy()->all()->first()->data); + + $tenant->put(['foo' => 'bar', 'abc' => 'xyz']); + $this->assertArrayHasKey('foo', $tenant->data); + $this->assertArrayHasKey('abc', $tenant->data); + + $tenant->deleteKeys(['foo', 'abc']); + $this->assertArrayNotHasKey('foo', $tenant->data); + $this->assertArrayNotHasKey('abc', $tenant->data); + } + + /** @test */ + public function tenant_can_be_identified_using_an_arbitrary_string() + { + if (! tenancy()->storage instanceof CanFindByAnyKey) { + $this->markTestSkipped(get_class(tenancy()->storage) . ' does not implement the CanFindByAnyKey interface.'); + } + + $tenant = Tenant::new()->withData(['email' => 'foo@example.com'])->save(); + + $this->assertSame($tenant->id, tenancy()->findByEmail('foo@example.com')->id); + } +}