update 20.10.2025
This commit is contained in:
parent
8c11130b5d
commit
a939cd51ef
616 changed files with 84821 additions and 4121 deletions
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Domain;
|
||||
|
||||
use App\Models\UserShop;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* DomainContext ist ein unveränderliches Datenobjekt, das den Kontext
|
||||
* der aktuellen Domain für eine einzelne Anfrage enthält.
|
||||
*
|
||||
* Es wird vom DomainServiceProvider erstellt und im Service-Container
|
||||
* registriert, damit andere Teile der Anwendung darauf zugreifen können.
|
||||
*/
|
||||
final class DomainContext
|
||||
{
|
||||
/**
|
||||
* @param string $type Der Typ der Domain (z.B. 'main', 'crm', 'user-shop').
|
||||
* @param string $host Der vollständige Hostname (z.B. 'my.mivita.care').
|
||||
* @param string|null $subdomain Die extrahierte Subdomain (z.B. 'my').
|
||||
* @param UserShop|null $userShop Das zugehörige UserShop-Objekt, falls vorhanden.
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $type,
|
||||
public readonly string $host,
|
||||
public readonly ?string $subdomain,
|
||||
public readonly ?UserShop $userShop
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt eine neue Instanz aus einem Array von Domain-Informationen.
|
||||
*/
|
||||
public static function fromArray(array $domainInfo, ?UserShop $userShop = null): self
|
||||
{
|
||||
return new self(
|
||||
Arr::get($domainInfo, 'type', 'unknown'),
|
||||
Arr::get($domainInfo, 'host', ''),
|
||||
Arr::get($domainInfo, 'subdomain'),
|
||||
$userShop
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob es sich um eine bekannte Domain handelt.
|
||||
*/
|
||||
public function isUnknown(): bool
|
||||
{
|
||||
return $this->type === 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob es sich um eine User-Shop-Domain handelt.
|
||||
*/
|
||||
public function isUserShop(): bool
|
||||
{
|
||||
return $this->type === 'user-shop';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Slug des User-Shops zurück.
|
||||
*/
|
||||
public function getUserShopSlug(): ?string
|
||||
{
|
||||
return $this->userShop?->slug;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
277
app/Domain/EarlyDomainParser.php
Normal file
277
app/Domain/EarlyDomainParser.php
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
<?php
|
||||
|
||||
namespace App\Domain;
|
||||
|
||||
/**
|
||||
* Early Domain Parser Service
|
||||
*
|
||||
* Provides domain parsing functionality that can be used during
|
||||
* bootstrap phase (RouteServiceProvider) and runtime (Middleware).
|
||||
*
|
||||
* This service caches parsing results per request to avoid duplicate work.
|
||||
*/
|
||||
class EarlyDomainParser
|
||||
{
|
||||
/**
|
||||
* Cache for parsed domain information per request
|
||||
* @var array|null
|
||||
*/
|
||||
private static ?array $cachedDomainInfo = null;
|
||||
|
||||
/**
|
||||
* Cache key (host) for cache invalidation
|
||||
* @var string|null
|
||||
*/
|
||||
private static ?string $cachedHost = null;
|
||||
|
||||
/**
|
||||
* Parse domain information from config/domains.php
|
||||
*
|
||||
* Results are cached per request to avoid duplicate parsing.
|
||||
*
|
||||
* @param string|null $host If null, uses HTTP_HOST or SERVER_NAME
|
||||
* @return array Domain information array
|
||||
*/
|
||||
public static function parseDomain(?string $host = null): array
|
||||
{
|
||||
// Get host from request if not provided
|
||||
if ($host === null) {
|
||||
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
|
||||
}
|
||||
|
||||
// Remove protocol if present
|
||||
$host = preg_replace('/^https?:\/\//', '', $host);
|
||||
|
||||
// Return cached result if available for same host
|
||||
if (self::$cachedHost === $host && self::$cachedDomainInfo !== null) {
|
||||
return self::$cachedDomainInfo;
|
||||
}
|
||||
// Load domains configuration
|
||||
$domains = self::getDomainsConfig();
|
||||
$reservedSubdomains = self::getReservedSubdomains();
|
||||
|
||||
// Check exact matches first (main, shop, crm, portal, checkout)
|
||||
foreach ($domains as $key => $domainConfig) {
|
||||
if ($key === 'user-shop') {
|
||||
continue; // Handle user-shop separately
|
||||
}
|
||||
|
||||
if ($host === $domainConfig['host']) {
|
||||
$domainInfo = [
|
||||
'type' => $domainConfig['type'],
|
||||
'host' => $host,
|
||||
'subdomain' => null,
|
||||
'config_key' => $key,
|
||||
];
|
||||
|
||||
// Cache the result for this request
|
||||
self::$cachedHost = $host;
|
||||
self::$cachedDomainInfo = $domainInfo;
|
||||
|
||||
return $domainInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for user-shop pattern (dynamic subdomains)
|
||||
if (isset($domains['user-shop'])) {
|
||||
$userShopPattern = $domains['user-shop']['host'];
|
||||
$baseDomain = str_replace('{subdomain}.', '', $userShopPattern);
|
||||
|
||||
if (str_ends_with($host, '.' . $baseDomain)) {
|
||||
$subdomain = str_replace('.' . $baseDomain, '', $host);
|
||||
|
||||
// Check if subdomain is not reserved
|
||||
if (!empty($subdomain) && !in_array($subdomain, $reservedSubdomains)) {
|
||||
$domainInfo = [
|
||||
'type' => 'user-shop',
|
||||
'host' => $host,
|
||||
'subdomain' => $subdomain,
|
||||
'config_key' => 'user-shop',
|
||||
];
|
||||
|
||||
// Cache the result for this request
|
||||
self::$cachedHost = $host;
|
||||
self::$cachedDomainInfo = $domainInfo;
|
||||
|
||||
return $domainInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown domain
|
||||
$domainInfo = [
|
||||
'type' => 'unknown',
|
||||
'host' => $host,
|
||||
'subdomain' => null,
|
||||
'config_key' => null,
|
||||
];
|
||||
|
||||
// Cache the result for this request
|
||||
self::$cachedHost = $host;
|
||||
self::$cachedDomainInfo = $domainInfo;
|
||||
|
||||
return $domainInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current domain type quickly (for RouteServiceProvider)
|
||||
*/
|
||||
public static function getCurrentDomainType(): string
|
||||
{
|
||||
$domainInfo = self::parseDomain();
|
||||
return $domainInfo['type'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current domain is a user shop
|
||||
*/
|
||||
public static function isUserShop(): bool
|
||||
{
|
||||
return self::getCurrentDomainType() === 'user-shop';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get subdomain for user shops
|
||||
*/
|
||||
public static function getSubdomain(): ?string
|
||||
{
|
||||
$domainInfo = self::parseDomain();
|
||||
return $domainInfo['subdomain'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get domains configuration (early bootstrap safe)
|
||||
*/
|
||||
private static function getDomainsConfig(): array
|
||||
{
|
||||
// Try Laravel config first (if available)
|
||||
if (function_exists('config')) {
|
||||
$config = config('domains.domains');
|
||||
if ($config) {
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Read config file directly
|
||||
$configPath = __DIR__ . '/../../../../config/domains.php';
|
||||
if (file_exists($configPath)) {
|
||||
$config = include $configPath;
|
||||
return $config['domains'] ?? [];
|
||||
}
|
||||
|
||||
// Last resort: Build from environment variables
|
||||
return self::buildConfigFromEnv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reserved subdomains configuration
|
||||
*/
|
||||
private static function getReservedSubdomains(): array
|
||||
{
|
||||
// Try Laravel config first (if available)
|
||||
if (function_exists('config')) {
|
||||
$reserved = config('domains.reserved_subdomains');
|
||||
if ($reserved) {
|
||||
return $reserved;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Read config file directly
|
||||
$configPath = __DIR__ . '/../../../../config/domains.php';
|
||||
if (file_exists($configPath)) {
|
||||
$config = include $configPath;
|
||||
return $config['reserved_subdomains'] ?? [];
|
||||
}
|
||||
|
||||
// Default reserved subdomains
|
||||
return ['my', 'in', 'checkout', 'www', 'api', 'mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build basic domain configuration from environment variables
|
||||
* Used as fallback when config file is not available
|
||||
*/
|
||||
private static function buildConfigFromEnv(): array
|
||||
{
|
||||
$domain = $_ENV['APP_DOMAIN'] ?? 'mivita';
|
||||
$tldCare = $_ENV['APP_TLD_CARE'] ?? '.care';
|
||||
$tldShop = $_ENV['APP_TLD_SHOP'] ?? '.shop';
|
||||
$crmPrefix = $_ENV['APP_PRE_URL_CRM'] ?? 'my.';
|
||||
$portalPrefix = $_ENV['APP_PRE_URL_PORTAL'] ?? 'in.';
|
||||
$checkoutPrefix = $_ENV['APP_URL_CHECKOUT'] ?? 'checkout.';
|
||||
|
||||
return [
|
||||
'main' => [
|
||||
'host' => $domain . $tldCare,
|
||||
'type' => 'main',
|
||||
],
|
||||
'shop' => [
|
||||
'host' => $domain . $tldShop,
|
||||
'type' => 'main-shop',
|
||||
'default_user_shop' => 'aloevera',
|
||||
],
|
||||
'crm' => [
|
||||
'host' => $crmPrefix . $domain . $tldCare,
|
||||
'type' => 'crm',
|
||||
],
|
||||
'portal' => [
|
||||
'host' => $portalPrefix . $domain . $tldCare,
|
||||
'type' => 'portal',
|
||||
],
|
||||
'checkout' => [
|
||||
'host' => $checkoutPrefix . $domain . $tldCare,
|
||||
'type' => 'checkout',
|
||||
],
|
||||
'user-shop' => [
|
||||
'host' => '{subdomain}.' . $domain . $tldCare,
|
||||
'type' => 'user-shop',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get protocol from configuration
|
||||
*/
|
||||
public static function getProtocol(): string
|
||||
{
|
||||
if (function_exists('config')) {
|
||||
return config('domains.protocol', 'https://');
|
||||
}
|
||||
|
||||
return $_ENV['APP_PROTOCOL'] ?? 'https://';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get main domain URL for redirects
|
||||
*/
|
||||
public static function getMainUrl(): string
|
||||
{
|
||||
$domains = self::getDomainsConfig();
|
||||
$mainHost = $domains['main']['host'] ?? 'localhost';
|
||||
$protocol = self::getProtocol();
|
||||
|
||||
return $protocol . $mainHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the internal cache (useful for testing or special cases)
|
||||
*/
|
||||
public static function clearCache(): void
|
||||
{
|
||||
self::$cachedDomainInfo = null;
|
||||
self::$cachedHost = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if result is cached for current/given host
|
||||
*/
|
||||
public static function isCached(?string $host = null): bool
|
||||
{
|
||||
if ($host === null) {
|
||||
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
|
||||
$host = preg_replace('/^https?:\/\//', '', $host);
|
||||
}
|
||||
|
||||
return self::$cachedHost === $host && self::$cachedDomainInfo !== null;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue