update 20.10.2025
This commit is contained in:
parent
8c11130b5d
commit
a939cd51ef
616 changed files with 84821 additions and 4121 deletions
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dev\SubdomainOptimizationGpt5\Http\Middleware;
|
||||
|
||||
use App\Domain\DomainContext;
|
||||
use App\Services\DomainService;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
/**
|
||||
* Früh gestartete Middleware zur DOMÄNEN-Auflösung OHNE Sessionzugriff.
|
||||
* - Parst den Host und erzeugt einen DomainContext
|
||||
* - Setzt dynamische Konfiguration (session.domain, app.url)
|
||||
* - Registriert DomainContext im Container und als Request-Attribut
|
||||
*/
|
||||
class DomainBootstrap
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// Nur für relevante HTTP-Requests (keine Assets/API) – minimalistischer Filter
|
||||
if ($this->shouldSkip($request)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/** @var DomainService $domainService */
|
||||
$domainService = app(DomainService::class);
|
||||
$domainInfo = $domainService->parseDomain($request->getHost());
|
||||
|
||||
$userShop = null;
|
||||
if (($domainInfo['type'] ?? 'unknown') === 'user-shop' && !empty($domainInfo['subdomain'])) {
|
||||
// KEIN Sessionzugriff – lediglich Context vorbereiten
|
||||
$userShop = $domainService->getUserShop($domainInfo['subdomain']);
|
||||
if (!$userShop) {
|
||||
// Ungültig → unknown, keine Session anlegen
|
||||
$domainInfo['type'] = 'unknown';
|
||||
}
|
||||
} elseif (($domainInfo['type'] ?? null) === 'main-shop' && !empty($domainInfo['default_user_shop'])) {
|
||||
$userShop = $domainService->getUserShop($domainInfo['default_user_shop']);
|
||||
}
|
||||
|
||||
$context = DomainContext::fromArray($domainInfo, $userShop);
|
||||
|
||||
// Früh: session.domain + app.url setzen (wir greifen noch nicht auf Session zu)
|
||||
$this->configureRuntime($context);
|
||||
|
||||
// Context bereitstellen
|
||||
app()->instance(DomainContext::class, $context);
|
||||
$request->attributes->set('domain.context', $context);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
private function shouldSkip(Request $request): bool
|
||||
{
|
||||
if ($request->is('api/*')) {
|
||||
return true;
|
||||
}
|
||||
if ($request->isMethod('GET') && preg_match('/\.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$/i', $request->path())) {
|
||||
return true;
|
||||
}
|
||||
if ($request->isMethod('GET') && in_array($request->path(), ['_debugbar/*'])) {
|
||||
return true;
|
||||
}
|
||||
if ($request->isMethod('GET') && in_array($request->path(), ['health', 'status', 'ping'])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function configureRuntime(DomainContext $context): void
|
||||
{
|
||||
// session.domain abhängig vom Kontext setzen
|
||||
if ($context->type === 'shop' || $context->type === 'user-shop' || $context->type === 'main-shop') {
|
||||
Config::set('session.domain', '.' . config('app.domain') . config('app.tld_shop'));
|
||||
} else {
|
||||
Config::set('session.domain', '.' . config('app.domain') . config('app.tld_care'));
|
||||
}
|
||||
|
||||
// app.url für URL-Generierung
|
||||
if (!empty($context->host)) {
|
||||
Config::set('app.url', $context->host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dev\SubdomainOptimizationGpt5\Http\Middleware;
|
||||
|
||||
use App\Dev\SubdomainOptimizationGpt5\Services\UserShopSessionManager;
|
||||
use App\Domain\DomainContext;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Spät gestartete Middleware (NACH StartSession).
|
||||
* - Synchronisiert `user_shop` zwischen Cookie und Session
|
||||
* - Setzt optional Legacy-Session-Keys für Abwärtskompatibilität
|
||||
*/
|
||||
class DomainSessionSync
|
||||
{
|
||||
public function __construct(private readonly UserShopSessionManager $manager) {}
|
||||
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
/** @var DomainContext|null $context */
|
||||
$context = app(DomainContext::class);
|
||||
|
||||
// Session ist aktiv – konsolidieren
|
||||
$this->manager->synchronize($request, $context);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dev\SubdomainOptimizationGpt5\Services;
|
||||
|
||||
use App\Domain\DomainContext;
|
||||
use App\Models\UserShop;
|
||||
use App\Services\DomainService;
|
||||
use Illuminate\Contracts\Cookie\Factory as CookieFactory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
class UserShopSessionManager
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DomainService $domainService,
|
||||
private readonly CookieFactory $cookies
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Synchronisiert UserShop zwischen Cookie und Session. Setzt optional Legacy-Keys.
|
||||
*/
|
||||
public function synchronize(Request $request, ?DomainContext $context): void
|
||||
{
|
||||
$config = Config::get('subdomain_optimization', []);
|
||||
$cookieName = $config['cookie']['name'] ?? 'mvt_shop';
|
||||
$legacy = (bool)($config['legacy']['enable_legacy_session_keys'] ?? true);
|
||||
$cookieTtl = (int)($config['cookie']['ttl_minutes'] ?? 60 * 24 * 30);
|
||||
|
||||
// 1) Quelle bestimmen: DomainContext (falls user-shop) → Cookie → Session
|
||||
$slugFromContext = ($context && $context->userShop) ? $context->userShop->slug : null;
|
||||
$slugFromCookie = $request->cookie($cookieName);
|
||||
$slugFromSession = Session::get('ctx.user_shop.slug');
|
||||
|
||||
$effectiveSlug = $slugFromContext ?: ($slugFromCookie ?: $slugFromSession);
|
||||
|
||||
if (!$effectiveSlug) {
|
||||
// Fallback: main-shop mit default_user_shop
|
||||
if ($context && $context->type === 'main-shop') {
|
||||
$default = $this->domainService->getDefaultUserShop();
|
||||
$effectiveSlug = $default?->slug;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$effectiveSlug) {
|
||||
return; // Nichts zu synchronisieren
|
||||
}
|
||||
|
||||
$shop = $this->domainService->getUserShop($effectiveSlug);
|
||||
if (!$shop) {
|
||||
return; // Ungültig → keine Seiteneffekte
|
||||
}
|
||||
|
||||
// 2) Session updaten (kompakter Namespace)
|
||||
Session::put('ctx.user_shop', [
|
||||
'id' => $shop->id,
|
||||
'slug' => $shop->slug,
|
||||
'host' => $this->domainService->buildUrl('user-shop', null, $shop->slug),
|
||||
]);
|
||||
|
||||
// 3) Legacy-Keys optional bedienen
|
||||
if ($legacy) {
|
||||
Session::put('user_shop', $shop);
|
||||
Session::put('user_shop_domain', parse_url($this->domainService->buildUrl('user-shop', null, $shop->slug), PHP_URL_HOST));
|
||||
}
|
||||
|
||||
Session::save();
|
||||
|
||||
// 4) Cookie aktualisieren (sticky über Subdomains)
|
||||
$domainForCookie = config('session.domain');
|
||||
cookie()->queue(
|
||||
cookie(
|
||||
$cookieName,
|
||||
$shop->slug,
|
||||
$cookieTtl,
|
||||
path: '/',
|
||||
domain: $domainForCookie,
|
||||
secure: config('session.secure', false),
|
||||
httpOnly: true,
|
||||
sameSite: config('session.same_site', 'lax')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue