Example #1
0
 /**
  * {@inheritdoc}
  */
 public function render(ResultRow $values)
 {
     $value = $this->getValue($values);
     if (!empty($this->options['not'])) {
         $value = !$value;
     }
     if ($this->options['type'] == 'custom') {
         $custom_value = $value ? $this->options['type_custom_true'] : $this->options['type_custom_false'];
         return ViewsRenderPipelineMarkup::create(UtilityXss::filterAdmin($custom_value));
     } elseif (isset($this->formats[$this->options['type']])) {
         return $value ? $this->formats[$this->options['type']][0] : $this->formats[$this->options['type']][1];
     } else {
         return $value ? $this->formats['yes-no'][0] : $this->formats['yes-no'][1];
     }
 }
 /**
  * Renders all of the fields for a given style and store them on the object.
  *
  * @param array $result
  *   The result array from $view->result
  */
 protected function renderFields(array $result)
 {
     if (!$this->usesFields()) {
         return;
     }
     if (!isset($this->rendered_fields)) {
         $this->rendered_fields = [];
         $this->view->row_index = 0;
         $field_ids = array_keys($this->view->field);
         // Only tokens relating to field handlers preceding the one we invoke
         // ::getRenderTokens() on are returned, so here we need to pick the last
         // available field handler.
         $render_tokens_field_id = end($field_ids);
         // If all fields have a field::access FALSE there might be no fields, so
         // there is no reason to execute this code.
         if (!empty($field_ids)) {
             $renderer = $this->getRenderer();
             /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
             $cache_plugin = $this->view->display_handler->getPlugin('cache');
             /** @var \Drupal\views\ResultRow $row */
             foreach ($result as $index => $row) {
                 $this->view->row_index = $index;
                 // Here we implement render caching for result rows. Since we never
                 // build a render array for single rows, given that style templates
                 // need individual field markup to support proper theming, we build
                 // a raw render array containing all field render arrays and cache it.
                 // This allows us to cache the markup of the various children, that is
                 // individual fields, which is then available for style template
                 // preprocess functions, later in the rendering workflow.
                 // @todo Fetch all the available cached row items in one single cache
                 //   get operation, once https://www.drupal.org/node/2453945 is fixed.
                 $data = ['#pre_render' => [[$this, 'elementPreRenderRow']], '#row' => $row, '#cache' => ['keys' => $cache_plugin->getRowCacheKeys($row), 'tags' => $cache_plugin->getRowCacheTags($row)], '#cache_properties' => $field_ids];
                 $renderer->addCacheableDependency($data, $this->view->storage);
                 // Views may be rendered both inside and outside a render context:
                 // - HTML views are rendered inside a render context: then we want to
                 //   use ::render(), so that attachments and cacheability are bubbled.
                 // - non-HTML views are rendered outside a render context: then we
                 //   want to use ::renderPlain(), so that no bubbling happens
                 if ($renderer->hasRenderContext()) {
                     $renderer->render($data);
                 } else {
                     $renderer->renderPlain($data);
                 }
                 // Extract field output from the render array and post process it.
                 $fields = $this->view->field;
                 $rendered_fields =& $this->rendered_fields[$index];
                 $post_render_tokens = [];
                 foreach ($field_ids as $id) {
                     $rendered_fields[$id] = $data[$id]['#markup'];
                     $tokens = $fields[$id]->postRender($row, $rendered_fields[$id]);
                     if ($tokens) {
                         $post_render_tokens += $tokens;
                     }
                 }
                 // Populate row tokens.
                 $this->rowTokens[$index] = $this->view->field[$render_tokens_field_id]->getRenderTokens([]);
                 // Replace post-render tokens.
                 if ($post_render_tokens) {
                     $placeholders = array_keys($post_render_tokens);
                     $values = array_values($post_render_tokens);
                     foreach ($this->rendered_fields[$index] as &$rendered_field) {
                         // Placeholders and rendered fields have been processed by the
                         // render system and are therefore safe.
                         $rendered_field = ViewsRenderPipelineMarkup::create(str_replace($placeholders, $values, $rendered_field));
                     }
                 }
             }
         }
         unset($this->view->row_index);
     }
 }
