You are here

abstract class StylePluginBase in Drupal 9

Same name and namespace in other branches
  1. 8 core/modules/views/src/Plugin/views/style/StylePluginBase.php \Drupal\views\Plugin\views\style\StylePluginBase

Base class for views style plugins.

Hierarchy

Expanded class hierarchy of StylePluginBase

Related topics

4 files declare their use of StylePluginBase
DisplayKernelTest.php in core/modules/views/tests/src/Kernel/Plugin/DisplayKernelTest.php
Serializer.php in core/modules/rest/src/Plugin/views/style/Serializer.php
StyleTemplateTest.php in core/modules/views/tests/modules/views_test_data/src/Plugin/views/style/StyleTemplateTest.php
StyleTest.php in core/modules/views/tests/modules/views_test_data/src/Plugin/views/style/StyleTest.php

File

core/modules/views/src/Plugin/views/style/StylePluginBase.php, line 40

Namespace

Drupal\views\Plugin\views\style
View source
abstract class StylePluginBase extends PluginBase {

  /**
   * {@inheritdoc}
   */
  protected $usesOptions = TRUE;

  /**
   * Store all available tokens row rows.
   */
  protected $rowTokens = [];

  /**
   * Whether or not this style uses a row plugin.
   *
   * @var bool
   */
  protected $usesRowPlugin = FALSE;

  /**
   * Does the style plugin support custom css class for the rows.
   *
   * @var bool
   */
  protected $usesRowClass = FALSE;

  /**
   * Does the style plugin support grouping of rows.
   *
   * @var bool
   */
  protected $usesGrouping = TRUE;

  /**
   * Does the style plugin for itself support to add fields to its output.
   *
   * This option only makes sense on style plugins without row plugins, like
   * for example table.
   *
   * @var bool
   */
  protected $usesFields = FALSE;

  /**
   * Stores the rendered field values, keyed by the row index and field name.
   *
   * @see \Drupal\views\Plugin\views\style\StylePluginBase::renderFields()
   * @see \Drupal\views\Plugin\views\style\StylePluginBase::getField()
   *
   * @var array|null
   */
  protected $rendered_fields;

  /**
   * The theme function used to render the grouping set.
   *
   * Plugins may override this attribute if they wish to use some other theme
   * function to render the grouping set.
   *
   * @var string
   *
   * @see StylePluginBase::renderGroupingSets()
   */
  protected $groupingTheme = 'views_view_grouping';

  /**
   * Should field labels be enabled by default.
   *
   * @var bool
   */
  protected $defaultFieldLabels = FALSE;

