diff --git a/.gitattributes b/.gitattributes index 9112d843..7d68b812 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,16 +2,16 @@ # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html # Ignore all test and documentation with "export-ignore". -/.github export-ignore -/art export-ignore -/tests export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.styleci.yml export-ignore +/.github export-ignore +/art export-ignore +/tests export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.styleci.yml export-ignore /docker-compose.yml export-ignore -/Dockerfile export-ignore -/fulltest export-ignore -/phpunit.xml export-ignore -/.editorconfig export-ignore -/.coverage.xml export-ignore -/coverage export-ignore +/Dockerfile export-ignore +/test export-ignore +/phpunit.xml export-ignore +/.editorconfig export-ignore +/.coverage.xml export-ignore +/coverage export-ignore diff --git a/src/Contracts/Tenant.php b/src/Contracts/Tenant.php index 5a49360d..dc5667a3 100644 --- a/src/Contracts/Tenant.php +++ b/src/Contracts/Tenant.php @@ -6,6 +6,10 @@ namespace Stancl\Tenancy\Contracts; /** * @see \Stancl\Tenancy\Database\Models\Tenant + * + * @method mixed __call() IDE support. This will be a model. + * @method mixed __callStatic() IDE support. This will be a model. + * @mixin \Illuminate\Database\Eloquent\Model */ interface Tenant { diff --git a/src/Database/Concerns/InvalidatesResolverCache.php b/src/Database/Concerns/InvalidatesResolverCache.php new file mode 100644 index 00000000..65e40b13 --- /dev/null +++ b/src/Database/Concerns/InvalidatesResolverCache.php @@ -0,0 +1,28 @@ +invalidateCache($tenant); + } + }); + } +} diff --git a/src/Database/Concerns/InvalidatesTenantsResolverCache.php b/src/Database/Concerns/InvalidatesTenantsResolverCache.php new file mode 100644 index 00000000..23e9acd5 --- /dev/null +++ b/src/Database/Concerns/InvalidatesTenantsResolverCache.php @@ -0,0 +1,32 @@ +invalidateCache($model->tenant); + } + }); + } +} diff --git a/src/Database/Models/Domain.php b/src/Database/Models/Domain.php index 2a6099b1..7c0e0596 100644 --- a/src/Database/Models/Domain.php +++ b/src/Database/Models/Domain.php @@ -19,7 +19,8 @@ use Stancl\Tenancy\Events; class Domain extends Model implements Contracts\Domain { use Concerns\CentralConnection, - Concerns\EnsuresDomainIsNotOccupied; + Concerns\EnsuresDomainIsNotOccupied, + Concerns\InvalidatesTenantsResolverCache; protected $guarded = []; diff --git a/src/Database/Models/Tenant.php b/src/Database/Models/Tenant.php index 8032716f..d6e97c44 100644 --- a/src/Database/Models/Tenant.php +++ b/src/Database/Models/Tenant.php @@ -25,7 +25,8 @@ class Tenant extends Model implements Contracts\Tenant Concerns\GeneratesIds, Concerns\HasDataColumn, Concerns\HasInternalKeys, - Concerns\TenantRun; + Concerns\TenantRun, + Concerns\InvalidatesResolverCache; protected $table = 'tenants'; protected $primaryKey = 'id'; diff --git a/src/Middleware/IdentificationMiddleware.php b/src/Middleware/IdentificationMiddleware.php index 16056fea..7a7a5210 100644 --- a/src/Middleware/IdentificationMiddleware.php +++ b/src/Middleware/IdentificationMiddleware.php @@ -14,15 +14,6 @@ abstract class IdentificationMiddleware /** @var callable */ public static $onFail; - /** @var bool */ - public static $shouldCache = false; - - /** @var int */ - public static $cacheTTL = 3600; // seconds - - /** @var string|null */ - public static $cacheStore = null; // default - /** @var Tenancy */ protected $tenancy; @@ -32,15 +23,9 @@ abstract class IdentificationMiddleware public function initializeTenancy($request, $next, ...$resolverArguments) { try { - if (static::$shouldCache) { - app(CachedTenantResolver::class)->resolve( - get_class($this->resolver), $resolverArguments, static::$cacheTTL, static::$cacheStore - ); - } else { - $this->tenancy->initialize( - $this->resolver->resolve(...$resolverArguments) - ); - } + $this->tenancy->initialize( + $this->resolver->resolve(...$resolverArguments) + ); } catch (TenantCouldNotBeIdentifiedException $e) { $onFail = static::$onFail ?? function ($e) { throw $e; diff --git a/src/Middleware/InitializeTenancyByDomain.php b/src/Middleware/InitializeTenancyByDomain.php index 1c1d386a..24a1abb7 100644 --- a/src/Middleware/InitializeTenancyByDomain.php +++ b/src/Middleware/InitializeTenancyByDomain.php @@ -13,15 +13,6 @@ class InitializeTenancyByDomain extends IdentificationMiddleware /** @var callable|null */ public static $onFail; - /** @var bool */ - public static $shouldCache = false; - - /** @var int */ - public static $cacheTTL = 3600; // seconds - - /** @var string|null */ - public static $cacheStore = null; // default - /** @var Tenancy */ protected $tenancy; diff --git a/src/Middleware/InitializeTenancyByPath.php b/src/Middleware/InitializeTenancyByPath.php index 7326d871..6289199b 100644 --- a/src/Middleware/InitializeTenancyByPath.php +++ b/src/Middleware/InitializeTenancyByPath.php @@ -16,15 +16,6 @@ class InitializeTenancyByPath extends IdentificationMiddleware /** @var callable|null */ public static $onFail; - /** @var bool */ - public static $shouldCache = false; - - /** @var int */ - public static $cacheTTL = 3600; // seconds - - /** @var string|null */ - public static $cacheStore = null; // default - /** @var Tenancy */ protected $tenancy; diff --git a/src/Middleware/InitializeTenancyByRequestData.php b/src/Middleware/InitializeTenancyByRequestData.php index be225cdb..de75d8c5 100644 --- a/src/Middleware/InitializeTenancyByRequestData.php +++ b/src/Middleware/InitializeTenancyByRequestData.php @@ -20,15 +20,6 @@ class InitializeTenancyByRequestData extends IdentificationMiddleware /** @var callable|null */ public static $onFail; - /** @var bool */ - public static $shouldCache = false; - - /** @var int */ - public static $cacheTTL = 3600; // seconds - - /** @var string|null */ - public static $cacheStore = null; // default - /** @var Tenancy */ protected $tenancy; diff --git a/src/Middleware/InitializeTenancyBySubdomain.php b/src/Middleware/InitializeTenancyBySubdomain.php index 765e7209..71cf279a 100644 --- a/src/Middleware/InitializeTenancyBySubdomain.php +++ b/src/Middleware/InitializeTenancyBySubdomain.php @@ -26,15 +26,6 @@ class InitializeTenancyBySubdomain extends InitializeTenancyByDomain /** @var callable|null */ public static $onFail; - /** @var bool */ - public static $shouldCache = false; - - /** @var int */ - public static $cacheTTL = 3600; // seconds - - /** @var string|null */ - public static $cacheStore = null; // default - /** * Handle an incoming request. * diff --git a/src/Resolvers/CachedTenantResolver.php b/src/Resolvers/CachedTenantResolver.php deleted file mode 100644 index c4604f48..00000000 --- a/src/Resolvers/CachedTenantResolver.php +++ /dev/null @@ -1,43 +0,0 @@ -cache = $cache; - } - - public function resolve(...$args): Tenant - { - $resolverClass = $args[0]; - $data = $args[1]; - $ttl = $args[2] ?? null; - $cacheStore = $args[3] ?? null; - - /** @var TenantResolver $resolver */ - $resolver = app($resolverClass); - $encodedData = json_encode($data); - - $cache = $this->cache->store($cacheStore); - - if ($cache->has($key = "_tenancy_resolver:$resolverClass:$encodedData")) { - return $cache->get($key); - } - - $resolved = $resolver->resolve(...$data); - $cache->put($key, $resolved, $ttl); - - return $resolved; - } -} diff --git a/src/Resolvers/Contracts/CachedTenantResolver.php b/src/Resolvers/Contracts/CachedTenantResolver.php new file mode 100644 index 00000000..ddd5fde6 --- /dev/null +++ b/src/Resolvers/Contracts/CachedTenantResolver.php @@ -0,0 +1,70 @@ +cache = $cache->store(static::$cacheStore); + } + + public function resolve(...$args): Tenant + { + if (! static::$shouldCache) { + return $this->resolveWithoutCache(...$args); + } + + $key = $this->getCacheKey(...$args); + + if ($this->cache->has($key)) { + return $this->cache->get($key); + } + + $tenant = $this->resolveWithoutCache(...$args); + $this->cache->put($key, $tenant, static::$cacheTTL); + + return $tenant; + } + + public function invalidateCache(Tenant $tenant): void + { + foreach ($this->getArgsForTenant($tenant) as $args) { + $this->cache->forget($this->getCacheKey(...$args)); + } + } + + public function getCacheKey(...$args): string + { + return '_tenancy_resolver:' . static::class . ':' . json_encode($args); + } + + abstract public function resolveWithoutCache(...$args): Tenant; + + /** + * Get all the arg combinations for resolve() that can be used to find this tenant. + * + * @param Tenant $tenant + * @return array[] + */ + abstract public function getArgsForTenant(Tenant $tenant): array; +} diff --git a/src/Resolvers/PathTenantResolver.php b/src/Resolvers/PathTenantResolver.php index d87aeda8..0b79626f 100644 --- a/src/Resolvers/PathTenantResolver.php +++ b/src/Resolvers/PathTenantResolver.php @@ -6,14 +6,22 @@ namespace Stancl\Tenancy\Resolvers; use Illuminate\Routing\Route; use Stancl\Tenancy\Contracts\Tenant; -use Stancl\Tenancy\Contracts\TenantResolver; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException; -class PathTenantResolver implements TenantResolver +class PathTenantResolver extends Contracts\CachedTenantResolver { public static $tenantParameterName = 'tenant'; - public function resolve(...$args): Tenant + /** @var bool */ + public static $shouldCache = false; + + /** @var int */ + public static $cacheTTL = 3600; // seconds + + /** @var string|null */ + public static $cacheStore = null; // default + + public function resolveWithoutCache(...$args): Tenant { /** @var Route $route */ $route = $args[0]; @@ -28,4 +36,11 @@ class PathTenantResolver implements TenantResolver throw new TenantCouldNotBeIdentifiedByPathException($id); } + + public function getArgsForTenant(Tenant $tenant): array + { + return [ + [$tenant->id], + ]; + } } diff --git a/src/Resolvers/RequestDataTenantResolver.php b/src/Resolvers/RequestDataTenantResolver.php index 2bd5785c..d9f2ebac 100644 --- a/src/Resolvers/RequestDataTenantResolver.php +++ b/src/Resolvers/RequestDataTenantResolver.php @@ -5,12 +5,20 @@ declare(strict_types=1); namespace Stancl\Tenancy\Resolvers; use Stancl\Tenancy\Contracts\Tenant; -use Stancl\Tenancy\Contracts\TenantResolver; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByRequestDataException; -class RequestDataTenantResolver implements TenantResolver +class RequestDataTenantResolver extends Contracts\CachedTenantResolver { - public function resolve(...$args): Tenant + /** @var bool */ + public static $shouldCache = false; + + /** @var int */ + public static $cacheTTL = 3600; // seconds + + /** @var string|null */ + public static $cacheStore = null; // default + + public function resolveWithoutCache(...$args): Tenant { $payload = $args[0]; @@ -20,4 +28,11 @@ class RequestDataTenantResolver implements TenantResolver throw new TenantCouldNotBeIdentifiedByRequestDataException($payload); } + + public function getArgsForTenant(Tenant $tenant): array + { + return [ + [$tenant->id], + ]; + } }