Example #3
0
 /**
  * {@inheritdoc}
  */
 public function sanitizeValue($value, $type = NULL)
 {
     switch ($type) {
         case 'xss':
             $value = Xss::filter($value);
             break;
         case 'xss_admin':
             $value = Xss::filterAdmin($value);
             break;
         case 'url':
             $value = Html::escape(UrlHelper::stripDangerousProtocols($value));
             break;
         default:
             $value = Html::escape($value);
             break;
     }
     return ViewsRenderPipelineMarkup::create($value);
 }
  /**
   * {@inheritdoc}
   */
  public function renderText($alter) {
    // We need to preserve the safeness of the value regardless of the
    // alterations made by this method. Any alterations or replacements made
    // within this method need to ensure that at the minimum the result is
    // XSS admin filtered. See self::renderAltered() as an example that does.
    $value_is_safe = $this->last_render instanceof MarkupInterface;
    // Cast to a string so that empty checks and string functions work as
    // expected.
    $value = (string) $this->last_render;

    if (!empty($alter['alter_text']) && $alter['text'] !== '') {
      $tokens = $this->getRenderTokens($alter);
      $value = $this->renderAltered($alter, $tokens);
    }

    if (!empty($this->options['alter']['trim_whitespace'])) {
      $value = trim($value);
    }

    // Check if there should be no further rewrite for empty values.
    $no_rewrite_for_empty = $this->options['hide_alter_empty'] && $this->isValueEmpty($this->original_value, $this->options['empty_zero']);

    // Check whether the value is empty and return nothing, so the field isn't rendered.
    // First check whether the field should be hidden if the value(hide_alter_empty = TRUE) /the rewrite is empty (hide_alter_empty = FALSE).
    // For numeric values you can specify whether "0"/0 should be empty.
    if ((($this->options['hide_empty'] && empty($value))
        || ($alter['phase'] != static::RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty))
      && $this->isValueEmpty($value, $this->options['empty_zero'], FALSE)) {
      return '';
    }
    // Only in empty phase.
    if ($alter['phase'] == static::RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty) {
      // If we got here then $alter contains the value of "No results text"
      // and so there is nothing left to do.
      return ViewsRenderPipelineMarkup::create($value);
    }

    if (!empty($alter['strip_tags'])) {
      $value = strip_tags($value, $alter['preserve_tags']);
    }

    $more_link = '';
    if (!empty($alter['trim']) && !empty($alter['max_length'])) {
      $length = strlen($value);
      $value = $this->renderTrimText($alter, $value);
      if ($this->options['alter']['more_link'] && strlen($value) < $length) {
        $tokens = $this->getRenderTokens($alter);
        $more_link_text = $this->options['alter']['more_link_text'] ? $this->options['alter']['more_link_text'] : $this->t('more');
        $more_link_text = strtr(Xss::filterAdmin($more_link_text), $tokens);
        $more_link_path = $this->options['alter']['more_link_path'];
        $more_link_path = strip_tags(Html::decodeEntities($this->viewsTokenReplace($more_link_path, $tokens)));

        // Make sure that paths which were run through URL generation work as
        // well.
        $base_path = base_path();
        // Checks whether the path starts with the base_path.
        if (strpos($more_link_path, $base_path) === 0) {
          $more_link_path = Unicode::substr($more_link_path, Unicode::strlen($base_path));
        }

        // @todo Views should expect and store a leading /. See
        //   https://www.drupal.org/node/2423913.
        $options = array(
          'attributes' => array(
            'class' => array(
              'views-more-link',
            ),
          ),
        );
        if (UrlHelper::isExternal($more_link_path)) {
          $more_link_url = CoreUrl::fromUri($more_link_path, $options);
        }
        else {
          $more_link_url = CoreUrl::fromUserInput('/' . $more_link_path, $options);
        }
        $more_link = ' ' . $this->linkGenerator()->generate($more_link_text, $more_link_url);
      }
    }

    if (!empty($alter['nl2br'])) {
      $value = nl2br($value);
    }

    if ($value_is_safe) {
      $value = ViewsRenderPipelineMarkup::create($value);
    }
    $this->last_render_text = $value;

    if (!empty($alter['make_link']) && (!empty($alter['path']) || !empty($alter['url']))) {
      if (!isset($tokens)) {
        $tokens = $this->getRenderTokens($alter);
      }
      $value = $this->renderAsLink($alter, $value, $tokens);
    }

    // Preserve whether or not the string is safe. Since $more_link comes from
    // \Drupal::l(), it is safe to append. Check if the value is an instance of
    // \Drupal\Component\Render\MarkupInterface here because renderAsLink()
    // can return both safe and unsafe values.
    if ($value instanceof MarkupInterface) {
      return ViewsRenderPipelineMarkup::create($value . $more_link);
    }
    else {
      // If the string is not already marked safe, it is still OK to return it
      // because it will be sanitized by Twig.
      return $value . $more_link;
    }
  }
Example #5
0
 /**
  * {@inheritdoc}
  */
 public function render()
 {
     $build = array();
     $build['#markup'] = $this->renderer->executeInRenderContext(new RenderContext(), function () {
         return $this->view->style_plugin->render();
     });
     $this->view->element['#content_type'] = $this->getMimeType();
     $this->view->element['#cache_properties'][] = '#content_type';
     // Encode and wrap the output in a pre tag if this is for a live preview.
     if (!empty($this->view->live_preview)) {
         $build['#prefix'] = '<pre>';
         $build['#plain_text'] = $build['#markup'];
         $build['#suffix'] = '</pre>';
         unset($build['#markup']);
     } elseif ($this->view->getRequest()->getFormat($this->view->element['#content_type']) !== 'html') {
         // This display plugin is primarily for returning non-HTML formats.
         // However, we still invoke the renderer to collect cacheability metadata.
         // Because the renderer is designed for HTML rendering, it filters
         // #markup for XSS unless it is already known to be safe, but that filter
         // only works for HTML. Therefore, we mark the contents as safe to bypass
         // the filter. So long as we are returning this in a non-HTML response
         // (checked above), this is safe, because an XSS attack only works when
         // executed by an HTML agent.
         // @todo Decide how to support non-HTML in the render API in
         //   https://www.drupal.org/node/2501313.
         $build['#markup'] = ViewsRenderPipelineMarkup::create($build['#markup']);
     }
     parent::applyDisplayCachablityMetadata($build);
     return $build;
 }
Example #6
0
 /**
  * {@inheritdoc}
  */
 public function render(ResultRow $values)
 {
     // Return the text, so the code never thinks the value is empty.
     return ViewsRenderPipelineMarkup::create(Xss::filterAdmin($this->options['alter']['text']));
 }
Example #7
0
 /**
  * {@inheritdoc}
  */
 public function render(ResultRow $values)
 {
     return ViewsRenderPipelineMarkup::create('<!--form-item-' . $this->options['id'] . '--' . $values->index . '-->');
 }