  /**
   * Overrides \Drupal\views\Plugin\views\PluginBase::init().
   *
   * The style options might come externally as the style can be sourced from at
   * least two locations. If it's not included, look on the display.
   */
  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
    parent::init($view, $display, $options);
    if ($this
      ->usesRowPlugin() && $display
      ->getOption('row')) {
      $this->view->rowPlugin = $display
        ->getPlugin('row');
    }
    $this->options += [
      'grouping' => [],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function destroy() {
    parent::destroy();
    if (isset($this->view->rowPlugin)) {
      $this->view->rowPlugin
        ->destroy();
    }
  }

  /**
   * Returns the usesRowPlugin property.
   *
   * @return bool
   */
  public function usesRowPlugin() {
    return $this->usesRowPlugin;
  }

  /**
   * Returns the usesRowClass property.
   *
   * @return bool
   */
  public function usesRowClass() {
    return $this->usesRowClass;
  }

  /**
   * Returns the usesGrouping property.
   *
   * @return bool
   */
  public function usesGrouping() {
    return $this->usesGrouping;
  }

  /**
   * Return TRUE if this style also uses fields.
   *
   * @return bool
   */
  public function usesFields() {

    // If we use a row plugin, ask the row plugin. Chances are, we don't
    // care, it does.
    $row_uses_fields = FALSE;
    if ($this
      ->usesRowPlugin() && ($row_plugin = $this->displayHandler
      ->getPlugin('row'))) {
      $row_uses_fields = $row_plugin
        ->usesFields();
    }

    // Otherwise, check the definition or the option.
    return $row_uses_fields || $this->usesFields || !empty($this->options['uses_fields']);
  }

  /**
   * Return TRUE if this style uses tokens.
   *
   * Used to ensure we don't fetch tokens when not needed for performance.
   */
  public function usesTokens() {
    if ($this
      ->usesRowClass()) {
      $class = $this->options['row_class'];
      if (strpos($class, '{{') !== FALSE) {
        return TRUE;
      }
    }
  }

  /**
   * Return TRUE if this style enables field labels by default.
   *
   * @return bool
   */
  public function defaultFieldLabels() {
    return $this->defaultFieldLabels;
  }

  /**
   * Return the token replaced row class for the specified row.
   */
  public function getRowClass($row_index) {
    if ($this
      ->usesRowClass()) {
      $class = $this->options['row_class'];
      if ($this
        ->usesFields() && $this->view->field) {
        $class = strip_tags($this
          ->tokenizeValue($class, $row_index));
      }
      $classes = explode(' ', $class);
      foreach ($classes as &$class) {
        $class = Html::cleanCssIdentifier($class);
      }
      return implode(' ', $classes);
    }
  }

  /**
   * Take a value and apply token replacement logic to it.
   */
  public function tokenizeValue($value, $row_index) {
    if (strpos($value, '{{') !== FALSE) {

      // Row tokens might be empty, for example for node row style.
      $tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : [];
      if (!empty($this->view->build_info['substitutions'])) {
        $tokens += $this->view->build_info['substitutions'];
      }
      $value = $this
        ->viewsTokenReplace($value, $tokens);
    }
    else {

      // ::viewsTokenReplace() will run Xss::filterAdmin on the
      // resulting string. We do the same here for consistency.
      $value = Xss::filterAdmin($value);
    }
    return $value;
  }

  /**
   * Should the output of the style plugin be rendered even if it's an empty
   * view.
   */
  public function evenEmpty() {
    return !empty($this->definition['even empty']);
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['grouping'] = [
      'default' => [],
    ];
    if ($this
      ->usesRowClass()) {
      $options['row_class'] = [
        'default' => '',
      ];
      $options['default_row_class'] = [
        'default' => TRUE,
      ];
    }
    $options['uses_fields'] = [
      'default' => FALSE,
    ];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);

    // Only fields-based views can handle grouping.  Style plugins can also exclude
    // themselves from being groupable by setting their "usesGrouping" property
    // to FALSE.
    // @TODO: Document "usesGrouping" in docs.php when docs.php is written.
    if ($this
      ->usesFields() && $this
      ->usesGrouping()) {
      $options = [
        '' => $this
          ->t('- None -'),
      ];
      $field_labels = $this->displayHandler
        ->getFieldLabels(TRUE);
      $options += $field_labels;

      // If there are no fields, we can't group on them.
      if (count($options) > 1) {

        // This is for backward compatibility, when there was just a single
        // select form.
        if (is_string($this->options['grouping'])) {
          $grouping = $this->options['grouping'];
          $this->options['grouping'] = [];
          $this->options['grouping'][0]['field'] = $grouping;
        }
        if (isset($this->options['group_rendered']) && is_string($this->options['group_rendered'])) {
          $this->options['grouping'][0]['rendered'] = $this->options['group_rendered'];
          unset($this->options['group_rendered']);
        }
        $c = count($this->options['grouping']);

        // Add a form for every grouping, plus one.
        for ($i = 0; $i <= $c; $i++) {
          $grouping = !empty($this->options['grouping'][$i]) ? $this->options['grouping'][$i] : [];
          $grouping += [
            'field' => '',
            'rendered' => TRUE,
            'rendered_strip' => FALSE,
          ];
          $form['grouping'][$i]['field'] = [
            '#type' => 'select',
            '#title' => $this
              ->t('Grouping field Nr.@number', [
              '@number' => $i + 1,
            ]),
            '#options' => $options,
            '#default_value' => $grouping['field'],
            '#description' => $this
              ->t('You may optionally specify a field by which to group the records. Leave blank to not group.'),
          ];
          $form['grouping'][$i]['rendered'] = [
            '#type' => 'checkbox',
            '#title' => $this
              ->t('Use rendered output to group rows'),
            '#default_value' => $grouping['rendered'],
            '#description' => $this
              ->t('If enabled the rendered output of the grouping field is used to group the rows.'),
            '#states' => [
              'invisible' => [
                ':input[name="style_options[grouping][' . $i . '][field]"]' => [
                  'value' => '',
                ],
              ],
            ],
          ];
          $form['grouping'][$i]['rendered_strip'] = [
            '#type' => 'checkbox',
            '#title' => $this
              ->t('Remove tags from rendered output'),
            '#default_value' => $grouping['rendered_strip'],
            '#states' => [
              'invisible' => [
                ':input[name="style_options[grouping][' . $i . '][field]"]' => [
                  'value' => '',
                ],
              ],
            ],
          ];
        }
      }
    }
    if ($this
      ->usesRowClass()) {
      $form['row_class'] = [
        '#title' => $this
          ->t('Row class'),
        '#description' => $this
          ->t('The class to provide on each row.'),
        '#type' => 'textfield',
        '#default_value' => $this->options['row_class'],
      ];
      if ($this
        ->usesFields()) {
        $form['row_class']['#description'] .= ' ' . $this
          ->t('You may use field tokens from as per the "Replacement patterns" used in "Rewrite the output of this field" for all fields.');
      }
      $form['default_row_class'] = [
        '#title' => $this
          ->t('Add views row classes'),
        '#description' => $this
          ->t('Add the default row classes like @classes to the output. You can use this to quickly reduce the amount of markup the view provides by default, at the cost of making it more difficult to apply CSS.', [
          '@classes' => 'views-row',
        ]),
        '#type' => 'checkbox',
        '#default_value' => $this->options['default_row_class'],
      ];
    }
    if (!$this
      ->usesFields() || !empty($this->options['uses_fields'])) {
      $form['uses_fields'] = [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Force using fields'),
        '#description' => $this
          ->t('If neither the row nor the style plugin supports fields, this field allows to enable them, so you can for example use groupby.'),
        '#default_value' => $this->options['uses_fields'],
      ];
    }
  }

