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 8f70316

Browse filesBrowse files
committed
[Routing] Convert static variables to text on compilation for generator
1 parent cde44fc commit 8f70316
Copy full SHA for 8f70316

File tree

6 files changed

+132
-36
lines changed
Filter options

6 files changed

+132
-36
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ private function groupStaticRoutes(RouteCollection $collection): array
170170
$dynamicRoutes = new RouteCollection();
171171

172172
foreach ($collection->all() as $name => $route) {
173-
$compiledRoute = $route->compile();
173+
$compiledRoute = $route->compile(true);
174174
$staticPrefix = rtrim($compiledRoute->getStaticPrefix(), '/');
175175
$hostRegex = $compiledRoute->getHostRegex();
176176
$regex = $compiledRoute->getRegex();
@@ -182,7 +182,9 @@ private function groupStaticRoutes(RouteCollection $collection): array
182182

183183
if (!$compiledRoute->getPathVariables()) {
184184
$host = !$compiledRoute->getHostVariables() ? $route->getHost() : '';
185-
$url = $route->getPath();
185+
$url = preg_replace_callback('#{([^}]+)}#', static function (array $matches) use ($route) {
186+
return $route->getRequirement($matches[1]);
187+
}, $route->getPath());
186188
if ($hasTrailingSlash) {
187189
$url = substr($url, 0, -1);
188190
}

‎src/Symfony/Component/Routing/Route.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Route.php
+53-20Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@ class Route implements \Serializable
2929
private $condition = '';
3030

3131
/**
32-
* @var CompiledRoute|null
32+
* @var CompiledRoute|null Route compiled for the matcher
3333
*/
34-
private $compiled;
34+
private $matcherCompiled;
35+
36+
/**
37+
* @var CompiledRoute|null Route compiled for the generator
38+
*/
39+
private $generatorCompiled;
3540

3641
/**
3742
* Constructor.
@@ -73,7 +78,8 @@ public function __serialize(): array
7378
'schemes' => $this->schemes,
7479
'methods' => $this->methods,
7580
'condition' => $this->condition,
76-
'compiled' => $this->compiled,
81+
'matcherCompiled' => $this->matcherCompiled,
82+
'generatorCompiled' => $this->generatorCompiled,
7783
];
7884
}
7985

@@ -98,8 +104,15 @@ public function __unserialize(array $data): void
98104
if (isset($data['condition'])) {
99105
$this->condition = $data['condition'];
100106
}
107+
if (isset($data['matcherCompiled'])) {
108+
$this->matcherCompiled = $data['matcherCompiled'];
109+
}
110+
if (isset($data['generatorCompiled'])) {
111+
$this->generatorCompiled = $data['generatorCompiled'];
112+
}
113+
// Make serialized representation of a route in older symfony version also works in current
101114
if (isset($data['compiled'])) {
102-
$this->compiled = $data['compiled'];
115+
$this->matcherCompiled = $data['compiled'];
103116
}
104117
}
105118

@@ -146,7 +159,8 @@ public function setPath(string $pattern)
146159
// A pattern must start with a slash and must not have multiple slashes at the beginning because the
147160
// generated path for this route would be confused with a network path, e.g. '//domain.com/path'.
148161
$this->path = '/'.ltrim(trim($pattern), '/');
149-
$this->compiled = null;
162+
$this->matcherCompiled = null;
163+
$this->generatorCompiled = null;
150164

151165
return $this;
152166
}
@@ -171,7 +185,8 @@ public function getHost()
171185
public function setHost(?string $pattern)
172186
{
173187
$this->host = (string) $pattern;
174-
$this->compiled = null;
188+
$this->matcherCompiled = null;
189+
$this->generatorCompiled = null;
175190

176191
return $this;
177192
}
@@ -200,7 +215,8 @@ public function getSchemes()
200215
public function setSchemes($schemes)
201216
{
202217
$this->schemes = array_map('strtolower', (array) $schemes);
203-
$this->compiled = null;
218+
$this->matcherCompiled = null;
219+
$this->generatorCompiled = null;
204220

205221
return $this;
206222
}
@@ -239,7 +255,8 @@ public function getMethods()
239255
public function setMethods($methods)
240256
{
241257
$this->methods = array_map('strtoupper', (array) $methods);
242-
$this->compiled = null;
258+
$this->matcherCompiled = null;
259+
$this->generatorCompiled = null;
243260

244261
return $this;
245262
}
@@ -282,7 +299,8 @@ public function addOptions(array $options)
282299
foreach ($options as $name => $option) {
283300
$this->options[$name] = $option;
284301
}
285-
$this->compiled = null;
302+
$this->matcherCompiled = null;
303+
$this->generatorCompiled = null;
286304

287305
return $this;
288306
}
@@ -299,7 +317,8 @@ public function addOptions(array $options)
299317
public function setOption(string $name, $value)
300318
{
301319
$this->options[$name] = $value;
302-
$this->compiled = null;
320+
$this->matcherCompiled = null;
321+
$this->generatorCompiled = null;
303322

304323
return $this;
305324
}
@@ -364,7 +383,8 @@ public function addDefaults(array $defaults)
364383
foreach ($defaults as $name => $default) {
365384
$this->defaults[$name] = $default;
366385
}
367-
$this->compiled = null;
386+
$this->matcherCompiled = null;
387+
$this->generatorCompiled = null;
368388

369389
return $this;
370390
}
@@ -399,7 +419,8 @@ public function hasDefault(string $name)
399419
public function setDefault(string $name, $default)
400420
{
401421
$this->defaults[$name] = $default;
402-
$this->compiled = null;
422+
$this->matcherCompiled = null;
423+
$this->generatorCompiled = null;
403424

404425
return $this;
405426
}
@@ -444,7 +465,8 @@ public function addRequirements(array $requirements)
444465
foreach ($requirements as $key => $regex) {
445466
$this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
446467
}
447-
$this->compiled = null;
468+
$this->matcherCompiled = null;
469+
$this->generatorCompiled = null;
448470

449471
return $this;
450472
}
@@ -477,7 +499,8 @@ public function hasRequirement(string $key)
477499
public function setRequirement(string $key, string $regex)
478500
{
479501
$this->requirements[$key] = $this->sanitizeRequirement($key, $regex);
480-
$this->compiled = null;
502+
$this->matcherCompiled = null;
503+
$this->generatorCompiled = null;
481504

482505
return $this;
483506
}
@@ -502,30 +525,40 @@ public function getCondition()
502525
public function setCondition(?string $condition)
503526
{
504527
$this->condition = (string) $condition;
505-
$this->compiled = null;
528+
$this->matcherCompiled = null;
529+
$this->generatorCompiled = null;
506530

507531
return $this;
508532
}
509533

510534
/**
511535
* Compiles the route.
512536
*
537+
* @param bool $forGenerator If the route should be compiler for the generator
513538
* @return CompiledRoute A CompiledRoute instance
514539
*
515540
* @throws \LogicException If the Route cannot be compiled because the
516541
* path or host pattern is invalid
517542
*
518543
* @see RouteCompiler which is responsible for the compilation process
519544
*/
520-
public function compile()
545+
public function compile(bool $forGenerator = false)
521546
{
522-
if (null !== $this->compiled) {
523-
return $this->compiled;
547+
$class = $this->getOption('compiler_class');
548+
549+
if ($forGenerator) {
550+
if (null !== $this->generatorCompiled) {
551+
return $this->generatorCompiled;
552+
}
553+
554+
return $this->generatorCompiled = $class::compile($this, true);
524555
}
525556

526-
$class = $this->getOption('compiler_class');
557+
if (null !== $this->matcherCompiled) {
558+
return $this->matcherCompiled;
559+
}
527560

528-
return $this->compiled = $class::compile($this);
561+
return $this->matcherCompiled = $class::compile($this, false);
529562
}
530563

531564
private function sanitizeRequirement(string $key, string $regex)

‎src/Symfony/Component/Routing/RouteCompiler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/RouteCompiler.php
+30-3Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@ class RouteCompiler implements RouteCompilerInterface
4444
* @throws \DomainException if a variable name starts with a digit or if it is too long to be successfully used as
4545
* a PCRE subpattern
4646
*/
47-
public static function compile(Route $route)
47+
public static function compile(Route $route /**, bool $fixStaticVariables = false */)
4848
{
4949
$hostVariables = [];
5050
$variables = [];
5151
$hostRegex = null;
5252
$hostTokens = [];
5353

54+
$fixStaticVariables = 1 < \func_num_args() ? (int) func_get_arg(1) : false;
55+
5456
if ('' !== $host = $route->getHost()) {
5557
$result = self::compilePattern($route, $host, true);
5658

@@ -63,7 +65,7 @@ public static function compile(Route $route)
6365

6466
$path = $route->getPath();
6567

66-
$result = self::compilePattern($route, $path, false);
68+
$result = self::compilePattern($route, $path, false, $fixStaticVariables);
6769

6870
$staticPrefix = $result['staticPrefix'];
6971

@@ -92,7 +94,7 @@ public static function compile(Route $route)
9294
);
9395
}
9496

95-
private static function compilePattern(Route $route, string $pattern, bool $isHost): array
97+
private static function compilePattern(Route $route, string $pattern, bool $isHost, bool $fixStaticVariables = false): array
9698
{
9799
$tokens = [];
98100
$variables = [];
@@ -184,6 +186,12 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo
184186
$regexp = self::transformCapturingGroupsToNonCapturings($regexp);
185187
}
186188

189+
// Fixed variable, could be transformed as text token
190+
if ($fixStaticVariables && preg_quote($regexp, self::REGEX_DELIMITER) === $regexp) {
191+
$tokens[] = ['text', ($isSeparator ? $precedingChar : '').$regexp];
192+
continue;
193+
}
194+
187195
if ($important) {
188196
$token = ['variable', $isSeparator ? $precedingChar : '', $regexp, $varName, false, true];
189197
} else {
@@ -198,6 +206,10 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo
198206
$tokens[] = ['text', substr($pattern, $pos)];
199207
}
200208

209+
if ($fixStaticVariables) {
210+
$tokens = self::mergeContiguousTextTokens($tokens);
211+
}
212+
201213
// find the first optional token
202214
$firstOptional = PHP_INT_MAX;
203215
if (!$isHost) {
@@ -237,6 +249,21 @@ private static function compilePattern(Route $route, string $pattern, bool $isHo
237249
];
238250
}
239251

252+
private static function mergeContiguousTextTokens(array $tokens): array
253+
{
254+
$mergedTokens = [$tokens[0]];
255+
for ($i = 1; $i < \count($tokens); ++$i) {
256+
if ('text' !== $tokens[$i][0] || 'variable' === end($mergedTokens)[0]) {
257+
$mergedTokens[] = $tokens[$i];
258+
continue;
259+
}
260+
261+
$mergedTokens[\count($mergedTokens) - 1][1] .= $tokens[$i][1];
262+
}
263+
264+
return $mergedTokens;
265+
}
266+
240267
/**
241268
* Determines the longest static prefix possible for a route.
242269
*/

‎src/Symfony/Component/Routing/RouteCompilerInterface.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/RouteCompilerInterface.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ interface RouteCompilerInterface
2121
/**
2222
* Compiles the current route instance.
2323
*
24+
* @param $fixStaticVariables Tell the compiler to convert static variables to text
2425
* @return CompiledRoute A CompiledRoute instance
2526
*
2627
* @throws \LogicException If the Route cannot be compiled because the
2728
* path or host pattern is invalid
2829
*/
29-
public static function compile(Route $route);
30+
public static function compile(Route $route /**, bool $fixStaticVariables = false */);
3031
}

‎src/Symfony/Component/Routing/Tests/Fixtures/dumper/compiled_url_matcher8.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/dumper/compiled_url_matcher8.php
+5-8Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,19 @@
88
return [
99
false, // $matchHost
1010
[ // $staticRoutes
11+
'/a' => [[['_route' => 'a'], null, null, null, false, false, null]],
1112
],
1213
[ // $regexpList
1314
0 => '{^(?'
14-
.'|/(a)(*:11)'
15-
.')/?$}sD',
15+
.'|/(.)(*:11)'
16+
.')/?$}sDu',
1617
11 => '{^(?'
1718
.'|/(.)(*:22)'
18-
.')/?$}sDu',
19-
22 => '{^(?'
20-
.'|/(.)(*:33)'
2119
.')/?$}sD',
2220
],
2321
[ // $dynamicRoutes
24-
11 => [[['_route' => 'a'], ['a'], null, null, false, true, null]],
25-
22 => [[['_route' => 'b'], ['a'], null, null, false, true, null]],
26-
33 => [
22+
11 => [[['_route' => 'b'], ['a'], null, null, false, true, null]],
23+
22 => [
2724
[['_route' => 'c'], ['a'], null, null, false, true, null],
2825
[null, null, null, null, false, false, 0],
2926
],

0 commit comments

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