$summaryCounts * @return array */ public static function normalize(array $summaryCounts): array { $allowedKeys = array_flip(OperationSummaryKeys::all()); $sanitized = []; foreach ($summaryCounts as $key => $value) { $key = trim((string) $key); if ($key === '' || ! isset($allowedKeys[$key])) { continue; } if (is_int($value)) { $sanitized[$key] = $value; continue; } if (is_float($value) && is_finite($value)) { $sanitized[$key] = (int) round($value); continue; } if (is_numeric($value)) { $sanitized[$key] = (int) $value; } } $ordered = []; foreach (OperationSummaryKeys::all() as $key) { if (array_key_exists($key, $sanitized)) { $ordered[$key] = $sanitized[$key]; } } return $ordered; } /** * @param array $summaryCounts */ public static function renderSummaryLine(array $summaryCounts): ?string { $normalized = self::normalize($summaryCounts); if ($normalized === []) { return null; } $parts = []; foreach ($normalized as $key => $value) { if ($value === 0) { continue; } $parts[] = self::label($key).': '.$value; } if ($parts === []) { return null; } return implode(' ยท ', $parts); } /** * Convert a snake_case summary key to a human-readable label. */ public static function label(string $key): string { return match ($key) { 'total' => 'Total', 'processed' => 'Processed', 'succeeded' => 'Completed successfully', 'failed' => 'Failed items', 'skipped' => 'Skipped items', 'items' => 'Affected items', 'tenants' => 'Tenants', 'created' => 'Created', 'updated' => 'Updated', 'deleted' => 'Deleted', 'finding_count' => 'Findings', 'report_count' => 'Reports', 'operation_count' => 'Operations', default => ucfirst(str_replace('_', ' ', $key)), }; } }