*/ private const FIELDS = [ 'name', 'registration_number', 'status', 'support_email', 'support_phone', 'preferred_contact_method', 'physical_address', 'postal_address', 'general_notes', ]; /** @var list */ private const DISPLAY_FIELDS = [ 'id', 'name', 'registration_number', 'status', 'support_email', 'support_phone', 'preferred_contact_method', 'physical_address', 'postal_address', 'general_notes', ]; /** @return array */ public function normalize(array $record): array { return [ 'name' => $this->normalizeName($record['name'] ?? null), 'registration_number' => $this->text($record['registration_number'] ?? null), 'status' => strtolower($this->text($record['status'] ?? null) ?? 'active'), 'support_email' => $this->lowerText($record['support_email'] ?? null), 'support_phone' => $this->text($record['support_phone'] ?? null), 'preferred_contact_method' => $this->text($record['preferred_contact_method'] ?? null), 'physical_address' => $this->text($record['physical_address'] ?? null), 'postal_address' => $this->text($record['postal_address'] ?? null), 'general_notes' => $this->text($record['general_notes'] ?? null), ]; } /** @return array{valid: bool, errors: array, name: string, registration_number: string|null, status: string, support_email: string|null, support_phone: string|null, preferred_contact_method: string|null, physical_address: string|null, postal_address: string|null, general_notes: string|null} */ public function validate(array $record): array { $normalized = $this->normalize($record); $errors = []; if ($normalized['name'] === '') { $errors['name'] = 'Client name is required.'; } elseif (mb_strlen($normalized['name']) > 190) { $errors['name'] = 'Client name must be 190 characters or fewer.'; } if (!in_array($normalized['status'], ['active', 'inactive'], true)) { $errors['status'] = 'Invalid client status.'; } if ($normalized['registration_number'] !== null && mb_strlen($normalized['registration_number']) > 120) { $errors['registration_number'] = 'Registration number must be 120 characters or fewer.'; } if ($normalized['support_email'] !== null) { if (filter_var($normalized['support_email'], FILTER_VALIDATE_EMAIL) === false) { $errors['support_email'] = 'Support email must be a valid email address.'; } elseif (mb_strlen($normalized['support_email']) > 190) { $errors['support_email'] = 'Support email must be 190 characters or fewer.'; } } if ($normalized['support_phone'] !== null && !$this->validPhone($normalized['support_phone'])) { $errors['support_phone'] = 'Support phone must contain a valid phone number.'; } return [...$normalized, 'valid' => $errors === [], 'errors' => $errors]; } /** @return array */ public function display(array $record): array { $safe = []; foreach (self::DISPLAY_FIELDS as $field) { if (array_key_exists($field, $record)) { $safe[$field] = $record[$field]; } } return $safe; } /** @return array */ public function toDisplay(array $record): array { return $this->display($record); } private function text(mixed $value): ?string { if ($value === null) return null; $text = trim(is_scalar($value) ? (string) $value : ''); return $text === '' ? null : $text; } private function lowerText(mixed $value): ?string { $text = $this->text($value); return $text === null ? null : strtolower($text); } private function normalizeName(mixed $value): ?string { $text = $this->text($value); if ($text === null) return null; $collapsed = preg_replace('/\s+/u', ' ', $text); return $collapsed === false ? $text : $collapsed; } private function validPhone(string $phone): bool { if (mb_strlen($phone) > 60 || preg_match('/^[0-9+().\-\s]+$/', $phone) !== 1) { return false; } return preg_match('/\d.*\d.*\d.*\d.*\d.*\d.*\d/', $phone) === 1; } }