| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- <?php
- declare(strict_types=1);
- namespace App\Mail;
- use App\Form\FormSchema;
- /**
- * Formats raw submission data into human-readable label/value pairs,
- * respecting visibility conditions and field types from the form schema.
- */
- final class SubmissionFormatter
- {
- private FormSchema $schema;
- public function __construct(FormSchema $schema)
- {
- $this->schema = $schema;
- }
- /**
- * @param array<string, mixed> $submission
- * @return array<int, array{title: string, fields: array<int, array{label: string, value: string}>}>
- */
- public function formatSteps(array $submission): array
- {
- $formData = (array) ($submission['form_data'] ?? []);
- $formData['is_minor'] = $this->deriveIsMinor($formData);
- $submissionEmail = trim((string) ($submission['email'] ?? ''));
- $result = [];
- foreach ($this->schema->getSteps() as $step) {
- $title = (string) ($step['title'] ?? '');
- $fields = [];
- foreach (($step['fields'] ?? []) as $fieldDef) {
- $key = (string) ($fieldDef['key'] ?? '');
- $type = (string) ($fieldDef['type'] ?? 'text');
- if ($key === '' || $type === 'file') {
- continue;
- }
- if (!$this->isVisible($fieldDef, $formData)) {
- continue;
- }
- $raw = $formData[$key] ?? null;
- if ($raw === null || $raw === '' || $raw === []) {
- continue;
- }
- $label = (string) ($fieldDef['label'] ?? $key);
- $value = $this->formatValue($raw, $fieldDef);
- $fields[] = ['label' => $label, 'value' => $value];
- }
- if ($this->isPersonalDataStep($title) && $submissionEmail !== '' && !$this->hasEmailField($fields)) {
- $fields[] = ['label' => 'E-Mail', 'value' => $submissionEmail];
- }
- if ($fields !== []) {
- $result[] = ['title' => $title, 'fields' => $fields];
- }
- }
- return $result;
- }
- /**
- * @param array<string, mixed> $submission
- * @return array<int, array{label: string, files: array<int, string>}>
- */
- public function formatUploads(array $submission): array
- {
- $uploads = (array) ($submission['uploads'] ?? []);
- $uploadFields = $this->schema->getUploadFields();
- $result = [];
- foreach ($uploadFields as $key => $fieldDef) {
- $files = $uploads[$key] ?? [];
- if (!is_array($files) || $files === []) {
- continue;
- }
- $label = (string) ($fieldDef['label'] ?? $key);
- $names = [];
- foreach ($files as $file) {
- if (is_array($file)) {
- $names[] = (string) ($file['original_filename'] ?? 'Datei');
- }
- }
- if ($names !== []) {
- $result[] = ['label' => $label, 'files' => $names];
- }
- }
- return $result;
- }
- /** @param array<string, mixed> $fieldDef */
- private function formatValue(mixed $raw, array $fieldDef): string
- {
- $type = (string) ($fieldDef['type'] ?? 'text');
- if ($type === 'date' && is_string($raw)) {
- return $this->formatDate($raw);
- }
- if ($type === 'checkbox') {
- return ((string) $raw === '1' || $raw === true) ? 'Ja' : 'Nein';
- }
- if ($type === 'select' && is_string($raw)) {
- return $this->resolveSelectLabel($raw, $fieldDef);
- }
- if ($type === 'table' && is_array($raw)) {
- return $this->formatTable($raw, $fieldDef);
- }
- if (is_scalar($raw)) {
- return (string) $raw;
- }
- return json_encode($raw, JSON_UNESCAPED_UNICODE) ?: '';
- }
- private function formatDate(string $value): string
- {
- $ts = strtotime($value);
- if ($ts === false) {
- return $value;
- }
- return date('d.m.Y', $ts);
- }
- /** @param array<string, mixed> $fieldDef */
- private function resolveSelectLabel(string $value, array $fieldDef): string
- {
- foreach (($fieldDef['options'] ?? []) as $opt) {
- if (is_array($opt) && (string) ($opt['value'] ?? '') === $value) {
- return (string) ($opt['label'] ?? $value);
- }
- }
- return $value;
- }
- /** @param array<string, mixed> $fieldDef */
- private function formatTable(array $rows, array $fieldDef): string
- {
- $columns = $fieldDef['columns'] ?? [];
- if (!is_array($columns) || $columns === []) {
- return '';
- }
- $lines = [];
- foreach ($rows as $row) {
- if (!is_array($row)) {
- continue;
- }
- $cells = [];
- $hasContent = false;
- foreach ($columns as $i => $col) {
- $cellValue = (string) ($row[$i] ?? '');
- $colType = (string) ($col['type'] ?? 'text');
- if ($colType === 'date' && $cellValue !== '') {
- $cellValue = $this->formatDate($cellValue);
- }
- if ($cellValue !== '') {
- $hasContent = true;
- }
- $colLabel = (string) ($col['label'] ?? '');
- $cells[] = $colLabel . ': ' . $cellValue;
- }
- if ($hasContent) {
- $lines[] = implode(' | ', $cells);
- }
- }
- return implode("\n", $lines);
- }
- /** @param array<string, mixed> $fieldDef */
- private function isVisible(array $fieldDef, array $formData): bool
- {
- if (isset($fieldDef['visible_if'])) {
- $cond = $fieldDef['visible_if'];
- $field = (string) ($cond['field'] ?? '');
- $expected = (string) ($cond['equals'] ?? '');
- $actual = (string) ($formData[$field] ?? '');
- if ($actual !== $expected) {
- return false;
- }
- }
- if (isset($fieldDef['hidden_if'])) {
- $cond = $fieldDef['hidden_if'];
- $field = (string) ($cond['field'] ?? '');
- $expected = (string) ($cond['equals'] ?? '');
- $actual = (string) ($formData[$field] ?? '');
- if ($actual === $expected) {
- return false;
- }
- }
- return true;
- }
- private function isPersonalDataStep(string $title): bool
- {
- return trim($title) === 'Persönliche Daten';
- }
- /** @param array<int, array{label: string, value: string}> $fields */
- private function hasEmailField(array $fields): bool
- {
- foreach ($fields as $field) {
- if (strtolower(trim((string) ($field['label'] ?? ''))) === 'e-mail') {
- return true;
- }
- }
- return false;
- }
- /** @param array<string, mixed> $formData */
- private function deriveIsMinor(array $formData): string
- {
- $birthdate = trim((string) ($formData['geburtsdatum'] ?? ''));
- if ($birthdate === '') {
- return '0';
- }
- $date = \DateTimeImmutable::createFromFormat('!Y-m-d', $birthdate);
- if (!$date || $date->format('Y-m-d') !== $birthdate) {
- return '0';
- }
- $today = new \DateTimeImmutable('today');
- if ($date > $today) {
- return '0';
- }
- return $date->diff($today)->y < 18 ? '1' : '0';
- }
- }
|