comparison vendor/symfony/routing/Matcher/UrlMatcher.php @ 17:129ea1e6d783

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:21:36 +0000
parents 1fec387a4317
children
comparison
equal deleted inserted replaced
16:c2387f117808 17:129ea1e6d783
9 * file that was distributed with this source code. 9 * file that was distributed with this source code.
10 */ 10 */
11 11
12 namespace Symfony\Component\Routing\Matcher; 12 namespace Symfony\Component\Routing\Matcher;
13 13
14 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
15 use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
16 use Symfony\Component\HttpFoundation\Request;
14 use Symfony\Component\Routing\Exception\MethodNotAllowedException; 17 use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15 use Symfony\Component\Routing\Exception\NoConfigurationException; 18 use Symfony\Component\Routing\Exception\NoConfigurationException;
16 use Symfony\Component\Routing\Exception\ResourceNotFoundException; 19 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
17 use Symfony\Component\Routing\RouteCollection;
18 use Symfony\Component\Routing\RequestContext; 20 use Symfony\Component\Routing\RequestContext;
19 use Symfony\Component\Routing\Route; 21 use Symfony\Component\Routing\Route;
20 use Symfony\Component\HttpFoundation\Request; 22 use Symfony\Component\Routing\RouteCollection;
21 use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
22 use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
23 23
24 /** 24 /**
25 * UrlMatcher matches URL based on a set of routes. 25 * UrlMatcher matches URL based on a set of routes.
26 * 26 *
27 * @author Fabien Potencier <fabien@symfony.com> 27 * @author Fabien Potencier <fabien@symfony.com>
31 const REQUIREMENT_MATCH = 0; 31 const REQUIREMENT_MATCH = 0;
32 const REQUIREMENT_MISMATCH = 1; 32 const REQUIREMENT_MISMATCH = 1;
33 const ROUTE_MATCH = 2; 33 const ROUTE_MATCH = 2;
34 34
35 protected $context; 35 protected $context;
36 protected $allow = array(); 36 protected $allow = [];
37 protected $routes; 37 protected $routes;
38 protected $request; 38 protected $request;
39 protected $expressionLanguage; 39 protected $expressionLanguage;
40 40
41 /** 41 /**
42 * @var ExpressionFunctionProviderInterface[] 42 * @var ExpressionFunctionProviderInterface[]
43 */ 43 */
44 protected $expressionLanguageProviders = array(); 44 protected $expressionLanguageProviders = [];
45 45
46 public function __construct(RouteCollection $routes, RequestContext $context) 46 public function __construct(RouteCollection $routes, RequestContext $context)
47 { 47 {
48 $this->routes = $routes; 48 $this->routes = $routes;
49 $this->context = $context; 49 $this->context = $context;
68 /** 68 /**
69 * {@inheritdoc} 69 * {@inheritdoc}
70 */ 70 */
71 public function match($pathinfo) 71 public function match($pathinfo)
72 { 72 {
73 $this->allow = array(); 73 $this->allow = [];
74 74
75 if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) { 75 if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
76 return $ret; 76 return $ret;
77 } 77 }
78 78
79 if ('/' === $pathinfo && !$this->allow) { 79 if ('/' === $pathinfo && !$this->allow) {
80 throw new NoConfigurationException(); 80 throw new NoConfigurationException();
81 } 81 }
82 82
83 throw 0 < count($this->allow) 83 throw 0 < \count($this->allow)
84 ? new MethodNotAllowedException(array_unique($this->allow)) 84 ? new MethodNotAllowedException(array_unique($this->allow))
85 : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); 85 : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
86 } 86 }
87 87
88 /** 88 /**
116 * @throws ResourceNotFoundException If the resource could not be found 116 * @throws ResourceNotFoundException If the resource could not be found
117 * @throws MethodNotAllowedException If the resource was found but the request method is not allowed 117 * @throws MethodNotAllowedException If the resource was found but the request method is not allowed
118 */ 118 */
119 protected function matchCollection($pathinfo, RouteCollection $routes) 119 protected function matchCollection($pathinfo, RouteCollection $routes)
120 { 120 {
121 // HEAD and GET are equivalent as per RFC
122 if ('HEAD' === $method = $this->context->getMethod()) {
123 $method = 'GET';
124 }
125 $supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;
126
121 foreach ($routes as $name => $route) { 127 foreach ($routes as $name => $route) {
122 $compiledRoute = $route->compile(); 128 $compiledRoute = $route->compile();
129 $staticPrefix = $compiledRoute->getStaticPrefix();
130 $requiredMethods = $route->getMethods();
123 131
124 // check the static prefix of the URL first. Only use the more expensive preg_match when it matches 132 // check the static prefix of the URL first. Only use the more expensive preg_match when it matches
125 if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) { 133 if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
126 continue; 134 // no-op
127 } 135 } elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods)) || 'GET' !== $method) {
128 136 continue;
129 if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) { 137 } elseif ('/' === substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) {
130 continue; 138 return $this->allow = [];
131 } 139 } else {
132 140 continue;
133 $hostMatches = array(); 141 }
142 $regex = $compiledRoute->getRegex();
143
144 if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
145 $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
146 $hasTrailingSlash = true;
147 } else {
148 $hasTrailingSlash = false;
149 }
150
151 if (!preg_match($regex, $pathinfo, $matches)) {
152 continue;
153 }
154
155 if ($hasTrailingSlash && '/' !== substr($pathinfo, -1)) {
156 if ((!$requiredMethods || \in_array('GET', $requiredMethods)) && 'GET' === $method) {
157 return $this->allow = [];
158 }
159 continue;
160 }
161
162 $hostMatches = [];
134 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) { 163 if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
135 continue; 164 continue;
136 } 165 }
137 166
138 $status = $this->handleRouteRequirements($pathinfo, $name, $route); 167 $status = $this->handleRouteRequirements($pathinfo, $name, $route);
140 if (self::REQUIREMENT_MISMATCH === $status[0]) { 169 if (self::REQUIREMENT_MISMATCH === $status[0]) {
141 continue; 170 continue;
142 } 171 }
143 172
144 // check HTTP method requirement 173 // check HTTP method requirement
145 if ($requiredMethods = $route->getMethods()) { 174 if ($requiredMethods) {
146 // HEAD and GET are equivalent as per RFC 175 if (!\in_array($method, $requiredMethods)) {
147 if ('HEAD' === $method = $this->context->getMethod()) {
148 $method = 'GET';
149 }
150
151 if (!in_array($method, $requiredMethods)) {
152 if (self::REQUIREMENT_MATCH === $status[0]) { 176 if (self::REQUIREMENT_MATCH === $status[0]) {
153 $this->allow = array_merge($this->allow, $requiredMethods); 177 $this->allow = array_merge($this->allow, $requiredMethods);
154 } 178 }
155 179
156 continue; 180 continue;
157 } 181 }
158 } 182 }
159 183
160 return $this->getAttributes($route, $name, array_replace($matches, $hostMatches, isset($status[1]) ? $status[1] : array())); 184 return $this->getAttributes($route, $name, array_replace($matches, $hostMatches, isset($status[1]) ? $status[1] : []));
161 } 185 }
186
187 return [];
162 } 188 }
163 189
164 /** 190 /**
165 * Returns an array of values to use as request attributes. 191 * Returns an array of values to use as request attributes.
166 * 192 *
191 * @return array The first element represents the status, the second contains additional information 217 * @return array The first element represents the status, the second contains additional information
192 */ 218 */
193 protected function handleRouteRequirements($pathinfo, $name, Route $route) 219 protected function handleRouteRequirements($pathinfo, $name, Route $route)
194 { 220 {
195 // expression condition 221 // expression condition
196 if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), array('context' => $this->context, 'request' => $this->request ?: $this->createRequest($pathinfo)))) { 222 if ($route->getCondition() && !$this->getExpressionLanguage()->evaluate($route->getCondition(), ['context' => $this->context, 'request' => $this->request ?: $this->createRequest($pathinfo)])) {
197 return array(self::REQUIREMENT_MISMATCH, null); 223 return [self::REQUIREMENT_MISMATCH, null];
198 } 224 }
199 225
200 // check HTTP scheme requirement 226 // check HTTP scheme requirement
201 $scheme = $this->context->getScheme(); 227 $scheme = $this->context->getScheme();
202 $status = $route->getSchemes() && !$route->hasScheme($scheme) ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH; 228 $status = $route->getSchemes() && !$route->hasScheme($scheme) ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH;
203 229
204 return array($status, null); 230 return [$status, null];
205 } 231 }
206 232
207 /** 233 /**
208 * Get merged default parameters. 234 * Get merged default parameters.
209 * 235 *
213 * @return array Merged default parameters 239 * @return array Merged default parameters
214 */ 240 */
215 protected function mergeDefaults($params, $defaults) 241 protected function mergeDefaults($params, $defaults)
216 { 242 {
217 foreach ($params as $key => $value) { 243 foreach ($params as $key => $value) {
218 if (!is_int($key)) { 244 if (!\is_int($key)) {
219 $defaults[$key] = $value; 245 $defaults[$key] = $value;
220 } 246 }
221 } 247 }
222 248
223 return $defaults; 249 return $defaults;
242 { 268 {
243 if (!class_exists('Symfony\Component\HttpFoundation\Request')) { 269 if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
244 return null; 270 return null;
245 } 271 }
246 272
247 return Request::create($this->context->getScheme().'://'.$this->context->getHost().$this->context->getBaseUrl().$pathinfo, $this->context->getMethod(), $this->context->getParameters(), array(), array(), array( 273 return Request::create($this->context->getScheme().'://'.$this->context->getHost().$this->context->getBaseUrl().$pathinfo, $this->context->getMethod(), $this->context->getParameters(), [], [], [
248 'SCRIPT_FILENAME' => $this->context->getBaseUrl(), 274 'SCRIPT_FILENAME' => $this->context->getBaseUrl(),
249 'SCRIPT_NAME' => $this->context->getBaseUrl(), 275 'SCRIPT_NAME' => $this->context->getBaseUrl(),
250 )); 276 ]);
251 } 277 }
252 } 278 }