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 $matchHost false;
  26.     private $staticRoutes = [];
  27.     private $regexpList = [];
  28.     private $dynamicRoutes = [];
  29.     /**
  30.      * @var callable|null
  31.      */
  32.     private $checkCondition;
  33.     public function match(string $pathinfo): array
  34.     {
  35.         $allow $allowSchemes = [];
  36.         if ($ret $this->doMatch($pathinfo$allow$allowSchemes)) {
  37.             return $ret;
  38.         }
  39.         if ($allow) {
  40.             throw new MethodNotAllowedException(array_keys($allow));
  41.         }
  42.         if (!$this instanceof RedirectableUrlMatcherInterface) {
  43.             throw new ResourceNotFoundException(sprintf('No routes found for "%s".'$pathinfo));
  44.         }
  45.         if (!\in_array($this->context->getMethod(), ['HEAD''GET'], true)) {
  46.             // no-op
  47.         } elseif ($allowSchemes) {
  48.             redirect_scheme:
  49.             $scheme $this->context->getScheme();
  50.             $this->context->setScheme(key($allowSchemes));
  51.             try {
  52.                 if ($ret $this->doMatch($pathinfo)) {
  53.                     return $this->redirect($pathinfo$ret['_route'], $this->context->getScheme()) + $ret;
  54.                 }
  55.             } finally {
  56.                 $this->context->setScheme($scheme);
  57.             }
  58.         } elseif ('/' !== $trimmedPathinfo rtrim($pathinfo'/') ?: '/') {
  59.             $pathinfo $trimmedPathinfo === $pathinfo $pathinfo.'/' $trimmedPathinfo;
  60.             if ($ret $this->doMatch($pathinfo$allow$allowSchemes)) {
  61.                 return $this->redirect($pathinfo$ret['_route']) + $ret;
  62.             }
  63.             if ($allowSchemes) {
  64.                 goto redirect_scheme;
  65.             }
  66.         }
  67.         throw new ResourceNotFoundException(sprintf('No routes found for "%s".'$pathinfo));
  68.     }
  69.     private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array
  70.     {
  71.         $allow $allowSchemes = [];
  72.         $pathinfo rawurldecode($pathinfo) ?: '/';
  73.         $trimmedPathinfo rtrim($pathinfo'/') ?: '/';
  74.         $context $this->context;
  75.         $requestMethod $canonicalMethod $context->getMethod();
  76.         if ($this->matchHost) {
  77.             $host strtolower($context->getHost());
  78.         }
  79.         if ('HEAD' === $requestMethod) {
  80.             $canonicalMethod 'GET';
  81.         }
  82.         $supportsRedirections 'GET' === $canonicalMethod && $this instanceof RedirectableUrlMatcherInterface;
  83.         foreach ($this->staticRoutes[$trimmedPathinfo] ?? [] as [$ret$requiredHost$requiredMethods$requiredSchemes$hasTrailingSlash, , $condition]) {
  84.             if ($condition && !($this->checkCondition)($condition$context$condition $request ?? $request $this->request ?: $this->createRequest($pathinfo) : null)) {
  85.                 continue;
  86.             }
  87.             if ($requiredHost) {
  88.                 if ('{' !== $requiredHost[0] ? $requiredHost !== $host : !preg_match($requiredHost$host$hostMatches)) {
  89.                     continue;
  90.                 }
  91.                 if ('{' === $requiredHost[0] && $hostMatches) {
  92.                     $hostMatches['_route'] = $ret['_route'];
  93.                     $ret $this->mergeDefaults($hostMatches$ret);
  94.                 }
  95.             }
  96.             if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
  97.                 if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
  98.                     return $allow $allowSchemes = [];
  99.                 }
  100.                 continue;
  101.             }
  102.             $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
  103.             if ($hasRequiredScheme && $requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
  104.                 $allow += $requiredMethods;
  105.                 continue;
  106.             }
  107.             if (!$hasRequiredScheme) {
  108.                 $allowSchemes += $requiredSchemes;
  109.                 continue;
  110.             }
  111.             return $ret;
  112.         }
  113.         $matchedPathinfo $this->matchHost $host.'.'.$pathinfo $pathinfo;
  114.         foreach ($this->regexpList as $offset => $regex) {
  115.             while (preg_match($regex$matchedPathinfo$matches)) {
  116.                 foreach ($this->dynamicRoutes[$m = (int) $matches['MARK']] as [$ret$vars$requiredMethods$requiredSchemes$hasTrailingSlash$hasTrailingVar$condition]) {
  117.                     if (null !== $condition) {
  118.                         if (=== $condition) { // marks the last route in the regexp
  119.                             continue 3;
  120.                         }
  121.                         if (!($this->checkCondition)($condition$context$condition $request ?? $request $this->request ?: $this->createRequest($pathinfo) : null)) {
  122.                             continue;
  123.                         }
  124.                     }
  125.                     $hasTrailingVar $trimmedPathinfo !== $pathinfo && $hasTrailingVar;
  126.                     if ($hasTrailingVar && ($hasTrailingSlash || (null === $n $matches[\count($vars)] ?? null) || '/' !== ($n[-1] ?? '/')) && preg_match($regex$this->matchHost $host.'.'.$trimmedPathinfo $trimmedPathinfo$n) && $m === (int) $n['MARK']) {
  127.                         if ($hasTrailingSlash) {
  128.                             $matches $n;
  129.                         } else {
  130.                             $hasTrailingVar false;
  131.                         }
  132.                     }
  133.                     if ('/' !== $pathinfo && !$hasTrailingVar && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
  134.                         if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
  135.                             return $allow $allowSchemes = [];
  136.                         }
  137.                         continue;
  138.                     }
  139.                     foreach ($vars as $i => $v) {
  140.                         if (isset($matches[$i])) {
  141.                             $ret[$v] = $matches[$i];
  142.                         }
  143.                     }
  144.                     if ($requiredSchemes && !isset($requiredSchemes[$context->getScheme()])) {
  145.                         $allowSchemes += $requiredSchemes;
  146.                         continue;
  147.                     }
  148.                     if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
  149.                         $allow += $requiredMethods;
  150.                         continue;
  151.                     }
  152.                     return $ret;
  153.                 }
  154.                 $regex substr_replace($regex'F'$m $offset\strlen($m));
  155.                 $offset += \strlen($m);
  156.             }
  157.         }
  158.         if ('/' === $pathinfo && !$allow && !$allowSchemes) {
  159.             throw new NoConfigurationException();
  160.         }
  161.         return [];
  162.     }
  163. }