vendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php line 74

  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Routing\Matcher\Dumper;
  11. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  12. use Symfony\Component\Routing\Exception\NoConfigurationException;
  13. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  14. use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
  15. use Symfony\Component\Routing\RequestContext;
  16. /**
  17.  * @author Nicolas Grekas <p@tchwork.com>
  18.  *
  19.  * @internal
  20.  *
  21.  * @property RequestContext $context
  22.  */
  23. trait CompiledUrlMatcherTrait
  24. {
  25.     private bool $matchHost false;
  26.     private array $staticRoutes = [];
  27.     private array $regexpList = [];
  28.     private array $dynamicRoutes = [];
  29.     private ?\Closure $checkCondition;
  30.     public function match(string $pathinfo): array
  31.     {
  32.         $allow $allowSchemes = [];
  33.         if ($ret $this->doMatch($pathinfo$allow$allowSchemes)) {
  34.             return $ret;
  35.         }
  36.         if ($allow) {
  37.             throw new MethodNotAllowedException(array_keys($allow));
  38.         }
  39.         if (!$this instanceof RedirectableUrlMatcherInterface) {
  40.             throw new ResourceNotFoundException(sprintf('No routes found for "%s".'$pathinfo));
  41.         }
  42.         if (!\in_array($this->context->getMethod(), ['HEAD''GET'], true)) {
  43.             // no-op
  44.         } elseif ($allowSchemes) {
  45.             redirect_scheme:
  46.             $scheme $this->context->getScheme();
  47.             $this->context->setScheme(key($allowSchemes));
  48.             try {
  49.                 if ($ret $this->doMatch($pathinfo)) {
  50.                     return $this->redirect($pathinfo$ret['_route'], $this->context->getScheme()) + $ret;
  51.                 }
  52.             } finally {
  53.                 $this->context->setScheme($scheme);
  54.             }
  55.         } elseif ('/' !== $trimmedPathinfo rtrim($pathinfo'/') ?: '/') {
  56.             $pathinfo $trimmedPathinfo === $pathinfo $pathinfo.'/' $trimmedPathinfo;
  57.             if ($ret $this->doMatch($pathinfo$allow$allowSchemes)) {
  58.                 return $this->redirect($pathinfo$ret['_route']) + $ret;
  59.             }
  60.             if ($allowSchemes) {
  61.                 goto redirect_scheme;
  62.             }
  63.         }
  64.         throw new ResourceNotFoundException(sprintf('No routes found for "%s".'$pathinfo));
  65.     }
  66.     private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array
  67.     {
  68.         $allow $allowSchemes = [];
  69.         $pathinfo rawurldecode($pathinfo) ?: '/';
  70.         $trimmedPathinfo rtrim($pathinfo'/') ?: '/';
  71.         $context $this->context;
  72.         $requestMethod $canonicalMethod $context->getMethod();
  73.         if ($this->matchHost) {
  74.             $host strtolower($context->getHost());
  75.         }
  76.         if ('HEAD' === $requestMethod) {
  77.             $canonicalMethod 'GET';
  78.         }
  79.         $supportsRedirections 'GET' === $canonicalMethod && $this instanceof RedirectableUrlMatcherInterface;
  80.         foreach ($this->staticRoutes[$trimmedPathinfo] ?? [] as [$ret$requiredHost$requiredMethods$requiredSchemes$hasTrailingSlash, , $condition]) {
  81.             if ($requiredHost) {
  82.                 if ('{' !== $requiredHost[0] ? $requiredHost !== $host : !preg_match($requiredHost$host$hostMatches)) {
  83.                     continue;
  84.                 }
  85.                 if ('{' === $requiredHost[0] && $hostMatches) {
  86.                     $hostMatches['_route'] = $ret['_route'];
  87.                     $ret $this->mergeDefaults($hostMatches$ret);
  88.                 }
  89.             }
  90.             if ($condition && !($this->checkCondition)($condition$context$condition $request ??= $this->request ?: $this->createRequest($pathinfo) : null$ret)) {
  91.                 continue;
  92.             }
  93.             if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
  94.                 if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
  95.                     return $allow $allowSchemes = [];
  96.                 }
  97.                 continue;
  98.             }
  99.             $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
  100.             if ($hasRequiredScheme && $requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
  101.                 $allow += $requiredMethods;
  102.                 continue;
  103.             }
  104.             if (!$hasRequiredScheme) {
  105.                 $allowSchemes += $requiredSchemes;
  106.                 continue;
  107.             }
  108.             return $ret;
  109.         }
  110.         $matchedPathinfo $this->matchHost $host.'.'.$pathinfo $pathinfo;
  111.         foreach ($this->regexpList as $offset => $regex) {
  112.             while (preg_match($regex$matchedPathinfo$matches)) {
  113.                 foreach ($this->dynamicRoutes[$m = (int) $matches['MARK']] as [$ret$vars$requiredMethods$requiredSchemes$hasTrailingSlash$hasTrailingVar$condition]) {
  114.                     if (=== $condition) { // marks the last route in the regexp
  115.                         continue 3;
  116.                     }
  117.                     $hasTrailingVar $trimmedPathinfo !== $pathinfo && $hasTrailingVar;
  118.                     if ($hasTrailingVar && ($hasTrailingSlash || (null === $n $matches[\count($vars)] ?? null) || '/' !== ($n[-1] ?? '/')) && preg_match($regex$this->matchHost $host.'.'.$trimmedPathinfo $trimmedPathinfo$n) && $m === (int) $n['MARK']) {
  119.                         if ($hasTrailingSlash) {
  120.                             $matches $n;
  121.                         } else {
  122.                             $hasTrailingVar false;
  123.                         }
  124.                     }
  125.                     foreach ($vars as $i => $v) {
  126.                         if (isset($matches[$i])) {
  127.                             $ret[$v] = $matches[$i];
  128.                         }
  129.                     }
  130.                     if ($condition && !($this->checkCondition)($condition$context$condition $request ??= $this->request ?: $this->createRequest($pathinfo) : null$ret)) {
  131.                         continue;
  132.                     }
  133.                     if ('/' !== $pathinfo && !$hasTrailingVar && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
  134.                         if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
  135.                             return $allow $allowSchemes = [];
  136.                         }
  137.                         continue;
  138.                     }
  139.                     if ($requiredSchemes && !isset($requiredSchemes[$context->getScheme()])) {
  140.                         $allowSchemes += $requiredSchemes;
  141.                         continue;
  142.                     }
  143.                     if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
  144.                         $allow += $requiredMethods;
  145.                         continue;
  146.                     }
  147.                     return $ret;
  148.                 }
  149.                 $regex substr_replace($regex'F'$m $offset\strlen($m));
  150.                 $offset += \strlen($m);
  151.             }
  152.         }
  153.         if ('/' === $pathinfo && !$allow && !$allowSchemes) {
  154.             throw new NoConfigurationException();
  155.         }
  156.         return [];
  157.     }
  158. }