  /**
   * {@inheritdoc}
   */
  public function validateOptionsForm(&$form, FormStateInterface $form_state) {

    // Don't run validation on style plugins without the grouping setting.
    if ($form_state
      ->hasValue([
      'style_options',
      'grouping',
    ])) {

      // Don't save grouping if no field is specified.
      $groupings = $form_state
        ->getValue([
        'style_options',
        'grouping',
      ]);
      foreach ($groupings as $index => $grouping) {
        if (empty($grouping['field'])) {
          $form_state
            ->unsetValue([
            'style_options',
            'grouping',
            $index,
          ]);
        }
      }
    }
  }

  /**
   * Provide a form in the views wizard if this style is selected.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param string $type
   *   The display type, either block or page.
   *
   * @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct
   *   replacement is provided.
   *
   * @see https://www.drupal.org/node/3186502
   */
  public function wizardForm(&$form, FormStateInterface $form_state, $type) {
    @trigger_error(__METHOD__ . '() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/3186502', E_USER_DEPRECATED);
  }

  /**
   * Alter the options of a display before they are added to the view.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param \Drupal\views\Plugin\views\wizard\WizardInterface $wizard
   *   The current used wizard.
   * @param array $display_options
   *   The options which will be used on the view. The style plugin should
   *   alter this to its own needs.
   * @param string $display_type
   *   The display type, either block or page.
   */
  public function wizardSubmit(&$form, FormStateInterface $form_state, WizardInterface $wizard, &$display_options, $display_type) {
  }

  /**
   * Called by the view builder to see if this style handler wants to
   * interfere with the sorts. If so it should build; if it returns
   * any non-TRUE value, normal sorting will NOT be added to the query.
   */
  public function buildSort() {
    return TRUE;
  }

  /**
   * Called by the view builder to let the style build a second set of
   * sorts that will come after any other sorts in the view.
   */
  public function buildSortPost() {
  }

