Kategorien, Jahresarchive, Meldungen und Newsrooms liefen auch unter pressekonto.com — die Ausgabe-Routen gelten für alle Hosts, und der Portal-Kontext fällt dort auf businessportal24 zurück. Jetzt 301 auf das Portal. Meldung und Newsroom folgen ihrem eigenen Portal, nicht einer festen Vorgabe; bei Doppelveröffentlichung (gleicher Slug auf beiden Portalen) gewinnt die Erstquelle, sonst endete die Weiterleitung auf der Kopie. Kategorie, Archiv und Suche gibt es auf beiden Portalen — dort entscheidet canonical.portal_only_host. Bewusst nicht weitergeleitet wird ein unbekannter Slug (sonst 301 in ein 404) und alles, was kein GET ist (ein 301 auf POST verliert die Anfrage — Newsroom beanspruchen und Share-Zählung laufen weiter). Query-Parameter bleiben erhalten. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
142 lines
4.7 KiB
PHP
142 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Support;
|
|
|
|
use App\Enums\Portal;
|
|
|
|
/**
|
|
* Kanonischer Host statischer Seiten (Roadmap Anhang 2, E10).
|
|
*
|
|
* faq, hilfe, Transparenzseiten und die API-Doku werden auf Hub und beiden
|
|
* Portalen mit identischem Text ausgeliefert. Damit nicht drei Adressen um
|
|
* denselben Text konkurrieren, führt je Seite ein Host; die beiden anderen
|
|
* verweisen per rel=canonical dorthin. Rechtstexte sind bewusst
|
|
* ausgenommen — sie gehören zu ihrer Domain (siehe config/canonical.php).
|
|
*/
|
|
class StaticPageCanonical
|
|
{
|
|
/**
|
|
* Kanonische Adresse der aktuellen Seite oder null, wenn die Seite
|
|
* self-canonical bleibt.
|
|
*/
|
|
public static function urlFor(?string $routeName, string $path): ?string
|
|
{
|
|
$base = self::baseFor($routeName);
|
|
|
|
return $base === null ? null : $base.$path;
|
|
}
|
|
|
|
/**
|
|
* Basis-URL des führenden Hosts einer Route, oder null.
|
|
*/
|
|
public static function baseFor(?string $routeName): ?string
|
|
{
|
|
if ($routeName === null) {
|
|
return null;
|
|
}
|
|
|
|
$domainKey = config('canonical.static_page_host.'.$routeName);
|
|
|
|
if (! is_string($domainKey)) {
|
|
return null;
|
|
}
|
|
|
|
$url = config('domains.domains.'.$domainKey.'.url');
|
|
|
|
return is_string($url) && $url !== '' ? rtrim($url, '/') : null;
|
|
}
|
|
|
|
/**
|
|
* Basis der Selbst-Referenz: die konfigurierte URL des Hosts, unter dem
|
|
* die Seite tatsächlich aufgerufen wurde.
|
|
*
|
|
* Der geteilte `$domainUrl` aus dem ThemeServiceProvider taugt dafür
|
|
* nicht immer — er wird beim Booten aus dem damaligen Host abgeleitet
|
|
* und von `WebPortalContext::fromRequest()` auf ein Portal umgestellt,
|
|
* auf dem Hub also auf businessportal24. Maßgeblich ist der Host der
|
|
* Anfrage — außer bei Portal-Inhalten, die über den Hub aufgerufen
|
|
* wurden ($portalContextApplied).
|
|
*/
|
|
public static function selfBase(?string $domainUrl = null, bool $portalContextApplied = false): string
|
|
{
|
|
$host = request()->getHost();
|
|
|
|
// Portal-Inhalte (Kategorie, Archiv, Meldung, Newsroom) sind auch
|
|
// über den Hub erreichbar und rendern dort das Portal. Ihr Canonical
|
|
// gehört auf das Portal, nicht auf pressekonto.
|
|
if ($portalContextApplied && is_string($domainUrl) && $domainUrl !== '') {
|
|
return rtrim($domainUrl, '/');
|
|
}
|
|
|
|
if (is_string($domainUrl) && $domainUrl !== '' && parse_url($domainUrl, PHP_URL_HOST) === $host) {
|
|
return rtrim($domainUrl, '/');
|
|
}
|
|
|
|
foreach ((array) config('domains.domains', []) as $domain) {
|
|
$url = $domain['url'] ?? null;
|
|
|
|
if (is_string($url) && parse_url($url, PHP_URL_HOST) === $host) {
|
|
return rtrim($url, '/');
|
|
}
|
|
}
|
|
|
|
return rtrim(request()->getSchemeAndHttpHost(), '/');
|
|
}
|
|
|
|
/**
|
|
* Adresse für einen Link auf eine benannte Seite: normalerweise die des
|
|
* aufgerufenen Hosts — bei Portalseiten auf dem Hub direkt die des
|
|
* führenden Portals, damit der Besucher nicht über eine Weiterleitung
|
|
* läuft.
|
|
*/
|
|
public static function publicUrlFor(string $routeName): string
|
|
{
|
|
$url = route($routeName);
|
|
$portalBase = self::portalOnlyRedirect($routeName);
|
|
|
|
if ($portalBase !== null && str_contains(request()->getHost(), 'pressekonto')) {
|
|
return $portalBase.(string) parse_url($url, PHP_URL_PATH);
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Seiten, die es nur auf den Portalen gibt — auf dem Hub führen sie auf
|
|
* das führende Portal statt auf eine Fassung mit fremdem Branding.
|
|
*/
|
|
public static function portalOnlyRedirect(?string $routeName): ?string
|
|
{
|
|
if ($routeName === null || ! in_array($routeName, (array) config('canonical.portal_only_pages', []), true)) {
|
|
return null;
|
|
}
|
|
|
|
return self::defaultPortalBase();
|
|
}
|
|
|
|
/**
|
|
* Basis-URL des Standard-Portals (config canonical.portal_only_host).
|
|
*/
|
|
public static function defaultPortalBase(): ?string
|
|
{
|
|
$url = config('domains.domains.'.config('canonical.portal_only_host', 'presseecho').'.url');
|
|
|
|
return is_string($url) && $url !== '' ? rtrim($url, '/') : null;
|
|
}
|
|
|
|
/**
|
|
* Basis-URL eines Portals aus dem Enum-Wert (`presseecho`,
|
|
* `businessportal24`); `both` und Unbekanntes fallen auf das
|
|
* Standard-Portal zurück.
|
|
*/
|
|
public static function portalBaseFor(?string $portal): ?string
|
|
{
|
|
if ($portal === null || $portal === Portal::Both->value) {
|
|
return self::defaultPortalBase();
|
|
}
|
|
|
|
$url = config('domains.domains.'.$portal.'.url');
|
|
|
|
return is_string($url) && $url !== '' ? rtrim($url, '/') : self::defaultPortalBase();
|
|
}
|
|
}
|