[ Index ]

PHP Cross Reference of phpBB-3.3.3-deutsch

title

Body

[close]

/vendor/symfony/routing/Matcher/ -> UrlMatcher.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of the Symfony package.
   5   *
   6   * (c) Fabien Potencier <fabien@symfony.com>
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  namespace Symfony\Component\Routing\Matcher;
  13  
  14  use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
  15  use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
  16  use Symfony\Component\HttpFoundation\Request;
  17  use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  18  use Symfony\Component\Routing\Exception\NoConfigurationException;
  19  use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  20  use Symfony\Component\Routing\RequestContext;
  21  use Symfony\Component\Routing\Route;
  22  use Symfony\Component\Routing\RouteCollection;
  23  
  24  /**
  25   * UrlMatcher matches URL based on a set of routes.
  26   *
  27   * @author Fabien Potencier <fabien@symfony.com>
  28   */
  29  class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
  30  {
  31      const REQUIREMENT_MATCH = 0;
  32      const REQUIREMENT_MISMATCH = 1;
  33      const ROUTE_MATCH = 2;
  34  
  35      protected $context;
  36      protected $allow = [];
  37      protected $routes;
  38      protected $request;
  39      protected $expressionLanguage;
  40  
  41      /**
  42       * @var ExpressionFunctionProviderInterface[]
  43       */
  44      protected $expressionLanguageProviders = [];
  45  
  46      public function __construct(RouteCollection $routes, RequestContext $context)
  47      {
  48          $this->routes = $routes;
  49          $this->context = $context;
  50      }
  51  
  52      /**
  53       * {@inheritdoc}
  54       */
  55      public function setContext(RequestContext $context)
  56      {
  57          $this->context = $context;
  58      }
  59  
  60      /**
  61       * {@inheritdoc}
  62       */
  63      public function getContext()
  64      {
  65          return $this->context;
  66      }
  67  
  68      /**
  69       * {@inheritdoc}
  70       */
  71      public function match($pathinfo)
  72      {
  73          $this->allow = [];
  74  
  75          if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
  76              return $ret;
  77          }
  78  
  79          if ('/' === $pathinfo && !$this->allow) {
  80              throw new NoConfigurationException();
  81          }
  82  
  83          throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
  84      }
  85  
  86      /**
  87       * {@inheritdoc}
  88       */
  89      public function matchRequest(Request $request)
  90      {
  91          $this->request = $request;
  92  
  93          $ret = $this->match($request->getPathInfo());
  94  
  95          $this->request = null;
  96  
  97          return $ret;
  98      }
  99  
 100      public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
 101      {
 102          $this->expressionLanguageProviders[] = $provider;
 103      }
 104  
 105      /**
 106       * Tries to match a URL with a set of routes.
 107       *
 108       * @param string          $pathinfo The path info to be parsed
 109       * @param RouteCollection $routes   The set of routes
 110       *
 111       * @return array An array of parameters
 112       *
 113       * @throws NoConfigurationException  If no routing configuration could be found
 114       * @throws ResourceNotFoundException If the resource could not be found
 115       * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
 116       */
 117      protected function matchCollection($pathinfo, RouteCollection $routes)
 118      {
 119          // HEAD and GET are equivalent as per RFC
 120          if ('HEAD' === $method = $this->context->getMethod()) {
 121              $method = 'GET';
 122          }
 123          $supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;
 124  
 125          foreach ($routes as $name => $route) {
 126              $compiledRoute = $route->compile();
 127              $staticPrefix = $compiledRoute->getStaticPrefix();
 128              $requiredMethods = $route->getMethods();
 129  
 130              // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
 131              if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
 132                  // no-op
 133              } elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods)) || 'GET' !== $method) {
 134                  continue;
 135              } elseif ('/' === substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) {
 136                  return $this->allow = [];
 137              } else {
 138                  continue;
 139              }
 140              $regex = $compiledRoute->getRegex();
 141  
 142              if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
 143                  $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
 144                  $hasTrailingSlash = true;
 145              } else {
 146                  $hasTrailingSlash = false;
 147              }
 148  
 149              if (!preg_match($regex, $pathinfo, $matches)) {
 150                  continue;
 151              }
 152  
 153              if ($hasTrailingSlash && '/' !== substr($pathinfo, -1)) {
 154                  if ((!$requiredMethods || \in_array('GET', $requiredMethods)) && 'GET' === $method) {
 155                      return $this->allow = [];
 156                  }
 157                  continue;
 158              }
 159  
 160              $hostMatches = [];
 161              if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
 162                  continue;
 163              }
 164  
 165              $status = $this->handleRouteRequirements($pathinfo, $name, $route);
 166  
 167              if (self::REQUIREMENT_MISMATCH === $status[0]) {
 168                  continue;
 169              }
 170  
 171              // check HTTP method requirement
 172              if ($requiredMethods) {
 173                  if (!\in_array($method, $requiredMethods)) {
 174                      if (self::REQUIREMENT_MATCH === $status[0]) {
 175                          $this->allow = array_merge($this->allow, $requiredMethods);
 176                      }
 177  
 178                      continue;
 179                  }
 180              }
 181  
 182              return $this->getAttributes($route, $name, array_replace($matches, $hostMatches, isset($status[1]) ? $status[1] : []));
 183          }
 184  
 185          return [];
 186      }
 187  
 188      /**
 189       * Returns an array of values to use as request attributes.
 190       *
 191       * As this method requires the Route object, it is not available
 192       * in matchers that do not have access to the matched Route instance
 193       * (like the PHP and Apache matcher dumpers).
 194       *
 195       * @param Route  $route      The route we are matching against
 196       * @param string $name       The name of the route
 197       * @param array  $attributes An array of attributes from the matcher
 198       *
 199       * @return array An array of parameters
 200       */
 201      protected function getAttributes(Route $route, $name, array $attributes)
 202      {
 203          $attributes['_route'] = $name;
 204  
 205          return $this->mergeDefaults($attributes, $route->getDefaults());
 206      }
 207  
 208      /**
 209       * Handles specific route requirements.
 210       *
 211       * @param string $pathinfo The path
 212       * @param string $name     The route name
 213       * @param Route  $route    The route
 214       *
 215       * @return array The first element represents the status, the second contains additional information
 216       */
 217      protected function handleRouteRequirements($pathinfo, $name, Route $route)
 218      {
 219          // expression condition
 220          if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), ['context' => $this->context, 'request' => $this->request ?: $this->createRequest($pathinfo)])) {
 221              return [self::REQUIREMENT_MISMATCH, null];
 222          }
 223  
 224          // check HTTP scheme requirement
 225          $scheme = $this->context->getScheme();
 226          $status = $route->getSchemes() && !$route->hasScheme($scheme) ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
 227  
 228          return [$status, null];
 229      }
 230  
 231      /**
 232       * Get merged default parameters.
 233       *
 234       * @param array $params   The parameters
 235       * @param array $defaults The defaults
 236       *
 237       * @return array Merged default parameters
 238       */
 239      protected function mergeDefaults($params, $defaults)
 240      {
 241          foreach ($params as $key => $value) {
 242              if (!\is_int($key)) {
 243                  $defaults[$key] = $value;
 244              }
 245          }
 246  
 247          return $defaults;
 248      }
 249  
 250      protected function getExpressionLanguage()
 251      {
 252          if (null === $this->expressionLanguage) {
 253              if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
 254                  throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
 255              }
 256              $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
 257          }
 258  
 259          return $this->expressionLanguage;
 260      }
 261  
 262      /**
 263       * @internal
 264       */
 265      protected function createRequest($pathinfo)
 266      {
 267          if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
 268              return null;
 269          }
 270  
 271          return Request::create($this->context->getScheme().'://'.$this->context->getHost().$this->context->getBaseUrl().$pathinfo, $this->context->getMethod(), $this->context->getParameters(), [], [], [
 272              'SCRIPT_FILENAME' => $this->context->getBaseUrl(),
 273              'SCRIPT_NAME' => $this->context->getBaseUrl(),
 274          ]);
 275      }
 276  }


Generated: Sun Feb 14 20:08:31 2021 Cross-referenced by PHPXref 0.7.1