You are here

protected function FieldPluginBase::renderAsLink in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/views/src/Plugin/views/field/FieldPluginBase.php \Drupal\views\Plugin\views\field\FieldPluginBase::renderAsLink()

Render this field as a link, with the info from a fieldset set by the user.

1 call to FieldPluginBase::renderAsLink()
FieldPluginBase::renderText in core/modules/views/src/Plugin/views/field/FieldPluginBase.php
Performs an advanced text render for the item.

File

core/modules/views/src/Plugin/views/field/FieldPluginBase.php, line 1387

Class

FieldPluginBase
Base class for views fields.

Namespace

Drupal\views\Plugin\views\field

Code

protected function renderAsLink($alter, $text, $tokens) {
  $options = [
    'absolute' => !empty($alter['absolute']) ? TRUE : FALSE,
    'alias' => FALSE,
    'entity' => NULL,
    'entity_type' => NULL,
    'fragment' => NULL,
    'language' => NULL,
    'query' => [],
  ];
  $alter += [
    'path' => NULL,
  ];
  $path = $alter['path'];

  // strip_tags() and viewsTokenReplace remove <front>, so check whether it's
  // different to front.
  if ($path != '<front>') {

    // Use strip_tags as there should never be HTML in the path.
    // However, we need to preserve special characters like " that were
    // removed by Html::escape().
    $path = Html::decodeEntities($this
      ->viewsTokenReplace($alter['path'], $tokens));

    // Tokens might contain <front>, so check for <front> again.
    if ($path != '<front>') {
      $path = strip_tags($path);
    }

    // Tokens might have resolved URL's, as is the case for tokens provided by
    // Link fields, so all internal paths will be prefixed by base_path(). For
    // proper further handling reset this to internal:/.
    if (strpos($path, base_path()) === 0) {
      $path = 'internal:/' . substr($path, strlen(base_path()));
    }

    // If we have no $path and no $alter['url'], we have nothing to work with,
    // so we just return the text.
    if (empty($path) && empty($alter['url'])) {
      return $text;
    }

    // If no scheme is provided in the $path, assign the default 'http://'.
    // This allows a url of 'www.example.com' to be converted to
    // 'http://www.example.com'.
    // Only do this when flag for external has been set, $path doesn't contain
    // a scheme and $path doesn't have a leading /.
    if ($alter['external'] && !parse_url($path, PHP_URL_SCHEME) && strpos($path, '/') !== 0) {

      // There is no scheme, add the default 'http://' to the $path.
      $path = "http://" . $path;
    }
  }
  if (empty($alter['url'])) {
    if (!parse_url($path, PHP_URL_SCHEME)) {

      // @todo Views should expect and store a leading /. See
      //   https://www.drupal.org/node/2423913.
      $alter['url'] = CoreUrl::fromUserInput('/' . ltrim($path, '/'));
    }
    else {
      $alter['url'] = CoreUrl::fromUri($path);
    }
  }
  $options = $alter['url']
    ->getOptions() + $options;
  $path = $alter['url']
    ->setOptions($options)
    ->toUriString();
  if (!empty($alter['path_case']) && $alter['path_case'] != 'none' && !$alter['url']
    ->isRouted()) {
    $path = str_replace($alter['path'], $this
      ->caseTransform($alter['path'], $this->options['alter']['path_case']), $path);
  }
  if (!empty($alter['replace_spaces'])) {
    $path = str_replace(' ', '-', $path);
  }

  // Parse the URL and move any query and fragment parameters out of the path.
  $url = UrlHelper::parse($path);

  // Seriously malformed URLs may return FALSE or empty arrays.
  if (empty($url)) {
    return $text;
  }

  // If the path is empty do not build a link around the given text and return
  // it as is.
  // http://www.example.com URLs will not have a $url['path'], so check host as well.
  if (empty($url['path']) && empty($url['host']) && empty($url['fragment']) && empty($url['url'])) {
    return $text;
  }

  // If we get to here we have a path from the url parsing. So assign that to
  // $path now so we don't get query strings or fragments in the path.
  $path = $url['path'];
  if (isset($url['query'])) {

    // Remove query parameters that were assigned a query string replacement
    // token for which there is no value available.
    foreach ($url['query'] as $param => $val) {
      if ($val == '%' . $param) {
        unset($url['query'][$param]);
      }

      // Replace any empty query params from URL parsing with NULL. So the
      // query will get built correctly with only the param key.
      // @see \Drupal\Component\Utility\UrlHelper::buildQuery().
      if ($val === '') {
        $url['query'][$param] = NULL;
      }
    }
    $options['query'] = $url['query'];
  }
  if (isset($url['fragment'])) {
    $path = strtr($path, [
      '#' . $url['fragment'] => '',
    ]);

    // If the path is empty we want to have a fragment for the current site.
    if ($path == '') {
      $options['external'] = TRUE;
    }
    $options['fragment'] = $url['fragment'];
  }
  $alt = $this
    ->viewsTokenReplace($alter['alt'], $tokens);

  // Set the title attribute of the link only if it improves accessibility
  if ($alt && $alt != $text) {
    $options['attributes']['title'] = Html::decodeEntities($alt);
  }
  $class = $this
    ->viewsTokenReplace($alter['link_class'], $tokens);
  if ($class) {
    $options['attributes']['class'] = [
      $class,
    ];
  }
  if (!empty($alter['rel']) && ($rel = $this
    ->viewsTokenReplace($alter['rel'], $tokens))) {
    $options['attributes']['rel'] = $rel;
  }
  $target = trim($this
    ->viewsTokenReplace($alter['target'], $tokens));
  if (!empty($target)) {
    $options['attributes']['target'] = $target;
  }

  // Allow the addition of arbitrary attributes to links. Additional attributes
  // currently can only be altered in preprocessors and not within the UI.
  if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) {
    foreach ($alter['link_attributes'] as $key => $attribute) {
      if (!isset($options['attributes'][$key])) {
        $options['attributes'][$key] = $this
          ->viewsTokenReplace($attribute, $tokens);
      }
    }
  }

  // If the query and fragment were programmatically assigned overwrite any
  // parsed values.
  if (isset($alter['query'])) {

    // Convert the query to a string, perform token replacement, and then
    // convert back to an array form for
    // \Drupal\Core\Utility\LinkGeneratorInterface::generate().
    $options['query'] = UrlHelper::buildQuery($alter['query']);
    $options['query'] = $this
      ->viewsTokenReplace($options['query'], $tokens);
    $query = [];
    parse_str($options['query'], $query);
    $options['query'] = $query;
  }
  if (isset($alter['alias'])) {

    // Alias is a boolean field, so no token.
    $options['alias'] = $alter['alias'];
  }
  if (isset($alter['fragment'])) {
    $options['fragment'] = $this
      ->viewsTokenReplace($alter['fragment'], $tokens);
  }
  if (isset($alter['language'])) {
    $options['language'] = $alter['language'];
  }

  // If the url came from entity_uri(), pass along the required options.
  if (isset($alter['entity'])) {
    $options['entity'] = $alter['entity'];
  }
  if (isset($alter['entity_type'])) {
    $options['entity_type'] = $alter['entity_type'];
  }

  // The path has been heavily processed above, so it should be used as-is.
  $final_url = CoreUrl::fromUri($path, $options);

  // Build the link based on our altered Url object, adding on the optional
  // prefix and suffix
  $render = [
    '#type' => 'link',
    '#title' => $text,
    '#url' => $final_url,
  ];
  if (!empty($alter['prefix'])) {
    $render['#prefix'] = $this
      ->viewsTokenReplace($alter['prefix'], $tokens);
  }
  if (!empty($alter['suffix'])) {
    $render['#suffix'] = $this
      ->viewsTokenReplace($alter['suffix'], $tokens);
  }
  return $this
    ->getRenderer()
    ->render($render);
}