Lines 100.00% 28 / 28
Methods 100.00% 3 / 3
Classes 100.00% 1 / 1
Covered by tests of size
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 onKernelRequest 100.00% 22 / 22 100.00% 1 / 1 6
 normalizePath 100.00% 5 / 5 100.00% 1 / 1 5
33readonly class RouterListener
34{
35    public function __construct(
36        private RouteCollection $routes,
37    ) {
38    }
39
40    public function onKernelRequest(RequestEvent $event): void
41    {
42        if (!$event->isMainRequest()) {
43            return;
44        }
45
46        $request = $event->getRequest();
47
48        // Skip if already matched (e.g., by sub-request or test)
49        if ($request->attributes->has('_controller')) {
50            return;
51        }
52
53        $requestContext = new RequestContext();
54        $requestContext->fromRequest($request);
55
56        $urlMatcher = new UrlMatcher($this->routes, $requestContext);
57        try {
58            $pathInfo = $this->normalizePath($request->getPathInfo());
59            $parameters = $urlMatcher->match($pathInfo);
60        } catch (ResourceNotFoundException $exception) {
61            throw new NotFoundHttpException($exception->getMessage(), $exception);
62        } catch (MethodNotAllowedException $exception) {
63            throw new MethodNotAllowedHttpException(
64                $exception->getAllowedMethods(),
65                $exception->getMessage(),
66                $exception,
67            );
68        }
69
70        $normalizedParameters = [];
71        foreach ($parameters as $parameterName => $parameterValue) {
72            $normalizedParameters[(string) $parameterName] = $parameterValue;
73        }
74
75        $request->attributes->add($normalizedParameters);
76    }
77
78    /**
79     * Normalizes the path by removing trailing slashes and /index.php suffix.
80     */
81    private function normalizePath(string $path): string
82    {
83        // Strip /index.php suffix (e.g. /update/index.php → /update)
84        if (str_ends_with($path, '/index.php')) {
85            $path = substr($path, offset: 0, length: -10);
86        }
87
88        // Remove trailing slash, but keep root path as /
89        if ($path !== '/' && str_ends_with($path, '/')) {
90            $path = rtrim($path, characters: '/');
91        }
92
93        return $path === '' ? '/' : $path;
94    }
95}