cache = $cache->store(static::cacheStore()); } public function resolve(mixed ...$args): Tenant { if (! static::shouldCache()) { return $this->resolveWithoutCache(...$args); } $key = $this->getCacheKey(...$args); if ($tenant = $this->cache->get($key)) { $this->resolved($tenant, ...$args); return $tenant; } $tenant = $this->resolveWithoutCache(...$args); $this->cache->put($key, $tenant, static::cacheTTL()); return $tenant; } public function invalidateCache(Tenant $tenant): void { if (! static::shouldCache()) { return; } foreach ($this->getArgsForTenant($tenant) as $args) { $this->cache->forget($this->getCacheKey(...$args)); } } public function getCacheKey(mixed ...$args): string { return '_tenancy_resolver:' . static::class . ':' . json_encode($args); } abstract public function resolveWithoutCache(mixed ...$args): Tenant; public function resolved(Tenant $tenant, mixed ...$args): void { } /** * Get all the arg combinations for resolve() that can be used to find this tenant. * * @return array[] */ abstract public function getArgsForTenant(Tenant $tenant): array; // todo@v4 make it clear that this is only used for cache *invalidation* public static function shouldCache(): bool { return config('tenancy.identification.resolvers.' . static::class . '.cache') ?? false; } public static function cacheTTL(): int { return config('tenancy.identification.resolvers.' . static::class . '.cache_ttl') ?? 3600; } public static function cacheStore(): string|null { return config('tenancy.identification.resolvers.' . static::class . '.cache_store'); } }