You are here

public function UrlGenerator::generateFromRoute in Drupal 10

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Routing/UrlGenerator.php \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
  2. 9 core/lib/Drupal/Core/Routing/UrlGenerator.php \Drupal\Core\Routing\UrlGenerator::generateFromRoute()

File

core/lib/Drupal/Core/Routing/UrlGenerator.php, line 264

Class

UrlGenerator
Generates URLs from route names and parameters.

Namespace

Drupal\Core\Routing

Code

public function generateFromRoute($name, $parameters = [], $options = [], $collect_bubbleable_metadata = FALSE) {
  $options += [
    'prefix' => '',
  ];
  if (!isset($options['query']) || !is_array($options['query'])) {
    $options['query'] = [];
  }
  $route = $this
    ->getRoute($name);
  $generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL;
  $fragment = '';
  if (isset($options['fragment'])) {
    if (($fragment = trim($options['fragment'])) != '') {
      $fragment = '#' . $fragment;
    }
  }

  // Generate a relative URL having no path, just query string and fragment.
  if ($route
    ->getOption('_no_path')) {
    $query = $options['query'] ? '?' . UrlHelper::buildQuery($options['query']) : '';
    $url = $query . $fragment;
    return $collect_bubbleable_metadata ? $generated_url
      ->setGeneratedUrl($url) : $url;
  }
  $options += $route
    ->getOption('default_url_options') ?: [];
  $options += [
    'prefix' => '',
    'path_processing' => TRUE,
  ];
  $name = $this
    ->getRouteDebugMessage($name);
  $this
    ->processRoute($name, $route, $parameters, $generated_url);
  $path = $this
    ->getInternalPathFromRoute($name, $route, $parameters, $options['query']);

  // Outbound path processors might need the route object for the path, e.g.
  // to get the path pattern.
  $options['route'] = $route;
  if ($options['path_processing']) {
    $path = $this
      ->processPath($path, $options, $generated_url);
  }

  // Ensure the resulting path has at most one leading slash, to prevent it
  // becoming an external URL without a protocol like //example.com.
  if (strpos($path, '//') === 0) {
    $path = '/' . ltrim($path, '/');
  }

  // The contexts base URL is already encoded
  // (see Symfony\Component\HttpFoundation\Request).
  $path = str_replace($this->decodedChars[0], $this->decodedChars[1], rawurlencode($path));

  // Drupal paths rarely include dots, so skip this processing if possible.
  if (strpos($path, '/.') !== FALSE) {

    // the path segments "." and ".." are interpreted as relative reference when
    // resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
    // so we need to encode them as they are not used for this purpose here
    // otherwise we would generate a URI that, when followed by a user agent
    // (e.g. browser), does not match this route
    $path = strtr($path, [
      '/../' => '/%2E%2E/',
      '/./' => '/%2E/',
    ]);
    if ('/..' === substr($path, -3)) {
      $path = substr($path, 0, -2) . '%2E%2E';
    }
    elseif ('/.' === substr($path, -2)) {
      $path = substr($path, 0, -1) . '%2E';
    }
  }
  if (!empty($options['prefix'])) {
    $path = ltrim($path, '/');
    $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
    $path = '/' . str_replace('%2F', '/', rawurlencode($prefix)) . $path;
  }
  $query = $options['query'] ? '?' . UrlHelper::buildQuery($options['query']) : '';

  // The base_url might be rewritten from the language rewrite in domain mode.
  if (isset($options['base_url'])) {
    $base_url = $options['base_url'];
    if (isset($options['https'])) {
      if ($options['https'] === TRUE) {
        $base_url = str_replace('http://', 'https://', $base_url);
      }
      elseif ($options['https'] === FALSE) {
        $base_url = str_replace('https://', 'http://', $base_url);
      }
    }
    $url = $base_url . $path . $query . $fragment;
    return $collect_bubbleable_metadata ? $generated_url
      ->setGeneratedUrl($url) : $url;
  }
  $base_url = $this->context
    ->getBaseUrl();
  $absolute = !empty($options['absolute']);
  if (!$absolute || !($host = $this->context
    ->getHost())) {
    $url = $base_url . $path . $query . $fragment;
    return $collect_bubbleable_metadata ? $generated_url
      ->setGeneratedUrl($url) : $url;
  }

  // Prepare an absolute URL by getting the correct scheme, host and port from
  // the request context.
  if (isset($options['https'])) {
    $scheme = $options['https'] ? 'https' : 'http';
  }
  else {
    $scheme = $this->context
      ->getScheme();
  }
  $scheme_req = $route
    ->getSchemes();
  if ($scheme_req && ($req = $scheme_req[0]) && $scheme !== $req) {
    $scheme = $req;
  }
  $port = '';
  if ('http' === $scheme && 80 != $this->context
    ->getHttpPort()) {
    $port = ':' . $this->context
      ->getHttpPort();
  }
  elseif ('https' === $scheme && 443 != $this->context
    ->getHttpsPort()) {
    $port = ':' . $this->context
      ->getHttpsPort();
  }
  if ($collect_bubbleable_metadata) {
    $generated_url
      ->addCacheContexts([
      'url.site',
    ]);
  }
  $url = $scheme . '://' . $host . $port . $base_url . $path . $query . $fragment;
  return $collect_bubbleable_metadata ? $generated_url
    ->setGeneratedUrl($url) : $url;
}