$raw Rohwerte aus der Option */ public static function fromArray(array $raw): self { $base = self::text($raw['api_base_url'] ?? null); return new self( organization: strtolower(self::text($raw['organization'] ?? null)), token: self::text($raw['token'] ?? null), apiBaseUrl: rtrim($base === '' ? self::DEFAULT_API_BASE_URL : $base, '/'), customerName: self::text($raw['customer_name'] ?? null), heartbeatUrl: self::text($raw['heartbeat_url'] ?? null), securityTxt: (bool) ($raw['security_txt'] ?? false), securityTxtBaseUrl: rtrim(self::text($raw['security_txt_base_url'] ?? null), '/'), // vor 1.4.1 gespeicherte Einstellungen kennen den Schalter nicht: eingeschaltet platformHealth: (bool) ($raw['platform_health'] ?? true), ); } /** * @return array */ public function toArray(): array { return [ 'organization' => $this->organization, 'token' => $this->token, 'api_base_url' => $this->apiBaseUrl, 'customer_name' => $this->customerName, 'heartbeat_url' => $this->heartbeatUrl, 'security_txt' => $this->securityTxt, 'security_txt_base_url' => $this->securityTxtBaseUrl, 'platform_health' => $this->platformHealth, ]; } public function withHeartbeatUrl(string $url): self { return new self($this->organization, $this->token, $this->apiBaseUrl, $this->customerName, $url, $this->securityTxt, $this->securityTxtBaseUrl, $this->platformHealth); } /** Das aus dem Token ermittelte Kürzel merken, damit der nächste Lauf nicht wieder nachfragt. */ public function withOrganization(string $organization): self { return new self($organization, $this->token, $this->apiBaseUrl, $this->customerName, $this->heartbeatUrl, $this->securityTxt, $this->securityTxtBaseUrl, $this->platformHealth); } /** * Derselbe Zugang wie in den anderen Einstellungen? Token und Kürzel entscheiden, zu welcher Organisation die * Website spricht – und damit, ob eine gemerkte Ping-Adresse noch ihr gehört. */ public function sameAccess(self $other): bool { return $this->token === $other->token && $this->organization === $other->organization; } /** Basis, unter der DomainWarn security.txt-Dateien ausliefert; nur dorthin wird weitergeleitet. */ public function securityTxtBase(): ?string { return SiteHosting::securityTxtBase($this->apiBaseUrl, $this->securityTxtBaseUrl); } /** * Ohne Token tut die Erweiterung nichts – das ist kein Fehler, sondern der Auslieferungszustand. Das Kürzel * der Organisation braucht es nicht: Das Token gehört zu genau einer, und die API nennt sie. */ public function complete(): bool { return $this->token !== ''; } private static function text(mixed $value): string { return is_string($value) ? trim($value) : ''; } }