*/ public function validate(array $input, array $existingClients = [], ?int $currentId = null): array { $result = ($this->clients ?? new ClientRecord())->validate($input); $nameKey = $this->duplicateKey(is_string($result['name'] ?? null) ? $result['name'] : ''); if ($nameKey !== '' && $this->hasDuplicate($nameKey, $existingClients, $currentId)) { $result['errors']['name'] = 'Client name is already in use.'; } $result['valid'] = $result['errors'] === []; return $result; } /** @return array */ public function validateForCreate(array $input, array $existingClients = []): array { return $this->validate($input, $existingClients); } /** @return array */ public function validateForEdit(int $id, array $input, array $existingClients = []): array { $errors = []; if ($id < 1) $errors['id'] = 'Client ID must be a positive integer.'; $result = $this->validate($input, $existingClients, $id); $result['id'] = $id; $result['errors'] = [...$errors, ...$result['errors']]; $result['valid'] = $result['errors'] === []; return $result; } /** @return array{valid: bool, id: int, status: string, errors: array} */ public function validateDeactivate(array $client): array { return $this->validateTransition($client, 'active', 'inactive'); } /** @return array{valid: bool, id: int, status: string, errors: array} */ public function validateReactivate(array $client): array { return $this->validateTransition($client, 'inactive', 'active'); } /** @return array{valid: bool, id: int, status: string, errors: array} */ public function deactivate(array $client): array { return $this->validateDeactivate($client); } /** @return array{valid: bool, id: int, status: string, errors: array} */ public function reactivate(array $client): array { return $this->validateReactivate($client); } /** @return array */ public function display(array $client): array { return ($this->clients ?? new ClientRecord())->display($client); } /** @return array */ public function toDisplay(array $client): array { return $this->display($client); } /** @return array{valid: bool, id: int, status: string, errors: array} */ private function validateTransition(array $client, string $from, string $to): array { $id = $this->positiveId($client['id'] ?? null); $status = strtolower(trim(is_scalar($client['status'] ?? null) ? (string) $client['status'] : '')); $errors = []; if ($id === null) $errors['id'] = 'Client ID must be a positive integer.'; if ($status !== $from) $errors['status'] = "Only {$from} clients can be changed to {$to}."; return ['valid' => $errors === [], 'id' => $id ?? 0, 'status' => $to, 'errors' => $errors]; } private function hasDuplicate(string $candidate, array $rows, ?int $currentId): bool { foreach ($rows as $row) { $name = is_array($row) ? ($row['name'] ?? null) : $row; if (!is_scalar($name) || $this->duplicateKey((string) $name) !== $candidate) continue; $rowId = is_array($row) ? $this->positiveId($row['id'] ?? null) : null; if ($currentId === null || $rowId !== $currentId) return true; } return false; } private function duplicateKey(string $value): string { $collapsed = preg_replace('/\s+/u', ' ', trim($value)); return strtolower($collapsed === false ? trim($value) : $collapsed); } private function positiveId(mixed $value): ?int { if (is_int($value) && $value > 0) return $value; if (is_string($value) && preg_match('/^[1-9]\d*$/', trim($value)) === 1) { $id = filter_var(trim($value), FILTER_VALIDATE_INT); return $id === false ? null : $id; } return null; } }