mivita/dev/subdomain-optimization/DomainService.php
2025-08-12 18:01:59 +02:00

272 lines
No EOL
7.7 KiB
PHP

<?php
namespace App\Services;
use App\Models\UserShop;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
/**
* Domain Service - Centralized domain and subdomain management
*
* This service provides a centralized way to handle domain resolution,
* subdomain validation, and domain-specific configuration management.
*/
class DomainService
{
private const CACHE_TTL = 3600; // 1 hour
private const FIXED_SUBDOMAINS = ['my', 'in', 'checkout'];
private array $domainConfig;
public function __construct()
{
$this->domainConfig = $this->loadDomainConfiguration();
}
/**
* Load domain configuration from config files
*/
private function loadDomainConfiguration(): array
{
return [
'main_domain' => config('app.domain'),
'main_tld' => config('app.tld_care'),
'shop_tld' => config('app.tld_shop'),
'protocol' => config('app.protocol'),
'subdomains' => [
'crm' => config('app.pre_url_crm', 'my.'),
'portal' => config('app.pre_url_portal', 'in.'),
'checkout' => config('app.pre_url_checkout', 'checkout.'),
]
];
}
/**
* Determine the type of subdomain
*/
public function getSubdomainType(string $subdomain): string
{
// Check if it's a fixed subdomain
if (in_array($subdomain, self::FIXED_SUBDOMAINS)) {
return match($subdomain) {
'my' => 'crm',
'in' => 'portal',
'checkout' => 'checkout',
default => '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) {
$userShop = UserShop::where('slug', $slug)->first();
if (!$userShop) {
return false;
}
if (!$userShop->active) {
return false;
}
if (!$userShop->user) {
return false;
}
if (!$userShop->user->isActiveShop()) {
return false;
}
return true;
});
}
/**
* Get user shop by slug with caching
*/
public function getUserShop(string $slug): ?UserShop
{
if (!$this->isValidUserShop($slug)) {
return null;
}
$cacheKey = "user_shop_{$slug}";
return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($slug) {
return UserShop::where('slug', $slug)
->with('user')
->first();
});
}
/**
* Parse domain from request and determine context
*/
public function parseDomain(string $host): array
{
$parts = explode('.', $host);
// Handle different TLD scenarios
if (count($parts) < 2) {
return [
'type' => 'invalid',
'domain' => $host,
'subdomain' => null,
'tld' => null
];
}
// Extract TLD and domain
$tld = '.' . end($parts);
$domain = $parts[count($parts) - 2];
// Check for subdomain
$subdomain = null;
if (count($parts) > 2) {
$subdomain = $parts[0];
}
// Determine domain type
$type = $this->determineDomainType($domain, $subdomain, $tld);
return [
'type' => $type,
'domain' => $domain,
'subdomain' => $subdomain,
'tld' => $tld,
'full_domain' => $host
];
}
/**
* Determine domain type based on domain, subdomain, and TLD
*/
private function determineDomainType(string $domain, ?string $subdomain, string $tld): string
{
// Check if it's the main domain
if ($domain === $this->domainConfig['main_domain']) {
if ($subdomain === null) {
// Main domain without subdomain
if ($tld === $this->domainConfig['shop_tld']) {
return 'main-shop'; // mivita.shop
}
return 'main'; // mivita.care
}
// Main domain with subdomain
return $this->getSubdomainType($subdomain);
}
return 'unknown';
}
/**
* Build URL for specific domain type
*/
public function buildUrl(string $type, ?string $path = null, ?string $slug = null): string
{
$base = $this->domainConfig['protocol'];
switch ($type) {
case 'main':
$base .= $this->domainConfig['main_domain'] . $this->domainConfig['main_tld'];
break;
case 'main-shop':
$base .= $this->domainConfig['main_domain'] . $this->domainConfig['shop_tld'];
break;
case 'crm':
$base .= rtrim($this->domainConfig['subdomains']['crm'], '.') .
$this->domainConfig['main_domain'] . $this->domainConfig['main_tld'];
break;
case 'portal':
$base .= rtrim($this->domainConfig['subdomains']['portal'], '.') .
$this->domainConfig['main_domain'] . $this->domainConfig['main_tld'];
break;
case 'checkout':
$base .= rtrim($this->domainConfig['subdomains']['checkout'], '.') .
$this->domainConfig['main_domain'] . $this->domainConfig['main_tld'];
break;
case 'user-shop':
if (!$slug) {
throw new \InvalidArgumentException('Slug required for user-shop URLs');
}
$base .= $slug . '.' . $this->domainConfig['main_domain'] . $this->domainConfig['main_tld'];
break;
default:
throw new \InvalidArgumentException("Unknown domain type: {$type}");
}
if ($path) {
$base .= '/' . ltrim($path, '/');
}
return $base;
}
/**
* 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}");
}
/**
* Get default user shop for main domain (fallback)
*/
public function getDefaultUserShop(): ?UserShop
{
return $this->getUserShop('aloevera'); // Current hardcoded fallback
}
/**
* Validate domain configuration
*/
public function validateConfiguration(): array
{
$errors = [];
if (empty($this->domainConfig['main_domain'])) {
$errors[] = 'Main domain not configured';
}
if (empty($this->domainConfig['main_tld'])) {
$errors[] = 'Main TLD not configured';
}
if (empty($this->domainConfig['protocol'])) {
$errors[] = 'Protocol not configured';
}
return $errors;
}
}