presseportale/app/Providers/ThemeServiceProvider.php
Kevin Adametz c7bd940f28 Optimierung Phase 0: Korrektheit & Security
Konsolidierter Entwicklungsplan aus den zwei Analyse-Dokumenten plus
Umsetzung der Phase-0-Massnahmen (Korrektheit/Security, je mit Tests):

0.1 BasicAuth: timing-sicherer Vergleich (hash_equals, beide Felder ohne
    Short-Circuit); Enabled-Check zur Laufzeit via config('auth.basic.*')
    statt env() im Bootstrap-Closure (greift jetzt unter config:cache);
    Config-Block + .env.example. Fund: auth.basic.* war nie als Config
    definiert, Gate war faktisch unkonfigurierbar.
0.2 Legacy-Invoice-"latest"-Abfrage zentralisiert (LegacyInvoice::
    scopeLatestFirst + User::latestLegacyInvoice); beide Consumer N+1-frei
    umgestellt; unterschiedliches null-Verhalten bewusst erhalten.
0.3 Payment-Option-Eligibility vereinheitlicht (period-aware, strikt):
    UserPaymentOption::scopeActiveNow/grandfatheredNow + User::
    hasActivePaymentOption; hasActiveBooking/hasUnlimitedPressReleaseQuota
    und ApiAccessEligibilityService darauf umgestellt; $hasGrandfathered-
    Mislabel behoben.
0.4 Theme->Portal-Vokabular: totes, projektfremdes ThemeMiddleware
    geloescht; Mapping in Portal::fromTheme() zentralisiert; fremden
    b2in-Default im ThemeServiceProvider auf Portal-Default korrigiert.
0.5 InvoiceNumberGenerator: Erst-Insert race-sicher via insertOrIgnore
    (Unique-Index auf circle existiert bereits). CreditWalletService war
    bereits abgesichert (Unique-Index + createOrFirst).

Tests: 4 neue Dateien, 5 bestehende auf gueltiges grandfathered_until
angepasst. Volle Suite gruen (793 passed, 1 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:09:02 +00:00

90 lines
2.9 KiB
PHP

<?php
namespace App\Providers;
use App\Support\DomainAssetContext;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;
class ThemeServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
$this->mergeConfigFrom(
base_path('config/domains.php'),
'domains'
);
}
/**
* Bootstrap services.
*/
public function boot(): void
{
$host = Request::getHost();
$themeOverride = Request::get('theme');
// Fallback für unbekannte Hosts: Portal-/Admin-Theme dieses Projekts.
$defaults = [
'name' => config('app.name'),
'theme' => 'portal',
'view_prefix' => 'portal',
'assets_dir' => 'build/portal',
'url' => config('app.url'),
'domain_name' => config('app.domain_name'),
];
$domainConfig = DomainAssetContext::resolve(
$host,
$defaults,
config('domains.domains', []),
is_string($themeOverride) ? $themeOverride : null,
);
$staticAssetOrigin = DomainAssetContext::staticAssetOrigin($domainConfig);
$viteDevServerUrl = DomainAssetContext::viteDevServerUrl($domainConfig);
config([
'app.theme' => $domainConfig['theme'],
'app.view_prefix' => $domainConfig['view_prefix'],
'app.domain_name' => $domainConfig['domain_name'],
'app.url' => $domainConfig['url'],
'app.asset_url' => $staticAssetOrigin,
]);
URL::forceRootUrl($domainConfig['url']);
URL::forceScheme(parse_url($domainConfig['url'], PHP_URL_SCHEME) ?: 'https');
/** @var UrlGenerator $urlGenerator */
$urlGenerator = app('url');
$urlGenerator->useAssetOrigin($staticAssetOrigin);
View::share('theme', $domainConfig['theme']);
View::share('viewPrefix', $domainConfig['view_prefix']);
View::share('domainName', $domainConfig['domain_name']);
View::share('domainConfig', $domainConfig);
View::share('domainUrl', $domainConfig['url']);
View::share('assetUrl', $staticAssetOrigin);
View::share('viteDevServerUrl', $viteDevServerUrl);
if (! app()->runningInConsole()) {
if (isset($domainConfig['assets_dir'])) {
DomainAssetContext::configureVite($domainConfig);
}
if (app()->environment('local')) {
config(['app.vite_dev_server_url' => $viteDevServerUrl]);
} else {
Vite::useScriptTagAttributes(['crossorigin' => false]);
Vite::useStyleTagAttributes(['crossorigin' => false]);
}
}
}
}