Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. TraceableUrlMatcher.php

function TraceableUrlMatcher::matchCollection

Overrides UrlMatcher::matchCollection

File

vendor/symfony/routing/Matcher/TraceableUrlMatcher.php, line 53

Class

TraceableUrlMatcher
TraceableUrlMatcher helps debug path info matching by tracing the match.

Namespace

Symfony\Component\Routing\Matcher

Code

protected function matchCollection(string $pathinfo, RouteCollection $routes) : array {
    // HEAD and GET are equivalent as per RFC
    if ('HEAD' === ($method = $this->context
        ->getMethod())) {
        $method = 'GET';
    }
    $supportsTrailingSlash = 'GET' === $method && $this instanceof RedirectableUrlMatcherInterface;
    $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/';
    foreach ($routes as $name => $route) {
        $compiledRoute = $route->compile();
        $staticPrefix = rtrim($compiledRoute->getStaticPrefix(), '/');
        $requiredMethods = $route->getMethods();
        // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
        if ('' !== $staticPrefix && !str_starts_with($trimmedPathinfo, $staticPrefix)) {
            $this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
            continue;
        }
        $regex = $compiledRoute->getRegex();
        $pos = strrpos($regex, '$');
        $hasTrailingSlash = '/' === $regex[$pos - 1];
        $regex = substr_replace($regex, '/?$', $pos - $hasTrailingSlash, 1 + $hasTrailingSlash);
        if (!preg_match($regex, $pathinfo, $matches)) {
            // does it match without any requirements?
            $r = new Route($route->getPath(), $route->getDefaults(), [], $route->getOptions());
            $cr = $r->compile();
            if (!preg_match($cr->getRegex(), $pathinfo)) {
                $this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
                continue;
            }
            foreach ($route->getRequirements() as $n => $regex) {
                $r = new Route($route->getPath(), $route->getDefaults(), [
                    $n => $regex,
                ], $route->getOptions());
                $cr = $r->compile();
                if (\in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) {
                    $this->addTrace(\sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route);
                    continue 2;
                }
            }
            continue;
        }
        $hasTrailingVar = $trimmedPathinfo !== $pathinfo && preg_match('#\\{[\\w\\x80-\\xFF]+\\}/?$#', $route->getPath());
        if ($hasTrailingVar && ($hasTrailingSlash || null === ($m = $matches[\count($compiledRoute->getPathVariables())] ?? null) || '/' !== ($m[-1] ?? '/')) && preg_match($regex, $trimmedPathinfo, $m)) {
            if ($hasTrailingSlash) {
                $matches = $m;
            }
            else {
                $hasTrailingVar = false;
            }
        }
        $hostMatches = [];
        if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context
            ->getHost(), $hostMatches)) {
            $this->addTrace(\sprintf('Host "%s" does not match the requirement ("%s")', $this->context
                ->getHost(), $route->getHost()), self::ROUTE_ALMOST_MATCHES, $name, $route);
            continue;
        }
        $attributes = $this->getAttributes($route, $name, array_replace($matches, $hostMatches));
        $status = $this->handleRouteRequirements($pathinfo, $name, $route, $attributes);
        if (self::REQUIREMENT_MISMATCH === $status[0]) {
            $this->addTrace(\sprintf('Condition "%s" does not evaluate to "true"', $route->getCondition()), self::ROUTE_ALMOST_MATCHES, $name, $route);
            continue;
        }
        if ('/' !== $pathinfo && !$hasTrailingVar && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
            if ($supportsTrailingSlash && (!$requiredMethods || \in_array('GET', $requiredMethods, true))) {
                $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route);
                return $this->allow = $this->allowSchemes = [];
            }
            $this->addTrace(\sprintf('Path "%s" does not match', $route->getPath()), self::ROUTE_DOES_NOT_MATCH, $name, $route);
            continue;
        }
        if ($route->getSchemes() && !$route->hasScheme($this->context
            ->getScheme())) {
            $this->allowSchemes = array_merge($this->allowSchemes, $route->getSchemes());
            $this->addTrace(\sprintf('Scheme "%s" does not match any of the required schemes (%s)', $this->context
                ->getScheme(), implode(', ', $route->getSchemes())), self::ROUTE_ALMOST_MATCHES, $name, $route);
            continue;
        }
        if ($requiredMethods && !\in_array($method, $requiredMethods, true)) {
            $this->allow = array_merge($this->allow, $requiredMethods);
            $this->addTrace(\sprintf('Method "%s" does not match any of the required methods (%s)', $this->context
                ->getMethod(), implode(', ', $requiredMethods)), self::ROUTE_ALMOST_MATCHES, $name, $route);
            continue;
        }
        $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route);
        return array_replace($attributes, $status[1] ?? []);
    }
    return [];
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal