Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0ea1adf

Browse filesBrowse files
committed
minor #28798 [Routing] simplify PhpMatcherDumper by splitting code logic from route data (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- [Routing] simplify PhpMatcherDumper by splitting code logic from route data | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This PR splits all logic that is currently dumped into the matcher in a dedicated trait. This makes the code easier to maintain and prepares for the next step (making the dumper compile routes as a set of PHP arrays instead of code.) This diff is huge because affected fixtures are also huge, but it's negative, removing 1200 lines! Commits ------- 22186c7 [Routing] simplify PhpMatcherDumper by splitting code logic from route data
2 parents 6de1577 + 22186c7 commit 0ea1adf
Copy full SHA for 0ea1adf

16 files changed

+1503
-2717
lines changed

‎src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
+73-376Lines changed: 73 additions & 376 deletions
Large diffs are not rendered by default.
+156Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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\Dumper;
13+
14+
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15+
use Symfony\Component\Routing\Exception\NoConfigurationException;
16+
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
17+
use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
18+
19+
/**
20+
* @author Nicolas Grekas <p@tchwork.com>
21+
*
22+
* @internal
23+
*/
24+
trait PhpMatcherTrait
25+
{
26+
private $matchHost = false;
27+
private $staticRoutes = array();
28+
private $regexpList = array();
29+
private $dynamicRoutes = array();
30+
private $checkCondition;
31+
32+
public function match($pathinfo)
33+
{
34+
$allow = $allowSchemes = array();
35+
if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
36+
return $ret;
37+
}
38+
if ($allow) {
39+
throw new MethodNotAllowedException(array_keys($allow));
40+
}
41+
if (!$this instanceof RedirectableUrlMatcherInterface) {
42+
throw new ResourceNotFoundException();
43+
}
44+
if (!\in_array($this->context->getMethod(), array('HEAD', 'GET'), true)) {
45+
// no-op
46+
} elseif ($allowSchemes) {
47+
redirect_scheme:
48+
$scheme = $this->context->getScheme();
49+
$this->context->setScheme(key($allowSchemes));
50+
try {
51+
if ($ret = $this->doMatch($pathinfo)) {
52+
return $this->redirect($pathinfo, $ret['_route'], $this->context->getScheme()) + $ret;
53+
}
54+
} finally {
55+
$this->context->setScheme($scheme);
56+
}
57+
} elseif ('/' !== $pathinfo) {
58+
$pathinfo = '/' !== $pathinfo[-1] ? $pathinfo.'/' : substr($pathinfo, 0, -1);
59+
if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
60+
return $this->redirect($pathinfo, $ret['_route']) + $ret;
61+
}
62+
if ($allowSchemes) {
63+
goto redirect_scheme;
64+
}
65+
}
66+
67+
throw new ResourceNotFoundException();
68+
}
69+
70+
private function doMatch(string $rawPathinfo, array &$allow = array(), array &$allowSchemes = array()): ?array
71+
{
72+
$allow = $allowSchemes = array();
73+
$pathinfo = rawurldecode($rawPathinfo);
74+
$context = $this->context;
75+
$requestMethod = $canonicalMethod = $context->getMethod();
76+
77+
if ($this->matchHost) {
78+
$host = strtolower($context->getHost());
79+
}
80+
81+
if ('HEAD' === $requestMethod) {
82+
$canonicalMethod = 'GET';
83+
}
84+
85+
foreach ($this->staticRoutes[$pathinfo] ?? array() as list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $condition)) {
86+
if ($condition && !($this->checkCondition)($condition, $context, 0 < $condition ? $request ?? $request = $this->request ?: $this->createRequest($pathinfo) : null)) {
87+
continue;
88+
}
89+
90+
if ($requiredHost) {
91+
if ('#' !== $requiredHost[0] ? $requiredHost !== $host : !preg_match($requiredHost, $host, $hostMatches)) {
92+
continue;
93+
}
94+
if ('#' === $requiredHost[0] && $hostMatches) {
95+
$hostMatches['_route'] = $ret['_route'];
96+
$ret = $this->mergeDefaults($hostMatches, $ret);
97+
}
98+
}
99+
100+
$hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
101+
if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
102+
if ($hasRequiredScheme) {
103+
$allow += $requiredMethods;
104+
}
105+
continue;
106+
}
107+
if (!$hasRequiredScheme) {
108+
$allowSchemes += $requiredSchemes;
109+
continue;
110+
}
111+
112+
return $ret;
113+
}
114+
115+
$matchedPathinfo = $this->matchHost ? $host.'.'.$pathinfo : $pathinfo;
116+
117+
foreach ($this->regexpList as $offset => $regex) {
118+
while (preg_match($regex, $matchedPathinfo, $matches)) {
119+
foreach ($this->dynamicRoutes[$m = (int) $matches['MARK']] as list($ret, $vars, $requiredMethods, $requiredSchemes, $condition)) {
120+
if ($condition && !($this->checkCondition)($condition, $context, 0 < $condition ? $request ?? $request = $this->request ?: $this->createRequest($pathinfo) : null)) {
121+
continue;
122+
}
123+
124+
foreach ($vars as $i => $v) {
125+
if (isset($matches[1 + $i])) {
126+
$ret[$v] = $matches[1 + $i];
127+
}
128+
}
129+
130+
$hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
131+
if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
132+
if ($hasRequiredScheme) {
133+
$allow += $requiredMethods;
134+
}
135+
continue;
136+
}
137+
if (!$hasRequiredScheme) {
138+
$allowSchemes += $requiredSchemes;
139+
continue;
140+
}
141+
142+
return $ret;
143+
}
144+
145+
$regex = substr_replace($regex, 'F', $m - $offset, 1 + \strlen($m));
146+
$offset += \strlen($m);
147+
}
148+
}
149+
150+
if ('/' === $pathinfo && !$allow && !$allowSchemes) {
151+
throw new NoConfigurationException();
152+
}
153+
154+
return null;
155+
}
156+
}
+3-20Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<?php
22

3-
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
4-
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
3+
use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherTrait;
54
use Symfony\Component\Routing\RequestContext;
65

76
/**
@@ -10,26 +9,10 @@
109
*/
1110
class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
1211
{
12+
use PhpMatcherTrait;
13+
1314
public function __construct(RequestContext $context)
1415
{
1516
$this->context = $context;
1617
}
17-
18-
public function match($rawPathinfo)
19-
{
20-
$allow = $allowSchemes = array();
21-
$pathinfo = rawurldecode($rawPathinfo);
22-
$context = $this->context;
23-
$requestMethod = $canonicalMethod = $context->getMethod();
24-
25-
if ('HEAD' === $requestMethod) {
26-
$canonicalMethod = 'GET';
27-
}
28-
29-
if ('/' === $pathinfo && !$allow && !$allowSchemes) {
30-
throw new Symfony\Component\Routing\Exception\NoConfigurationException();
31-
}
32-
33-
throw $allow ? new MethodNotAllowedException(array_keys($allow)) : new ResourceNotFoundException();
34-
}
3518
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.