  /**
   * Allow the style to do stuff before each row is rendered.
   *
   * @param $result
   *   The full array of results from the query.
   */
  public function preRender($result) {
    if (!empty($this->view->rowPlugin)) {
      $this->view->rowPlugin
        ->preRender($result);
    }
  }

  /**
   * Renders a group of rows of the grouped view.
   *
   * @param array $rows
   *   The result rows rendered in this group.
   *
   * @return array
   *   The render array containing the single group theme output.
   */
  protected function renderRowGroup(array $rows = []) {
    return [
      '#theme' => $this
        ->themeFunctions(),
      '#view' => $this->view,
      '#rows' => $rows,
    ];
  }

  /**
   * Render the display in this style.
   */
  public function render() {
    if ($this
      ->usesRowPlugin() && empty($this->view->rowPlugin)) {
      trigger_error('Drupal\\views\\Plugin\\views\\style\\StylePluginBase: Missing row plugin', E_WARNING);
      return [];
    }

    // Group the rows according to the grouping instructions, if specified.
    $sets = $this
      ->renderGrouping($this->view->result, $this->options['grouping'], TRUE);
    return $this
      ->renderGroupingSets($sets);
  }

  /**
   * Render the grouping sets.
   *
   * Plugins may override this method if they wish some other way of handling
   * grouping.
   *
   * @param $sets
   *   An array keyed by group content containing the grouping sets to render.
   *   Each set contains the following associative array:
   *   - group: The group content.
   *   - level: The hierarchical level of the grouping.
   *   - rows: The result rows to be rendered in this group..
   *
   * @return array
   *   Render array of grouping sets.
   */
  public function renderGroupingSets($sets) {
    $output = [];
    $theme_functions = $this->view
      ->buildThemeFunctions($this->groupingTheme);
    foreach ($sets as $set) {
      $level = isset($set['level']) ? $set['level'] : 0;
      $row = reset($set['rows']);

      // Render as a grouping set.
      if (is_array($row) && isset($row['group'])) {
        $single_output = [
          '#theme' => $theme_functions,
          '#view' => $this->view,
          '#grouping' => $this->options['grouping'][$level],
          '#rows' => $set['rows'],
        ];
      }
      else {
        if ($this
          ->usesRowPlugin()) {
          foreach ($set['rows'] as $index => $row) {
            $this->view->row_index = $index;
            $set['rows'][$index] = $this->view->rowPlugin
              ->render($row);
          }
        }
        $single_output = $this
          ->renderRowGroup($set['rows']);
      }
      $single_output['#grouping_level'] = $level;
      $single_output['#title'] = $set['group'];
      $output[] = $single_output;
    }
    unset($this->view->row_index);
    return $output;
  }

