|
0
|
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; |
|
|
13 |
|
|
|
14 |
/** |
|
|
15 |
* RouteCompiler compiles Route instances to CompiledRoute instances. |
|
|
16 |
* |
|
|
17 |
* @author Fabien Potencier <fabien@symfony.com> |
|
|
18 |
*/ |
|
|
19 |
class RouteCompiler implements RouteCompilerInterface |
|
|
20 |
{ |
|
|
21 |
/** |
|
|
22 |
* Compiles the current route instance. |
|
|
23 |
* |
|
|
24 |
* @param Route $route A Route instance |
|
|
25 |
* |
|
|
26 |
* @return CompiledRoute A CompiledRoute instance |
|
|
27 |
*/ |
|
|
28 |
public function compile(Route $route) |
|
|
29 |
{ |
|
|
30 |
$pattern = $route->getPattern(); |
|
|
31 |
$len = strlen($pattern); |
|
|
32 |
$tokens = array(); |
|
|
33 |
$variables = array(); |
|
|
34 |
$pos = 0; |
|
|
35 |
preg_match_all('#.\{([\w\d_]+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); |
|
|
36 |
foreach ($matches as $match) { |
|
|
37 |
if ($text = substr($pattern, $pos, $match[0][1] - $pos)) { |
|
|
38 |
$tokens[] = array('text', $text); |
|
|
39 |
} |
|
|
40 |
$seps = array($pattern[$pos]); |
|
|
41 |
$pos = $match[0][1] + strlen($match[0][0]); |
|
|
42 |
$var = $match[1][0]; |
|
|
43 |
|
|
|
44 |
if ($req = $route->getRequirement($var)) { |
|
|
45 |
$regexp = $req; |
|
|
46 |
} else { |
|
|
47 |
if ($pos !== $len) { |
|
|
48 |
$seps[] = $pattern[$pos]; |
|
|
49 |
} |
|
|
50 |
$regexp = sprintf('[^%s]+?', preg_quote(implode('', array_unique($seps)), '#')); |
|
|
51 |
} |
|
|
52 |
|
|
|
53 |
$tokens[] = array('variable', $match[0][0][0], $regexp, $var); |
|
|
54 |
$variables[] = $var; |
|
|
55 |
} |
|
|
56 |
|
|
|
57 |
if ($pos < $len) { |
|
|
58 |
$tokens[] = array('text', substr($pattern, $pos)); |
|
|
59 |
} |
|
|
60 |
|
|
|
61 |
// find the first optional token |
|
|
62 |
$firstOptional = INF; |
|
|
63 |
for ($i = count($tokens) - 1; $i >= 0; $i--) { |
|
|
64 |
if ('variable' === $tokens[$i][0] && $route->hasDefault($tokens[$i][3])) { |
|
|
65 |
$firstOptional = $i; |
|
|
66 |
} else { |
|
|
67 |
break; |
|
|
68 |
} |
|
|
69 |
} |
|
|
70 |
|
|
|
71 |
// compute the matching regexp |
|
|
72 |
$regex = ''; |
|
|
73 |
$indent = 1; |
|
|
74 |
if (1 === count($tokens) && 0 === $firstOptional) { |
|
|
75 |
$token = $tokens[0]; |
|
|
76 |
++$indent; |
|
|
77 |
$regex .= str_repeat(' ', $indent * 4).sprintf("%s(?:\n", preg_quote($token[1], '#')); |
|
|
78 |
$regex .= str_repeat(' ', $indent * 4).sprintf("(?P<%s>%s)\n", $token[3], $token[2]); |
|
|
79 |
} else { |
|
|
80 |
foreach ($tokens as $i => $token) { |
|
|
81 |
if ('text' === $token[0]) { |
|
|
82 |
$regex .= str_repeat(' ', $indent * 4).preg_quote($token[1], '#')."\n"; |
|
|
83 |
} else { |
|
|
84 |
if ($i >= $firstOptional) { |
|
|
85 |
$regex .= str_repeat(' ', $indent * 4)."(?:\n"; |
|
|
86 |
++$indent; |
|
|
87 |
} |
|
|
88 |
$regex .= str_repeat(' ', $indent * 4).sprintf("%s(?P<%s>%s)\n", preg_quote($token[1], '#'), $token[3], $token[2]); |
|
|
89 |
} |
|
|
90 |
} |
|
|
91 |
} |
|
|
92 |
while (--$indent) { |
|
|
93 |
$regex .= str_repeat(' ', $indent * 4).")?\n"; |
|
|
94 |
} |
|
|
95 |
|
|
|
96 |
return new CompiledRoute( |
|
|
97 |
$route, |
|
|
98 |
'text' === $tokens[0][0] ? $tokens[0][1] : '', |
|
|
99 |
sprintf("#^\n%s$#x", $regex), |
|
|
100 |
array_reverse($tokens), |
|
|
101 |
$variables |
|
|
102 |
); |
|
|
103 |
} |
|
|
104 |
} |