Commit 525ef935 authored by Rob Phillips's avatar Rob Phillips Committed by Bryan Sharpe
Browse files

Issue #3259018 by robphillips, b_sharpe: An illegal choice on exposed sort

parent c73efd27
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@ use Drupal\views\Views;
 */
class Combine extends FieldPluginBase {

  /**
   * The handler types with map options.
   */
  const MAP_HANDLER_TYPES = ['filter', 'sort'];

  /**
   * {@inheritdoc}
   */
@@ -32,15 +37,52 @@ class Combine extends FieldPluginBase {
    return $this->options['view_id'];
  }

  /**
   * Get exposed views handlers.
   *
   * @param string $handler_type
   *   The views handler type.
   *
   * @return array
   *   Returns array of views exposed handlers.
   */
  public function getExposedHandlers(string $handler_type) {
    return array_filter(
      $this->view->getHandlers($handler_type),
      function ($handler) {
        return isset($handler['exposed']) && $handler['exposed'];
      }
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['view_id'] = ['default' => ''];
    foreach (self::MAP_HANDLER_TYPES as $handler_type) {
      $key = "{$handler_type}_map";
      $options[$key] = [];
      foreach ($this->getExposedHandlers($handler_type) as $id => $definition) {
        $options[$key][$id] = ['default' => ''];
      }
    }
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  protected function setOptionDefaults(array &$storage, array $options) {
    foreach ($options as &$definition) {
      if (!isset($definition['default'])) {
        $definition['default'] = '';
      }
    }
    parent::setOptionDefaults($storage, $options);
  }

  /**
   * {@inheritdoc}
   */
@@ -54,6 +96,40 @@ class Combine extends FieldPluginBase {
      '#default_value' => $this->options['view_id'],
      '#required' => TRUE,
    ];
    foreach (self::MAP_HANDLER_TYPES as $handler_type) {
      $this->buildMap($handler_type, $form);
    }
  }

  /**
   * Builds the views handler map elements.
   *
   * @param string $handler_type
   *   The views handler type.
   * @param array $form
   *   The form.
   */
  protected function buildMap(string $handler_type, array &$form) {
    if ($handlers = $this->getExposedHandlers($handler_type)) {
      $key = "{$handler_type}_map";
      $title = mb_strtolower(ViewExecutable::getHandlerTypes()[$handler_type]['title']);
      $form[$key] = [
        '#type' => 'details',
        '#title' => $this->t('Map exposed @title', ['@title' => $title]),
        '#description' => $this->t('Map exposed @title input identifiers from this view to the combined view.', [
          '@title' => $title,
        ]),
        '#open' => TRUE,
        '#tree' => TRUE,
      ];
      foreach ($handlers as $id => $definition) {
        $form[$key][$id] = [
          '#type' => 'textfield',
          '#title' => $id,
          '#default_value' => $this->options[$key][$id] ?? '',
        ];
      }
    }
  }

  /**
+38 −3
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ namespace Drupal\views_combine;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Database\Query\Select;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ViewExecutable;

/**
@@ -205,13 +206,47 @@ class ViewsCombiner {
   *   The display identifier.
   * @param \Drupal\views\ViewExecutable $base_view
   *   The base view.
   * @param \Drupal\views\Plugin\views\field\FieldPluginBase|null $field_handler
   *   The views field handler.
   *
   * @return \Drupal\views\ViewExecutable|null
   *   Returns the built view executable.
   */
  public function buildView(string $view_id, string $display_id, ViewExecutable $base_view) {
  public function buildView(string $view_id, string $display_id, ViewExecutable $base_view, FieldPluginBase $field_handler = NULL) {
    if ($view = $this->getView($view_id, $display_id)) {
      $view->setExposedInput($base_view->exposed_raw_input);
      $input = $base_view->exposed_raw_input;

      if ($field_handler) {
        foreach ($input as $id => $value) {
          if (isset($field_handler->options['filter_map'][$id]) && $field_handler->options['filter_map'][$id]) {
            // Use the mapped filter identifier.
            $input[$field_handler->options['filter_map'][$id]] = $value;
          }
        }
      }
      if (isset($input['sort_by']) && !empty($input['sort_by'])) {
        $id = $input['sort_by'];
        $sort_handlers = $view->getHandlers('sort');
        if (!array_key_exists($id, $sort_handlers)) {
          $input['sort_order'] = $input['sort_order'] ?? 'ASC';
          if (isset($field_handler->options['sort_map'][$id]) && $field_handler->options['sort_map'][$id]) {
            // Use the mapped sort identifier.
            $input['sort_by'] = $field_handler->options['sort_map'][$id];
          }
          elseif (!empty($sort_handlers)) {
            // Use the first sort identifier.
            $input['sort_by'] = key($sort_handlers);
          }
          else {
            unset($input['sort_by'], $input['sort_order'], $input['sort_bef_combine']);
          }
          if (isset($input['sort_bef_combine'])) {
            $input['sort_bef_combine'] = $input['sort_by'] . '_' . $input['sort_order'];
          }
        }
      }

      $view->setExposedInput($input);
      $view->preExecute($base_view->args);
      $view->build();
      return $view;
@@ -287,7 +322,7 @@ class ViewsCombiner {
    foreach ($this->view->field as $field_handler) {
      if ($field_handler->realField === 'views_combine' && $field_handler->options['view_id']) {
        [$view_id, $display_id] = explode(':', $field_handler->options['view_id']);
        if (($_view = $this->buildView($view_id, $display_id, $this->view)) && $this->filter($_view)) {
        if (($_view = $this->buildView($view_id, $display_id, $this->view, $field_handler)) && $this->filter($_view)) {
          if ($_view->build_info['query'] instanceof Select) {
            /** @var \Drupal\Core\Database\Query\Select $query */
            $query = $_view->build_info['query'];