Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
100.00% |
1 / 1 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
29 / 29 |
| RouteCompiler | |
100.00% |
1 / 1 |
|
100.00% |
5 / 5 |
7 | |
100.00% |
29 / 29 |
| compile | |
100.00% |
1 / 1 |
1 | |
100.00% |
14 / 14 |
|||
| getPatternOutline | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| getFit | |
100.00% |
1 / 1 |
3 | |
100.00% |
8 / 8 |
|||
| getPathWithoutDefaults | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| anonymous function | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Core\Routing\RouteCompiler. | |
| */ | |
| namespace Drupal\Core\Routing; | |
| use Symfony\Component\Routing\RouteCompilerInterface; | |
| use Symfony\Component\Routing\Route; | |
| use Symfony\Component\Routing\RouteCompiler as SymfonyRouteCompiler; | |
| /** | |
| * Compiler to generate derived information from a Route necessary for matching. | |
| */ | |
| class RouteCompiler extends SymfonyRouteCompiler implements RouteCompilerInterface { | |
| /** | |
| * Utility constant to use for regular expressions against the path. | |
| */ | |
| const REGEX_DELIMITER = '#'; | |
| /** | |
| * Compiles the current route instance. | |
| * | |
| * Because so much of the parent class is private, we need to call the parent | |
| * class's compile() method and then dissect its return value to build our | |
| * new compiled object. If upstream gets refactored so we can subclass more | |
| * easily then this may not be necessary. | |
| * | |
| * @param \Symfony\Component\Routing\Route $route | |
| * A Route instance. | |
| * | |
| * @return \Drupal\Core\Routing\CompiledRoute | |
| * A CompiledRoute instance. | |
| */ | |
| public static function compile(Route $route) { | |
| $symfony_compiled = parent::compile($route); | |
| // The Drupal-specific compiled information. | |
| $stripped_path = static::getPathWithoutDefaults($route); | |
| $fit = static::getFit($stripped_path); | |
| $pattern_outline = static::getPatternOutline($stripped_path); | |
| // We count the number of parts including any optional trailing parts. This | |
| // allows the RouteProvider to filter candidate routes more efficiently. | |
| $num_parts = count(explode('/', trim($route->getPath(), '/'))); | |
| return new CompiledRoute( | |
| $fit, | |
| $pattern_outline, | |
| $num_parts, | |
| // These are the Symfony compiled parts. | |
| $symfony_compiled->getStaticPrefix(), | |
| $symfony_compiled->getRegex(), | |
| $symfony_compiled->getTokens(), | |
| $symfony_compiled->getPathVariables(), | |
| $symfony_compiled->getHostRegex(), | |
| $symfony_compiled->getHostTokens(), | |
| $symfony_compiled->getHostVariables(), | |
| $symfony_compiled->getVariables() | |
| ); | |
| } | |
| /** | |
| * Returns the pattern outline. | |
| * | |
| * The pattern outline is the path pattern but normalized so that all | |
| * placeholders are equal strings and default values are removed. | |
| * | |
| * @param string $path | |
| * The path for which we want the normalized outline. | |
| * | |
| * @return string | |
| * The path pattern outline. | |
| */ | |
| public static function getPatternOutline($path) { | |
| return preg_replace('#\{\w+\}#', '%', $path); | |
| } | |
| /** | |
| * Determines the fitness of the provided path. | |
| * | |
| * @param string $path | |
| * The path whose fitness we want. | |
| * | |
| * @return int | |
| * The fitness of the path, as an integer. | |
| */ | |
| public static function getFit($path) { | |
| $parts = explode('/', trim($path, '/')); | |
| $number_parts = count($parts); | |
| // We store the highest index of parts here to save some work in the fit | |
| // calculation loop. | |
| $slashes = $number_parts - 1; | |
| // The fit value is a binary number which has 1 at every fixed path | |
| // position and 0 where there is a wildcard. We keep track of all such | |
| // patterns that exist so that we can minimize the number of path | |
| // patterns we need to check in the RouteProvider. | |
| $fit = 0; | |
| foreach ($parts as $k => $part) { | |
| if (strpos($part, '{') === FALSE) { | |
| $fit |= 1 << ($slashes - $k); | |
| } | |
| } | |
| return $fit; | |
| } | |
| /** | |
| * Returns the path of the route, without placeholders with a default value. | |
| * | |
| * When computing the path outline and fit, we want to skip default-value | |
| * placeholders. If we didn't, the path would never match. Note that this | |
| * only works for placeholders at the end of the path. Infix placeholders | |
| * with default values don't make sense anyway, so that should not be a | |
| * problem. | |
| * | |
| * @param \Symfony\Component\Routing\Route $route | |
| * The route to have the placeholders removed from. | |
| * | |
| * @return string | |
| * The path string, stripped of placeholders that have default values. | |
| */ | |
| public static function getPathWithoutDefaults(Route $route) { | |
| $path = $route->getPath(); | |
| $defaults = $route->getDefaults(); | |
| // Remove placeholders with default values from the outline, so that they | |
| // will still match. | |
| $remove = array_map(function($a) { | |
| return '/{' . $a . '}'; | |
| }, array_keys($defaults)); | |
| $path = str_replace($remove, '', $path); | |
| return $path; | |
| } | |
| } |