twigEngine; } protected function sessions(): SessionManager { return $this->sessionManager; } public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { if (($redirect = $this->requireUser($request, $response)) !== null) { return $redirect; } $user = $this->sessions()->getUser(); // Guard for static analysis — requireUser bounced if null already. if ($user === null) { return $response->withStatus(302)->withHeader('Location', '/login'); } $params = $request->getQueryParams(); $filters = [ 'actor_kind' => self::clean($params['actor_kind'] ?? null), 'actor_id' => self::clean($params['actor_id'] ?? null), 'action' => self::clean($params['action'] ?? null), 'entity_type' => self::clean($params['entity_type'] ?? null), 'entity_id' => self::clean($params['entity_id'] ?? null), 'subject_kind' => self::clean($params['subject_kind'] ?? null), 'subject_id' => self::clean($params['subject_id'] ?? null), 'from' => self::clean($params['from'] ?? null), 'to' => self::clean($params['to'] ?? null), ]; $page = isset($params['page']) && ctype_digit((string) $params['page']) ? max(1, (int) $params['page']) : 1; $pageSize = 50; $list = null; $error = null; try { $list = $this->admin->listAuditLog($user->userId, $filters, $page, $pageSize); } catch (ApiException $e) { $error = 'API error: ' . $e->getMessage(); } return $this->twigEngine->render($response, 'pages/audit/index.twig', [ 'active_section' => 'audit', 'list' => $list, 'page' => $page, 'page_size' => $pageSize, 'filters' => $filters, 'allowed_actions' => self::ALLOWED_ACTIONS, 'allowed_kinds' => self::ALLOWED_KINDS, 'error' => $error, ]); } private static function clean(mixed $v): ?string { if (!is_string($v)) { return null; } $trimmed = trim($v); return $trimmed === '' ? null : $trimmed; } }