public function RouteCompiler::getRegex

Generates a regular expression that will match this pattern.

This regex can be used in preg_match() to extract values inside {}.

This algorithm was lifted directly from Symfony's RouteCompiler class. It is not factored out nicely there, so we cannot simply subclass it. @todo Refactor Symfony's RouteCompiler so that it's useful to subclass.

Parameters

\Symfony\Component\Routing\Route $route: The route object.

string $pattern: The pattern for which we want a matching regex.

Return value

string A regular expression that will match a path against this route.

Throws

\LogicException

1 call to RouteCompiler::getRegex()
RouteCompiler::compile in drupal/core/lib/Drupal/Core/Routing/RouteCompiler.php
Compiles the current route instance.

File

drupal/core/lib/Drupal/Core/Routing/RouteCompiler.php, line 71
Definition of Drupal\Core\Routing\RouteCompiler.

Class

RouteCompiler
Compiler to generate derived information from a Route necessary for matching.

Namespace

Drupal\Core\Routing

Code

public function getRegex(Route $route, $pattern) {
  $len = strlen($pattern);
  $tokens = array();
  $variables = array();
  $pos = 0;
  preg_match_all('#.\\{(\\w+)\\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  foreach ($matches as $match) {
    if ($text = substr($pattern, $pos, $match[0][1] - $pos)) {
      $tokens[] = array(
        'text',
        $text,
      );
    }
    $pos = $match[0][1] + strlen($match[0][0]);
    $var = $match[1][0];
    if ($req = $route
      ->getRequirement($var)) {
      $regexp = $req;
    }
    else {

      // Use the character preceding the variable as a separator
      $separators = array(
        $match[0][0][0],
      );
      if ($pos !== $len) {

        // Use the character following the variable as the separator when available
        $separators[] = $pattern[$pos];
      }
      $regexp = sprintf('[^%s]+', preg_quote(implode('', array_unique($separators)), self::REGEX_DELIMITER));
    }
    $tokens[] = array(
      'variable',
      $match[0][0][0],
      $regexp,
      $var,
    );
    if (in_array($var, $variables)) {
      throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $route
        ->getPattern(), $var));
    }
    $variables[] = $var;
  }
  if ($pos < $len) {
    $tokens[] = array(
      'text',
      substr($pattern, $pos),
    );
  }

  // find the first optional token
  $first_optional = INF;
  for ($i = count($tokens) - 1; $i >= 0; $i--) {
    $token = $tokens[$i];
    if ('variable' === $token[0] && $route
      ->hasDefault($token[3])) {
      $first_optional = $i;
    }
    else {
      break;
    }
  }

  // compute the matching regexp
  $regexp = '';
  for ($i = 0, $nbToken = count($tokens); $i < $nbToken; $i++) {
    $regexp .= $this
      ->computeRegexp($tokens, $i, $first_optional);
  }
  return self::REGEX_DELIMITER . '^' . $regexp . '$' . self::REGEX_DELIMITER . 's';
}