1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 23:54:04 +00:00

[2.3.0] Cached tenant lookup (#316)

* Begin work on cached lookup

* Apply fixes from StyleCI

* wip

* wip cache invalidation

* Apply fixes from StyleCI

* Finish cache invalidation

* Apply fixes from StyleCI

* Remove config from TestCase

* Enable cache in the single test file

* Separate data & domains logic

* Apply fixes from StyleCI

* wip

* Apply fixes from StyleCI
This commit is contained in:
Samuel Štancl 2020-03-14 19:52:35 +01:00 committed by GitHub
parent 142912edc5
commit c7c6a7fec8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 313 additions and 17 deletions

View file

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace Stancl\Tenancy\StorageDrivers\Database;
use Closure;
use Illuminate\Cache\CacheManager;
use Illuminate\Cache\Repository as CacheRepository;
use Illuminate\Config\Repository as ConfigRepository;
class CachedTenantResolver
{
/** @var CacheRepository */
protected $cache;
/** @var ConfigRepository */
protected $config;
public function __construct(CacheManager $cacheManager, ConfigRepository $config)
{
$this->cache = $cacheManager->store($config->get('tenancy.storage_drivers.db.cache_store'));
$this->config = $config;
}
protected function ttl(): int
{
return $this->config->get('tenancy.storage_drivers.db.cache_ttl');
}
public function getTenantIdByDomain(string $domain, Closure $query): string
{
return $this->cache->remember('_tenancy_domain_to_id:' . $domain, $this->ttl(), $query);
}
public function getDataById(string $id, Closure $dataQuery): ?array
{
return $this->cache->remember('_tenancy_id_to_data:' . $id, $this->ttl(), $dataQuery);
}
public function getDomainsById(string $id, Closure $domainsQuery): ?array
{
return $this->cache->remember('_tenancy_id_to_domains:' . $id, $this->ttl(), $domainsQuery);
}
public function invalidateTenant(string $id): void
{
$this->invalidateTenantData($id);
$this->invalidateTenantDomains($id);
}
public function invalidateTenantData(string $id): void
{
$this->cache->forget('_tenancy_id_to_data:' . $id);
}
public function invalidateTenantDomains(string $id): void
{
$this->cache->forget('_tenancy_id_to_domains:' . $id);
}
public function invalidateDomainToIdMapping(array $domains): void
{
foreach ($domains as $domain) {
$this->cache->forget('_tenancy_domain_to_id:' . $domain);
}
}
}

View file

@ -32,12 +32,16 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys, CanFindByAn
/** @var DomainRepository */
protected $domains;
/** @var CachedTenantResolver */
protected $cache;
/** @var Tenant The default tenant. */
protected $tenant;
public function __construct(Application $app, ConfigRepository $config)
public function __construct(Application $app, ConfigRepository $config, CachedTenantResolver $cache)
{
$this->app = $app;
$this->cache = $cache;
$this->centralDatabase = $this->getCentralConnection();
$this->tenants = new TenantRepository($config);
$this->domains = new DomainRepository($config);
@ -60,7 +64,16 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys, CanFindByAn
public function findByDomain(string $domain): Tenant
{
$id = $this->domains->getTenantIdByDomain($domain);
$query = function () use ($domain) {
return $this->domains->getTenantIdByDomain($domain);
};
if ($this->usesCache()) {
$id = $this->cache->getTenantIdByDomain($domain, $query);
} else {
$id = $query();
}
if (! $id) {
throw new TenantCouldNotBeIdentifiedException($domain);
}
@ -70,14 +83,29 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys, CanFindByAn
public function findById(string $id): Tenant
{
$tenant = $this->tenants->find($id);
$dataQuery = function () use ($id) {
$data = $this->tenants->find($id);
if (! $tenant) {
return $data ? $this->tenants->decodeData($data) : null;
};
$domainsQuery = function () use ($id) {
return $this->domains->getTenantDomains($id);
};
if ($this->usesCache()) {
$data = $this->cache->getDataById($id, $dataQuery);
$domains = $this->cache->getDomainsById($id, $domainsQuery);
} else {
$data = $dataQuery();
$domains = $domainsQuery();
}
if (! $data) {
throw new TenantDoesNotExistException($id);
}
return Tenant::fromStorage($this->tenants->decodeData($tenant))
->withDomains($this->domains->getTenantDomains($id));
return Tenant::fromStorage($data)
->withDomains($domains);
}
/**
@ -128,19 +156,33 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys, CanFindByAn
public function updateTenant(Tenant $tenant): void
{
$this->centralDatabase->transaction(function () use ($tenant) {
$originalDomains = $this->domains->getTenantDomains($tenant);
$this->centralDatabase->transaction(function () use ($tenant, $originalDomains) {
$this->tenants->updateTenant($tenant);
$this->domains->updateTenantDomains($tenant);
$this->domains->updateTenantDomains($tenant, $originalDomains);
});
if ($this->usesCache()) {
$this->cache->invalidateTenant($tenant->id);
$this->cache->invalidateDomainToIdMapping($originalDomains);
}
}
public function deleteTenant(Tenant $tenant): void
{
$originalDomains = $this->domains->getTenantDomains($tenant);
$this->centralDatabase->transaction(function () use ($tenant) {
$this->tenants->where('id', $tenant->id)->delete();
$this->domains->where('tenant_id', $tenant->id)->delete();
});
if ($this->usesCache()) {
$this->cache->invalidateTenant($tenant->id);
$this->cache->invalidateDomainToIdMapping($originalDomains);
}
}
/**
@ -179,16 +221,37 @@ class DatabaseStorageDriver implements StorageDriver, CanDeleteKeys, CanFindByAn
public function put(string $key, $value, Tenant $tenant = null): void
{
$this->tenants->put($key, $value, $tenant ?? $this->currentTenant());
$tenant = $tenant ?? $this->currentTenant();
$this->tenants->put($key, $value, $tenant);
if ($this->usesCache()) {
$this->cache->invalidateTenantData($tenant->id);
}
}
public function putMany(array $kvPairs, Tenant $tenant = null): void
{
$this->tenants->putMany($kvPairs, $tenant ?? $this->currentTenant());
$tenant = $tenant ?? $this->currentTenant();
$this->tenants->putMany($kvPairs, $tenant);
if ($this->usesCache()) {
$this->cache->invalidateTenantData($tenant->id);
}
}
public function deleteMany(array $keys, Tenant $tenant = null): void
{
$this->tenants->deleteMany($keys, $tenant ?? $this->currentTenant());
$tenant = $tenant ?? $this->currentTenant();
$this->tenants->deleteMany($keys, $tenant);
if ($this->usesCache()) {
$this->cache->invalidateTenantData($tenant->id);
}
}
public function usesCache(): bool
{
// null is also truthy here
return $this->app['config']['tenancy.storage_drivers.db.cache_store'] !== false;
}
}

View file

@ -33,9 +33,8 @@ class DomainRepository extends Repository
}, $tenant->domains));
}
public function updateTenantDomains(Tenant $tenant)
public function updateTenantDomains(Tenant $tenant, array $originalDomains)
{
$originalDomains = $this->getTenantDomains($tenant);
$deletedDomains = array_diff($originalDomains, $tenant->domains);
$newDomains = array_diff($tenant->domains, $originalDomains);