You are here

public function LinkGenerator::generate in Drupal 8

Same name and namespace in other branches
  1. 9 core/lib/Drupal/Core/Utility/LinkGenerator.php \Drupal\Core\Utility\LinkGenerator::generate()

For anonymous users, the "active" class will be calculated on the server, because most sites serve each anonymous user the same cached page anyway. For authenticated users, the "active" class will be calculated on the client (through JavaScript), only data- attributes are added to links to prevent breaking the render cache. The JavaScript is added in system_page_attachments().

Overrides LinkGeneratorInterface::generate

See also

system_page_attachments()

1 call to LinkGenerator::generate()
LinkGenerator::generateFromLink in core/lib/Drupal/Core/Utility/LinkGenerator.php
Renders a link from a link object.

File

core/lib/Drupal/Core/Utility/LinkGenerator.php, line 79

Class

LinkGenerator
Provides a class which generates a link with route names and parameters.

Namespace

Drupal\Core\Utility

Code

public function generate($text, Url $url) {

  // The link generator should not modify the original URL object, this
  // ensures consistent rendering.
  // @see https://www.drupal.org/node/2842399
  $url = clone $url;

  // Performance: avoid Url::toString() needing to retrieve the URL generator
  // service from the container.
  $url
    ->setUrlGenerator($this->urlGenerator);
  if (is_array($text)) {
    $text = $this->renderer
      ->render($text);
  }

  // Start building a structured representation of our link to be altered later.
  $variables = [
    'text' => $text,
    'url' => $url,
    'options' => $url
      ->getOptions(),
  ];

  // Merge in default options.
  $variables['options'] += [
    'attributes' => [],
    'query' => [],
    'language' => NULL,
    'set_active_class' => FALSE,
    'absolute' => FALSE,
  ];

  // Add a hreflang attribute if we know the language of this link's url and
  // hreflang has not already been set.
  if (!empty($variables['options']['language']) && !isset($variables['options']['attributes']['hreflang'])) {
    $variables['options']['attributes']['hreflang'] = $variables['options']['language']
      ->getId();
  }

  // Ensure that query values are strings.
  array_walk($variables['options']['query'], function (&$value) {
    if ($value instanceof MarkupInterface) {
      $value = (string) $value;
    }
  });

  // Set the "active" class if the 'set_active_class' option is not empty.
  if (!empty($variables['options']['set_active_class']) && !$url
    ->isExternal()) {

    // Add a "data-drupal-link-query" attribute to let the
    // drupal.active-link library know the query in a standardized manner.
    if (!empty($variables['options']['query'])) {
      $query = $variables['options']['query'];
      ksort($query);
      $variables['options']['attributes']['data-drupal-link-query'] = Json::encode($query);
    }

    // Add a "data-drupal-link-system-path" attribute to let the
    // drupal.active-link library know the path in a standardized manner.
    if ($url
      ->isRouted() && !isset($variables['options']['attributes']['data-drupal-link-system-path'])) {

      // @todo System path is deprecated - use the route name and parameters.
      $system_path = $url
        ->getInternalPath();

      // Special case for the front page.
      if ($url
        ->getRouteName() === '<front>') {
        $system_path = '<front>';
      }
      if (!empty($system_path)) {
        $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path;
      }
    }
  }

  // Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags()
  // only when a quick strpos() gives suspicion tags are present.
  if (isset($variables['options']['attributes']['title']) && strpos($variables['options']['attributes']['title'], '<') !== FALSE) {
    $variables['options']['attributes']['title'] = strip_tags($variables['options']['attributes']['title']);
  }

  // Allow other modules to modify the structure of the link.
  $this->moduleHandler
    ->alter('link', $variables);
  $url = $variables['url'];

  // Move attributes out of options since generateFromRoute() doesn't need
  // them. Make sure the "href" comes first for testing purposes.
  $attributes = [
    'href' => '',
  ] + $variables['options']['attributes'];
  unset($variables['options']['attributes']);
  $url
    ->setOptions($variables['options']);

  // External URLs can not have cacheable metadata.
  if ($url
    ->isExternal()) {
    $generated_link = new GeneratedLink();
    $attributes['href'] = $url
      ->toString(FALSE);
    return $this
      ->doGenerate($generated_link, $attributes, $variables);
  }
  if ($url
    ->isRouted() && $url
    ->getRouteName() === '<nolink>') {
    $generated_link = new GeneratedNoLink();
    unset($attributes['href']);
    return $this
      ->doGenerate($generated_link, $attributes, $variables);
  }
  if ($url
    ->isRouted() && $url
    ->getRouteName() === '<button>') {
    $generated_link = new GeneratedButton();
    $attributes['type'] = 'button';
    unset($attributes['href']);
    return $this
      ->doGenerate($generated_link, $attributes, $variables);
  }
  $generated_url = $url
    ->toString(TRUE);
  $generated_link = GeneratedLink::createFromObject($generated_url);

  // The result of the URL generator is a plain-text URL to use as the href
  // attribute, and it is escaped by \Drupal\Core\Template\Attribute.
  $attributes['href'] = $generated_url
    ->getGeneratedUrl();
  return $this
    ->doGenerate($generated_link, $attributes, $variables);
}