configuredPublicPaths = array_values(array_unique($normalizedPaths)); $this->intendedUrlService = $intendedUrlService; } /** * Check if a path is publicly accessible (no authentication required). */ public function isPublicPath(string $path): bool { $normalizedPath = $this->normalizePath($path); // Root path check if ($normalizedPath === '/') { return in_array('/', $this->configuredPublicPaths, true); } // Check configured public paths if (in_array($normalizedPath, $this->configuredPublicPaths, true)) { return true; } // Check always-public prefixes foreach (self::ALWAYS_PUBLIC_PREFIXES as $prefix) { if (str_starts_with($normalizedPath, $prefix)) { return true; } } return false; } /** * Redirect to login if the path requires authentication and user is not logged in. * * @return bool True if access is allowed, false if redirected */ /** * Redirect to login if the path requires authentication and user is not logged in. * Appends ?return_to= so the user is redirected back after login. * * @return bool True if access is allowed, false if redirected */ public function requireAuthOrRedirect(string $path, bool $isLoggedIn): bool { if ($this->isPublicPath($path) || $isLoggedIn) { return true; } $locale = I18n::$locale ?? I18n::$defaultLocale; // Use the concrete target route. Minty alias rewrites compare the full // REQUEST_URI (including query), so alias paths with query params are fragile. $loginPath = Request::withLocale('auth/login', $locale); $requestUri = $_SERVER['REQUEST_URI'] ?? ''; $loginTarget = $this->intendedUrlService->buildLoginRedirect($loginPath, $requestUri); Router::redirect($loginTarget); return false; } private function normalizePath(string $path): string { $normalized = trim($path, '/'); return $normalized === '' ? '/' : $normalized; } }