domainConfig = $domainConfig ?? config('domains'); } /** * Determine the type of subdomain */ public function getSubdomainType(string $subdomain): string { // Frühe Validierung: Prüfe reservierte Subdomains aus Konfiguration $reservedSubdomains = $this->domainConfig['reserved_subdomains'] ?? self::FIXED_SUBDOMAINS; if (in_array($subdomain, $reservedSubdomains)) { return match($subdomain) { 'my' => 'crm', 'in' => 'portal', 'checkout' => 'checkout', default => 'unknown' // Andere reservierte Subdomains sind ungültig }; } // Frühe Validierung: Prüfe auf ungültige Zeichen für UserShop-Slugs if (!preg_match('/^[a-z0-9-]+$/', $subdomain) || strlen($subdomain) < 3) { return 'unknown'; } // Check if it's a valid user shop if ($this->isValidUserShop($subdomain)) { return 'user-shop'; } return 'unknown'; } /** * Check if a subdomain represents a valid user shop */ public function isValidUserShop(string $slug): bool { $cacheKey = "user_shop_valid_{$slug}"; return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($slug) { // Optimierte Query mit allen Validierungen in einem DB-Call $userShop = UserShop::where('slug', $slug) ->where('active', true) ->whereHas('user', function ($query) { $query->whereNotNull('payment_shop') ->where('payment_shop', '>', now()); }) ->exists(); return $userShop; }); } /** * Get user shop by slug with caching */ public function getUserShop(string $slug): ?UserShop { $cacheKey = "user_shop_{$slug}"; return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($slug) { // Optimierte Query mit allen Validierungen in einem DB-Call return UserShop::where('slug', $slug) ->where('active', true) ->whereHas('user', function ($query) { $query->whereNotNull('payment_shop') ->where('payment_shop', '>', now()); }) ->with('user') ->first(); }); } /** * Parse domain from request and determine context */ public function parseDomain(string $host): array { // Normalisiere den Host (lowercase) $host = strtolower(trim($host)); $parts = explode('.', $host); // Handle different TLD scenarios if (count($parts) < 2) { \Log::warning('Invalid host format', ['host' => $host]); return [ 'type' => 'invalid', 'domain' => $host, 'subdomain' => null, 'tld' => null, 'host' => $host ]; } // Extract TLD and domain $tld = '.' . end($parts); $domain = $parts[count($parts) - 2]; // Check for subdomain $subdomain = null; if (count($parts) > 2) { $subdomain = $parts[0]; if (config('app.debug')) { \Log::debug('DomainService: Using extracted subdomain', ['subdomain' => $subdomain, 'host' => $host]); } } // Determine domain type based on subdomain and host $type = $this->determineDomainType($host, $subdomain); return [ 'type' => $type, 'domain' => $domain, 'subdomain' => $subdomain, 'tld' => $tld, 'host' => $host, 'default_user_shop' => $this->domainConfig['domains']['shop']['default_user_shop'] ?? null ]; } /** * Determine domain type based on full host and subdomain */ private function determineDomainType(string $host, ?string $subdomain): string { // Check against configured domains foreach ($this->domainConfig['domains'] as $type => $config) { if (isset($config['host'])) { // Handle wildcard user-shop pattern if ($type === 'user-shop') { $pattern = str_replace('{subdomain}', '([a-z0-9-]+)', $config['host']); if (preg_match("/^{$pattern}$/", $host)) { return 'user-shop'; } } else { // Exact match for other domains if ($host === $config['host']) { return $type; } } } } // Additional check for subdomain-based detection if ($subdomain) { $subdomainType = $this->getSubdomainType($subdomain); if ($subdomainType !== 'unknown') { return $subdomainType; } } return 'unknown'; } /** * Build URL for specific domain type */ public function buildUrl(string $type, ?string $path = null, ?string $slug = null): string { $protocol = $this->domainConfig['protocol'] ?? 'https://'; $domainConfig = $this->domainConfig['domains'][$type] ?? null; if (!$domainConfig) { throw new \InvalidArgumentException("Unknown domain type: {$type}"); } $host = $domainConfig['host']; // Handle user-shop wildcard if ($type === 'user-shop') { if (!$slug) { throw new \InvalidArgumentException('Slug required for user-shop URLs'); } $host = str_replace('{subdomain}', $slug, $host); } $url = $protocol . $host; if ($path) { $url .= '/' . ltrim($path, '/'); } return $url; } /** * Get domain configuration */ public function getDomainConfiguration(): array { return $this->domainConfig; } /** * Clear user shop cache */ public function clearUserShopCache(string $slug): void { Cache::forget("user_shop_valid_{$slug}"); Cache::forget("user_shop_{$slug}"); } /** * Clear all user shop caches */ public function clearAllUserShopCaches(): void { // In Laravel mit Cache-Tags würde das eleganter funktionieren // Für jetzt eine einfache Lösung für häufig verwendete Shops $commonSlugs = ['aloevera']; // Füge häufig verwendete Slugs hinzu foreach ($commonSlugs as $slug) { $this->clearUserShopCache($slug); } } /** * Get default user shop for main domain (fallback) */ public function getDefaultUserShop(): ?UserShop { $defaultSlug = $this->domainConfig['domains']['shop']['default_user_shop'] ?? 'aloevera'; return $this->getUserShop($defaultSlug); } /** * Validate domain configuration */ public function validateConfiguration(): array { $errors = []; // Validate main domains $requiredDomains = ['main', 'shop', 'crm', 'portal', 'checkout', 'user-shop']; foreach ($requiredDomains as $domain) { if (empty($this->domainConfig['domains'][$domain]['host'])) { $errors[] = "Domain '{$domain}' not configured"; } } // Validate protocol if (empty($this->domainConfig['protocol'])) { $errors[] = 'Protocol not configured'; } // Validate reserved subdomains if (empty($this->domainConfig['reserved_subdomains'])) { $errors[] = 'Reserved subdomains not configured'; } // Validate shop default $defaultShop = $this->domainConfig['domains']['shop']['default_user_shop'] ?? null; if (!$defaultShop) { $errors[] = 'Default user shop not configured for shop domain'; } return $errors; } /** * Check if domain configuration is valid */ public function isConfigurationValid(): bool { return empty($this->validateConfiguration()); } }