  /**
   * Group records as needed for rendering.
   *
   * @param $records
   *   An array of records from the view to group.
   * @param $groupings
   *   An array of grouping instructions on which fields to group. If empty, the
   *   result set will be given a single group with an empty string as a label.
   * @param $group_rendered
   *   Boolean value whether to use the rendered or the raw field value for
   *   grouping. If set to NULL the return is structured as before
   *   Views 7.x-3.0-rc2. After Views 7.x-3.0 this boolean is only used if
   *   $groupings is an old-style string or if the rendered option is missing
   *   for a grouping instruction.
   *
   * @return
   *   The grouped record set.
   *   A nested set structure is generated if multiple grouping fields are used.
   *
   *   @code
   *   array(
   *     'grouping_field_1:grouping_1' => array(
   *       'group' => 'grouping_field_1:content_1',
   *       'level' => 0,
   *       'rows' => array(
   *         'grouping_field_2:grouping_a' => array(
   *           'group' => 'grouping_field_2:content_a',
   *           'level' => 1,
   *           'rows' => array(
   *             $row_index_1 => $row_1,
   *             $row_index_2 => $row_2,
   *             // ...
   *           )
   *         ),
   *       ),
   *     ),
   *     'grouping_field_1:grouping_2' => array(
   *       // ...
   *     ),
   *   )
   *   @endcode
   */
  public function renderGrouping($records, $groupings = [], $group_rendered = NULL) {

    // This is for backward compatibility, when $groupings was a string
    // containing the ID of a single field.
    if (is_string($groupings)) {
      $rendered = $group_rendered === NULL ? TRUE : $group_rendered;
      $groupings = [
        [
          'field' => $groupings,
          'rendered' => $rendered,
        ],
      ];
    }

    // Make sure fields are rendered
    $this
      ->renderFields($this->view->result);
    $sets = [];
    if ($groupings) {
      foreach ($records as $index => $row) {

        // Iterate through configured grouping fields to determine the
        // hierarchically positioned set where the current row belongs to.
        // While iterating, parent groups, that do not exist yet, are added.
        $set =& $sets;
        foreach ($groupings as $level => $info) {
          $field = $info['field'];
          $rendered = isset($info['rendered']) ? $info['rendered'] : $group_rendered;
          $rendered_strip = isset($info['rendered_strip']) ? $info['rendered_strip'] : FALSE;
          $grouping = '';
          $group_content = '';

          // Group on the rendered version of the field, not the raw.  That way,
          // we can control any special formatting of the grouping field through
          // the admin or theme layer or anywhere else we'd like.
          if (isset($this->view->field[$field])) {
            $group_content = $this
              ->getField($index, $field);
            if ($this->view->field[$field]->options['label']) {
              $group_content = $this->view->field[$field]->options['label'] . ': ' . $group_content;
            }
            if ($rendered) {
              $grouping = (string) $group_content;
              if ($rendered_strip) {
                $group_content = $grouping = strip_tags(htmlspecialchars_decode($group_content));
              }
            }
            else {
              $grouping = $this
                ->getFieldValue($index, $field);

              // Not all field handlers return a scalar value,
              // e.g. views_handler_field_field.
              if (!is_scalar($grouping)) {
                $grouping = hash('sha256', serialize($grouping));
              }
            }
          }

          // Create the group if it does not exist yet.
          if (empty($set[$grouping])) {
            $set[$grouping]['group'] = $group_content;
            $set[$grouping]['level'] = $level;
            $set[$grouping]['rows'] = [];
          }

          // Move the set reference into the row set of the group we just determined.
          $set =& $set[$grouping]['rows'];
        }

        // Add the row to the hierarchically positioned row set we just determined.
        $set[$index] = $row;
      }
    }
    else {

      // Create a single group with an empty grouping field.
      $sets[''] = [
        'group' => '',
        'rows' => $records,
      ];
    }

    // If this parameter isn't explicitly set, modify the output to be fully
    // backward compatible to code before Views 7.x-3.0-rc2.
    // @TODO Remove this as soon as possible e.g. October 2020
    if ($group_rendered === NULL) {
      $old_style_sets = [];
      foreach ($sets as $group) {
        $old_style_sets[$group['group']] = $group['rows'];
      }
      $sets = $old_style_sets;
    }
    return $sets;
  }

  /**
   * 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');
        $max_age = $cache_plugin
          ->getCacheMaxAge();

        /** @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),
              'max-age' => $max_age,
            ],
            '#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);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function trustedCallbacks() {
    $callbacks = parent::trustedCallbacks();
    $callbacks[] = 'elementPreRenderRow';
    return $callbacks;
  }

  /**
   * #pre_render callback for view row field rendering.
   *
   * @see self::render()
   *
   * @param array $data
   *   The element to #pre_render
   *
   * @return array
   *   The processed element.
   */
  public function elementPreRenderRow(array $data) {

    // Render row fields.
    foreach ($this->view->field as $id => $field) {
      $data[$id] = [
        '#markup' => $field
          ->theme($data['#row']),
      ];
    }
    return $data;
  }

  /**
   * Gets a rendered field.
   *
   * @param int $index
   *   The index count of the row.
   * @param string $field
   *   The ID of the field.
   *
   * @return \Drupal\Component\Render\MarkupInterface|null
   *   The output of the field, or NULL if it was empty.
   */
  public function getField($index, $field) {
    if (!isset($this->rendered_fields)) {
      $this
        ->renderFields($this->view->result);
    }
    if (isset($this->rendered_fields[$index][$field])) {
      return $this->rendered_fields[$index][$field];
    }
  }

