Chris@0: setOption('utf8', TRUE); Chris@0: $symfony_compiled = parent::compile($route); Chris@0: Chris@0: // The Drupal-specific compiled information. Chris@0: $stripped_path = static::getPathWithoutDefaults($route); Chris@0: $fit = static::getFit($stripped_path); Chris@0: $pattern_outline = static::getPatternOutline($stripped_path); Chris@0: // We count the number of parts including any optional trailing parts. This Chris@0: // allows the RouteProvider to filter candidate routes more efficiently. Chris@0: $num_parts = count(explode('/', trim($route->getPath(), '/'))); Chris@0: Chris@0: return new CompiledRoute( Chris@0: $fit, Chris@0: $pattern_outline, Chris@0: $num_parts, Chris@0: Chris@0: // The following parameters are what Symfony uses in Chris@0: // \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection(). Chris@0: Chris@0: // Set the static prefix to an empty string since it is redundant to Chris@0: // the matching in \Drupal\Core\Routing\RouteProvider::getRoutesByPath() Chris@0: // and by skipping it we more easily make the routing case-insensitive. Chris@0: '', Chris@0: $symfony_compiled->getRegex(), Chris@0: $symfony_compiled->getTokens(), Chris@0: $symfony_compiled->getPathVariables(), Chris@0: $symfony_compiled->getHostRegex(), Chris@0: $symfony_compiled->getHostTokens(), Chris@0: $symfony_compiled->getHostVariables(), Chris@0: $symfony_compiled->getVariables() Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the pattern outline. Chris@0: * Chris@0: * The pattern outline is the path pattern but normalized so that all Chris@0: * placeholders are the string '%'. Chris@0: * Chris@0: * @param string $path Chris@0: * The path for which we want the normalized outline. Chris@0: * Chris@0: * @return string Chris@0: * The path pattern outline. Chris@0: */ Chris@0: public static function getPatternOutline($path) { Chris@0: return preg_replace('#\{\w+\}#', '%', $path); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines the fitness of the provided path. Chris@0: * Chris@0: * @param string $path Chris@0: * The path whose fitness we want. Chris@0: * Chris@0: * @return int Chris@0: * The fitness of the path, as an integer. Chris@0: */ Chris@0: public static function getFit($path) { Chris@0: $parts = explode('/', trim($path, '/')); Chris@0: $number_parts = count($parts); Chris@0: // We store the highest index of parts here to save some work in the fit Chris@0: // calculation loop. Chris@0: $slashes = $number_parts - 1; Chris@0: // The fit value is a binary number which has 1 at every fixed path Chris@0: // position and 0 where there is a wildcard. We keep track of all such Chris@0: // patterns that exist so that we can minimize the number of path Chris@0: // patterns we need to check in the RouteProvider. Chris@0: $fit = 0; Chris@0: foreach ($parts as $k => $part) { Chris@0: if (strpos($part, '{') === FALSE) { Chris@0: $fit |= 1 << ($slashes - $k); Chris@0: } Chris@0: } Chris@0: Chris@0: return $fit; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the path of the route, without placeholders with a default value. Chris@0: * Chris@0: * When computing the path outline and fit, we want to skip default-value Chris@0: * placeholders. If we didn't, the path would never match. Note that this Chris@0: * only works for placeholders at the end of the path. Infix placeholders Chris@0: * with default values don't make sense anyway, so that should not be a Chris@0: * problem. Chris@0: * Chris@0: * @param \Symfony\Component\Routing\Route $route Chris@0: * The route to have the placeholders removed from. Chris@0: * Chris@0: * @return string Chris@0: * The path string, stripped of placeholders that have default values. Chris@0: */ Chris@0: public static function getPathWithoutDefaults(Route $route) { Chris@0: $path = $route->getPath(); Chris@0: $defaults = $route->getDefaults(); Chris@0: Chris@0: // Remove placeholders with default values from the outline, so that they Chris@0: // will still match. Chris@0: $remove = array_map(function ($a) { Chris@0: return '/{' . $a . '}'; Chris@0: }, array_keys($defaults)); Chris@0: $path = str_replace($remove, '', $path); Chris@0: Chris@0: return $path; Chris@0: } Chris@0: Chris@0: }