$triggers */ public function __construct( public ImagePrecheckOutcome $outcome, public array $triggers, public int $stage, ) {} /** * @return array */ public function triggersFor(ImagePrecheckOutcome $outcome): array { return array_values(array_filter($this->triggers, fn (array $t): bool => $t['outcome'] === $outcome)); } /** Grund in einem Satz bei automatischer Ablehnung. */ public function rejectionMessage(): ?string { $first = $this->triggersFor(ImagePrecheckOutcome::Reject)[0] ?? null; return $first !== null ? $first['category']->rejectionMessage() : null; } /** * Hinweise fürs Formular, in der Reihenfolge der Kategorien. * * @return array */ public function hints(): array { return array_map( fn (array $t): string => $t['category']->hintMessage($t['note']), $this->triggersFor(ImagePrecheckOutcome::Hint), ); } /** Kurzfassung fürs Audit: "stock_watermark 0.92, persons_visible 0.80". */ public function summary(): string { if ($this->triggers === []) { return $this->outcome === ImagePrecheckOutcome::Error ? 'nicht geprüft' : 'ohne Befund'; } return implode(', ', array_map( fn (array $t): string => sprintf('%s %.2f → %s', $t['category']->value, $t['confidence'], $t['outcome']->value), $this->triggers, )); } /** * @return array{outcome: string, stage: int, triggers: array} */ public function toArray(): array { return [ 'outcome' => $this->outcome->value, 'stage' => $this->stage, 'triggers' => array_map(fn (array $t): array => [ 'category' => $t['category']->value, 'confidence' => $t['confidence'], 'outcome' => $t['outcome']->value, 'note' => $t['note'], ], $this->triggers), ]; } }