  /**
   * Get the raw field value.
   *
   * @param $index
   *   The index count of the row.
   * @param $field
   *   The id of the field.
   */
  public function getFieldValue($index, $field) {
    $this->view->row_index = $index;
    $value = $this->view->field[$field]
      ->getValue($this->view->result[$index]);
    unset($this->view->row_index);
    return $value;
  }

  /**
   * {@inheritdoc}
   */
  public function validate() {
    $errors = parent::validate();
    if ($this
      ->usesRowPlugin()) {
      $plugin = $this->displayHandler
        ->getPlugin('row');
      if (empty($plugin)) {
        $errors[] = $this
          ->t('Style @style requires a row style but the row plugin is invalid.', [
          '@style' => $this->definition['title'],
        ]);
      }
      else {
        $result = $plugin
          ->validate();
        if (!empty($result) && is_array($result)) {
          $errors = array_merge($errors, $result);
        }
      }
    }
    return $errors;
  }

  /**
   * {@inheritdoc}
   */
  public function query() {
    parent::query();
    if (isset($this->view->rowPlugin)) {
      $this->view->rowPlugin
        ->query();
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
MessengerTrait::$messenger protected property The messenger. 27
MessengerTrait::messenger public function Gets the messenger. 27
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$definition public property Plugins's definition.
PluginBase::$displayHandler public property The display object this plugin is for.
PluginBase::$options public property Options for this plugin will be held here.
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::$renderer protected property Stores the render API renderer. 3
PluginBase::$view public property The top object of a view. 1
PluginBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 14
PluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 63
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::doFilterByDefinedOptions protected function Do the work to filter out stored options depending on the defined options.
PluginBase::filterByDefinedOptions public function Filter out stored options depending on the defined options. Overrides ViewsPluginInterface::filterByDefinedOptions
PluginBase::getAvailableGlobalTokens public function Returns an array of available token replacements. Overrides ViewsPluginInterface::getAvailableGlobalTokens
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 2
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::getProvider public function Returns the plugin provider. Overrides ViewsPluginInterface::getProvider
PluginBase::getRenderer protected function Returns the render API renderer. 1
PluginBase::globalTokenForm public function Adds elements for available core tokens to a form. Overrides ViewsPluginInterface::globalTokenForm
PluginBase::globalTokenReplace public function Returns a string with any core tokens replaced. Overrides ViewsPluginInterface::globalTokenReplace
PluginBase::INCLUDE_ENTITY constant Include entity row languages when listing languages.
PluginBase::INCLUDE_NEGOTIATED constant Include negotiated languages when listing languages.
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginBase::listLanguages protected function Makes an array of languages, optionally including special languages.
PluginBase::pluginTitle public function Return the human readable name of the display. Overrides ViewsPluginInterface::pluginTitle
PluginBase::preRenderAddFieldsetMarkup public static function Moves form elements into fieldsets for presentation purposes. Overrides ViewsPluginInterface::preRenderAddFieldsetMarkup
PluginBase::preRenderFlattenData public static function Flattens the structure of form elements. Overrides ViewsPluginInterface::preRenderFlattenData
PluginBase::queryLanguageSubstitutions public static function Returns substitutions for Views queries for languages.
PluginBase::setOptionDefaults protected function Fills up the options of the plugin with defaults.
PluginBase::submitOptionsForm public function Handle any special handling on the validate form. Overrides ViewsPluginInterface::submitOptionsForm 16
PluginBase::summaryTitle public function Returns the summary of the settings in the display. Overrides ViewsPluginInterface::summaryTitle 6
PluginBase::themeFunctions public function Provide a full list of possible theme templates used by this style. Overrides ViewsPluginInterface::themeFunctions 1
PluginBase::unpackOptions public function Unpack options over our existing defaults, drilling down into arrays so that defaults don't get totally blown away. Overrides ViewsPluginInterface::unpackOptions
PluginBase::usesOptions public function Returns the usesOptions property. Overrides ViewsPluginInterface::usesOptions 8
PluginBase::viewsTokenReplace protected function Replaces Views' tokens in a given string. The resulting string will be sanitized with Xss::filterAdmin. 1
PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT constant Query string to indicate the site default language.
PluginBase::__construct public function Constructs a PluginBase object. Overrides PluginBase::__construct
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
StylePluginBase::$defaultFieldLabels protected property Should field labels be enabled by default. 1
StylePluginBase::$groupingTheme protected property The theme function used to render the grouping set.
StylePluginBase::$rendered_fields protected property Stores the rendered field values, keyed by the row index and field name.
StylePluginBase::$rowTokens protected property Store all available tokens row rows.
StylePluginBase::$usesFields protected property Does the style plugin for itself support to add fields to its output. 3
StylePluginBase::$usesGrouping protected property Does the style plugin support grouping of rows. 3
StylePluginBase::$usesOptions protected property Denotes whether the plugin has an additional options form. Overrides PluginBase::$usesOptions
StylePluginBase::$usesRowClass protected property Does the style plugin support custom css class for the rows. 3
StylePluginBase::$usesRowPlugin protected property Whether or not this style uses a row plugin. 10
StylePluginBase::buildOptionsForm public function Provide a form to edit options for this plugin. Overrides PluginBase::buildOptionsForm 9
StylePluginBase::buildSort public function Called by the view builder to see if this style handler wants to interfere with the sorts. If so it should build; if it returns any non-TRUE value, normal sorting will NOT be added to the query. 1
StylePluginBase::buildSortPost public function Called by the view builder to let the style build a second set of sorts that will come after any other sorts in the view. 1
StylePluginBase::defaultFieldLabels public function Return TRUE if this style enables field labels by default. 1
StylePluginBase::defineOptions protected function Information about options for all kinds of purposes will be held here. Overrides PluginBase::defineOptions 9
StylePluginBase::destroy public function Clears a plugin. Overrides PluginBase::destroy
StylePluginBase::elementPreRenderRow public function #pre_render callback for view row field rendering.
StylePluginBase::evenEmpty public function Should the output of the style plugin be rendered even if it's an empty view. 2
StylePluginBase::getField public function Gets a rendered field.
StylePluginBase::getFieldValue public function Get the raw field value.
StylePluginBase::getRowClass public function Return the token replaced row class for the specified row.
StylePluginBase::init public function Overrides \Drupal\views\Plugin\views\PluginBase::init(). Overrides PluginBase::init
StylePluginBase::preRender public function Allow the style to do stuff before each row is rendered.
StylePluginBase::query public function Add anything to the query that we might need to. Overrides PluginBase::query 1
StylePluginBase::render public function Render the display in this style. 7
StylePluginBase::renderFields protected function Renders all of the fields for a given style and store them on the object.
StylePluginBase::renderGrouping public function Group records as needed for rendering.
StylePluginBase::renderGroupingSets public function Render the grouping sets.
StylePluginBase::renderRowGroup protected function Renders a group of rows of the grouped view.
StylePluginBase::tokenizeValue public function Take a value and apply token replacement logic to it.
StylePluginBase::trustedCallbacks public static function Lists the trusted callbacks provided by the implementing class. Overrides PluginBase::trustedCallbacks
StylePluginBase::usesFields public function Return TRUE if this style also uses fields. 3
StylePluginBase::usesGrouping public function Returns the usesGrouping property. 3
StylePluginBase::usesRowClass public function Returns the usesRowClass property. 3
StylePluginBase::usesRowPlugin public function Returns the usesRowPlugin property. 10
StylePluginBase::usesTokens public function Return TRUE if this style uses tokens.
StylePluginBase::validate public function Validate that the plugin is correct and can be saved. Overrides PluginBase::validate
StylePluginBase::validateOptionsForm public function Validate the options form. Overrides PluginBase::validateOptionsForm
StylePluginBase::wizardForm Deprecated public function Provide a form in the views wizard if this style is selected.
StylePluginBase::wizardSubmit public function Alter the options of a display before they are added to the view. 1
TrustedCallbackInterface::THROW_EXCEPTION constant Untrusted callbacks throw exceptions.
TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION constant Untrusted callbacks trigger silenced E_USER_DEPRECATION errors.
TrustedCallbackInterface::TRIGGER_WARNING constant Untrusted callbacks trigger E_USER_WARNING errors.