pressRelease?->company; $companyName = $company?->name; $credit = self::clean($image->copyright) ?? self::clean($image->author); $creditLabel = __('web.detail.photo'); if ($credit === null && $image->isLegacyRules() && filled($companyName)) { $credit = $companyName; $creditLabel = __('web.detail.source'); } $aiLabel = $image->ai_declaration?->publicLabel() ?? ($image->is_ai_generated ? __('KI-generiert') : null); $confirmation = $image->relationLoaded('latestRightsConfirmation') ? $image->latestRightsConfirmation : $image->latestRightsConfirmation()->first(); $responsible = null; if ($confirmation !== null && filled($companyName)) { $responsible = __('web.detail.image_responsible', [ 'company' => $companyName, 'date' => $confirmation->confirmed_at->locale('de')->isoFormat('D. MMMM YYYY'), ]); } return new self( credit: $credit, creditLabel: $creditLabel, aiLabel: $aiLabel, aiSourceLabel: $aiLabel !== null ? $image->ai_declaration_source?->publicLabel() ?? ($image->isLegacyRules() ? null : AiDeclarationSource::Customer->publicLabel()) : null, licenseUrl: self::safeUrl($image->license_url), sourceUrl: self::safeUrl($image->source_url), responsibleLine: $responsible, confirmation: $confirmation, isLegacy: $image->isLegacyRules(), ); } /** * Zeile aus Einzelteilen — für den eingebrannten OG-Balken beim Upload, * bevor es ein Modell gibt (H.1). */ public static function compose(?string $credit, ?string $aiLabel, ?string $label = null): ?string { $credit = self::clean($credit); $parts = []; if ($credit !== null) { $parts[] = ($label ?? __('web.detail.photo')).': '.$credit; } if ($aiLabel !== null && $aiLabel !== '') { $parts[] = $aiLabel; } return $parts === [] ? null : implode(' · ', $parts); } /** * Sichtbare Zeile unter dem Bild, z. B. „Foto: Musterfirma · KI-generiert". */ public function line(): ?string { if ($this->credit === null && $this->aiLabel === null) { return null; } $parts = []; if ($this->credit !== null) { $parts[] = $this->creditLabel.': '.$this->credit; } if ($this->aiLabel !== null) { $parts[] = $this->aiLabel; } return implode(' · ', $parts); } public function hasDetails(): bool { return $this->credit !== null || $this->aiLabel !== null || $this->responsibleLine !== null; } /** * Zeilen für das Beleg-PDF (D.4). * * @return list */ public function pdfLines(): array { $lines = []; if ($this->credit !== null) { $lines[] = 'Bildnachweis: '.$this->credit; } if ($this->licenseUrl !== null) { $lines[] = 'Lizenz: '.$this->licenseUrl; } if ($this->sourceUrl !== null) { $lines[] = 'Quelle: '.$this->sourceUrl; } if ($this->aiLabel !== null) { $lines[] = 'KI-Kennzeichnung: '.$this->aiLabel.($this->aiSourceLabel !== null ? ' ('.$this->aiSourceLabel.')' : ''); } if ($this->confirmation !== null) { $lines[] = sprintf( 'Rechte bestätigt am %s (%s, AGB %s)', $this->confirmation->confirmed_at->format('d.m.Y H:i'), $this->confirmation->legal_text_key, $this->confirmation->agb_version ?? '–', ); } return $lines; } private static function clean(?string $value): ?string { $value = trim((string) $value); return $value !== '' ? $value : null; } private static function safeUrl(?string $url): ?string { $url = trim((string) $url); if ($url === '' || ! Str::startsWith(strtolower($url), ['http://', 'https://'])) { return null; } return filter_var($url, FILTER_VALIDATE_URL) !== false ? $url : null; } }