You are here

protected function Selective::getOids in Views Selective Filters 8

Returns a list of options for current view, only at runtime.

1 call to Selective::getOids()
Selective::getValueOptions in src/Plugin/views/filter/Selective.php
Child classes should be used to override this function and set the 'value options', unless 'options callback' is defined as a valid function or static public method to generate these values.

File

src/Plugin/views/filter/Selective.php, line 258

Class

Selective
Views filter handler for selective values.

Namespace

Drupal\views_selective_filters\Plugin\views\filter

Code

protected function getOids() {

  // Parameters that we will be using during the process.
  $base_field = $this->definition['field_base'];
  $ui_name = $this
    ->adminLabel();
  $signature = $this
    ->getSignature();

  // Prevent same filters from being recalculated.
  if (empty(static::$results[$signature])) {

    // We don't want a badly configured selective filter
    // to return thousands of possible values.
    $max_items = (int) $this->options['selective_items_limit'];

    // Clone the view (so it works while editting) and get all results.
    $view_copy = Views::executableFactory()
      ->get($this->view->storage);
    if (!$view_copy) {
      return NULL;
    }

    // Store a flag so that we can know from other places
    // that this view is being used to obtain selective data.
    $view_copy->selective_oids = TRUE;

    // Store information about what filter is this view being used for.
    $view_copy->selective_handler_signature = $signature;

    // Transfer contextual information to cloned view.
    $view_copy
      ->setExposedInput($this->view
      ->getExposedInput());
    $view_copy
      ->setArguments($this->view->args);

    // Mess up with the field used for distinct have thousands of elements.
    // Limit result set to 100: anything above is not user friendly at all.
    $view_copy
      ->setItemsPerPage($max_items);
    $view_copy
      ->setDisplay($this->view->current_display);
    $display = $view_copy
      ->getDisplay();

    // Remove any exposed form configuration. This showed up with BEF module!
    unset($display->display['display_options']['exposed_form']);
    $fields =& $display
      ->getHandlers('field');
    $fields = array_intersect_key($fields, [
      $this->options['selective_display_field'] => TRUE,
    ]);

    // Check to see if the user remembered to add the field.
    if (empty($fields)) {
      drupal_set_message(t('Selective query filter must have corresponding field added to view with Administrative Name set to "@name" and Base Type "@type"', [
        '@name' => $ui_name,
        '@type' => $base_field,
      ]), 'error');
      return [];
    }

    // Get ID of field that will be used for rendering.
    $field = reset($fields);
    $field_options = $field->options;

    // Get field Id.
    $field_id = $field_options['id'];

    // Check that relationships are coherent between Field and Filter.
    $no_display_field_relationship = empty($field_options['relationship']) || $field_options['relationship'] === 'none';
    $no_filter_relationship = empty($this->options['relationship']) || $this->options['relationship'] === 'none';
    $equal = $no_display_field_relationship === TRUE && $no_filter_relationship === TRUE || $field_options['relationship'] === $this->options['relationship'];
    if (!$equal) {
      drupal_set_message(t('Selective filter "@name": relationship of field and filter must match.', [
        '@name' => $ui_name,
        '@type' => $base_field,
      ]), 'error');
      return [];
    }

    // If main field is excluded from presentation, bring it back.
    // Set group type for handler to populate database relationships in query.
    $field_options['exclude'] = 0;
    $field_options['group_type'] = 'group';

    // Remove all sorting: sorts must be added to aggregate fields.
    // $sorts =& $display->getHandlers('sort');
    // $sorts = [];.
    // Turn this into an aggregate query.
    $display
      ->setOption('group_by', 1);

    // Aggregate is incompatible with distinct and pure distinct.
    // At least it does not make sense as it is implemented now.
    $query_options = $display
      ->getOption('query');
    $query_options['options']['distinct'] = TRUE;
    $display
      ->setOption('query', $query_options);

    // Some style plugins can affect the built query, make sure we use a
    // reliable field based style plugin.
    $display
      ->setOption('pager', [
      'type' => 'none',
      'options' => [],
    ]);
    $display
      ->setOption('style', [
      'type' => 'default',
      'options' => [],
    ]);
    $display
      ->setOption('row', [
      'type' => 'fields',
      'options' => [],
    ]);
    $display
      ->setOption('cache', [
      'type' => 'none',
      'options' => [],
    ]);

    // Run View.
    $view_copy
      ->execute($this->view->current_display);

    // We show human-readable values when case.
    if (method_exists($field, 'getValueOptions')) {
      $field
        ->getValueOptions();
    }
    $style = $display
      ->getPlugin('style');

    // Create array of objects for selector.
    $oids = [];
    foreach ($view_copy->result as $row) {
      $key = $field
        ->getValue($row);
      $key = is_array($key) ? reset($key) : $key;

      // @todo This double escapes markup.
      $value = $style
        ->getField($row->index, $field_id);
      $oids[$key] = SafeMarkup::checkPlain($value);
    }

    // Sort values.
    $sort_option = $this->options['selective_display_sort'];
    switch ($sort_option) {
      case 'ASC':
        asort($oids);
        break;
      case 'DESC':
        arsort($oids);
        break;
      case 'KASC':
        ksort($oids);
        break;
      case 'KDESC':
        krsort($oids);
        break;
      case 'ORIG':
        $oids = static::filterOriginalOptions($this
          ->getOriginalOptions(), array_keys($oids));
        break;
      case 'NONE':
        break;
      default:
        asort($oids);
    }

    // If limit exceeded this field is not good for being "selective".
    if (!empty($max_items) && count($oids) == $max_items) {
      drupal_set_message(t('Selective filter "@field" has limited the amount of total results. Please, review you query configuration.', [
        '@field' => $ui_name,
      ]), 'warning');
    }
    static::$results[$signature] = $oids;
    $view_copy
      ->destroy();
  }
  return static::$results[$signature];
}