Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Core/Routing/RouteCompiler.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Core\Routing; | |
4 | |
5 use Symfony\Component\Routing\RouteCompilerInterface; | |
6 use Symfony\Component\Routing\Route; | |
7 use Symfony\Component\Routing\RouteCompiler as SymfonyRouteCompiler; | |
8 | |
9 /** | |
10 * Compiler to generate derived information from a Route necessary for matching. | |
11 */ | |
12 class RouteCompiler extends SymfonyRouteCompiler implements RouteCompilerInterface { | |
13 | |
14 /** | |
15 * Utility constant to use for regular expressions against the path. | |
16 */ | |
17 const REGEX_DELIMITER = '#'; | |
18 | |
19 /** | |
20 * Compiles the current route instance. | |
21 * | |
22 * Because so much of the parent class is private, we need to call the parent | |
23 * class's compile() method and then dissect its return value to build our | |
24 * new compiled object. If upstream gets refactored so we can subclass more | |
25 * easily then this may not be necessary. | |
26 * | |
27 * @param \Symfony\Component\Routing\Route $route | |
28 * A Route instance. | |
29 * | |
30 * @return \Drupal\Core\Routing\CompiledRoute | |
31 * A CompiledRoute instance. | |
32 */ | |
33 public static function compile(Route $route) { | |
34 | |
35 $symfony_compiled = parent::compile($route); | |
36 | |
37 // The Drupal-specific compiled information. | |
38 $stripped_path = static::getPathWithoutDefaults($route); | |
39 $fit = static::getFit($stripped_path); | |
40 $pattern_outline = static::getPatternOutline($stripped_path); | |
41 // We count the number of parts including any optional trailing parts. This | |
42 // allows the RouteProvider to filter candidate routes more efficiently. | |
43 $num_parts = count(explode('/', trim($route->getPath(), '/'))); | |
44 | |
45 return new CompiledRoute( | |
46 $fit, | |
47 $pattern_outline, | |
48 $num_parts, | |
49 | |
50 // The following parameters are what Symfony uses in | |
51 // \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection(). | |
52 | |
53 // Set the static prefix to an empty string since it is redundant to | |
54 // the matching in \Drupal\Core\Routing\RouteProvider::getRoutesByPath() | |
55 // and by skipping it we more easily make the routing case-insensitive. | |
56 '', | |
57 $symfony_compiled->getRegex(), | |
58 $symfony_compiled->getTokens(), | |
59 $symfony_compiled->getPathVariables(), | |
60 $symfony_compiled->getHostRegex(), | |
61 $symfony_compiled->getHostTokens(), | |
62 $symfony_compiled->getHostVariables(), | |
63 $symfony_compiled->getVariables() | |
64 ); | |
65 } | |
66 | |
67 /** | |
68 * Returns the pattern outline. | |
69 * | |
70 * The pattern outline is the path pattern but normalized so that all | |
71 * placeholders are the string '%'. | |
72 * | |
73 * @param string $path | |
74 * The path for which we want the normalized outline. | |
75 * | |
76 * @return string | |
77 * The path pattern outline. | |
78 */ | |
79 public static function getPatternOutline($path) { | |
80 return preg_replace('#\{\w+\}#', '%', $path); | |
81 } | |
82 | |
83 /** | |
84 * Determines the fitness of the provided path. | |
85 * | |
86 * @param string $path | |
87 * The path whose fitness we want. | |
88 * | |
89 * @return int | |
90 * The fitness of the path, as an integer. | |
91 */ | |
92 public static function getFit($path) { | |
93 $parts = explode('/', trim($path, '/')); | |
94 $number_parts = count($parts); | |
95 // We store the highest index of parts here to save some work in the fit | |
96 // calculation loop. | |
97 $slashes = $number_parts - 1; | |
98 // The fit value is a binary number which has 1 at every fixed path | |
99 // position and 0 where there is a wildcard. We keep track of all such | |
100 // patterns that exist so that we can minimize the number of path | |
101 // patterns we need to check in the RouteProvider. | |
102 $fit = 0; | |
103 foreach ($parts as $k => $part) { | |
104 if (strpos($part, '{') === FALSE) { | |
105 $fit |= 1 << ($slashes - $k); | |
106 } | |
107 } | |
108 | |
109 return $fit; | |
110 } | |
111 | |
112 /** | |
113 * Returns the path of the route, without placeholders with a default value. | |
114 * | |
115 * When computing the path outline and fit, we want to skip default-value | |
116 * placeholders. If we didn't, the path would never match. Note that this | |
117 * only works for placeholders at the end of the path. Infix placeholders | |
118 * with default values don't make sense anyway, so that should not be a | |
119 * problem. | |
120 * | |
121 * @param \Symfony\Component\Routing\Route $route | |
122 * The route to have the placeholders removed from. | |
123 * | |
124 * @return string | |
125 * The path string, stripped of placeholders that have default values. | |
126 */ | |
127 public static function getPathWithoutDefaults(Route $route) { | |
128 $path = $route->getPath(); | |
129 $defaults = $route->getDefaults(); | |
130 | |
131 // Remove placeholders with default values from the outline, so that they | |
132 // will still match. | |
133 $remove = array_map(function ($a) { | |
134 return '/{' . $a . '}'; | |
135 }, array_keys($defaults)); | |
136 $path = str_replace($remove, '', $path); | |
137 | |
138 return $path; | |
139 } | |
140 | |
141 } |