flexible_views-2.0.1/src/Plugin/views/exposed_form/ManualSelection.php

src/Plugin/views/exposed_form/ManualSelection.php
<?php

namespace Drupal\flexible_views\Plugin\views\exposed_form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Utility\TableSort;
use Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;

/**
 * ManualSelection Exposed form plugin.
 *
 * @ingroup views_exposed_form_plugins
 *
 * @ViewsExposedForm(
 *   id = "manual_selection",
 *   title = @Translation("Manual selection"),
 *   help = @Translation("Manual selection form")
 * )
 */
class ManualSelection extends ExposedFormPluginBase implements ContainerFactoryPluginInterface {

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['wrap_with_details'] = ['default' => FALSE];
    $options['details_label'] = ['default' => $this->t('Filter')];
    return $options;
  }

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

    $form['wrap_with_details'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Wrap with details element'),
      '#description' => $this->t('Wrap the whole exposed filters section with a details element, so it can be collapsed.'),
      '#default_value' => $this->options['wrap_with_details'],
    ];

    $form['details_label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Details wrapper label'),
      '#description' => $this->t('Text to display in the details wrapper element of the exposed form.'),
      '#default_value' => $this->options['details_label'],
      '#required' => FALSE,
      '#states' => [
        'invisible' => [
          'input[name="exposed_form_options[wrap_with_details]"]' => ['checked' => FALSE],
        ],
      ],
    ];

    // Get all filters of the view and add the possibility to make them visible
    // by default.
    $filters = $this->view->display_handler->getHandlers('filter');
    $form['filter_always_visible'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Select the filters which should be always visible'),
      '#default_value' => $this->options['filter_always_visible'] ?? [],
    ];

    /** @var \Drupal\views\Plugin\views\HandlerBase $filter **/
    foreach ($filters as $label => $filter) {
      if ($filter->isExposed() && $filter->realField !== 'column_selector') {
        $form['filter_always_visible']['#options'][$label] = $filter->options["expose"]["label"];
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function query() {
    $view = $this->view;
    $exposed_data = $view->exposed_data ?? [];
    $sort_by = $exposed_data['sort_by'] ?? NULL;
    if (!empty($sort_by)) {
      // Make sure the original order of sorts is preserved
      // (e.g. a sticky sort is often first)
      if (isset($view->sort[$sort_by])) {
        $view->query->orderby = [];
        foreach ($view->sort as $key => $sort) {
          if (!$sort->isExposed()) {
            $sort->query();
          }
          elseif ($key == $sort_by) {
            if (isset($exposed_data['sort_order']) && in_array($exposed_data['sort_order'], ['ASC', 'DESC'])) {
              $sort->options['order'] = $exposed_data['sort_order'];
            }
            $sort->setRelationship();
            $sort->query();
          }
        }
      }
    }
  }

  /**
   * Sorts checkboxes and always visible filters for each exposed filter.
   *
   * @todo Add Unit test.
   *
   * @param array $form
   *   The form array.
   * @param array $filter_always_visible
   *   The exposed filters which are always visible.
   *
   * @return array
   *   The form array.
   */
  public static function sortCheckboxes(array $form, array $filter_always_visible = []): array {
    $checkboxes = array_filter(array_keys($form), function ($element) {
      return strpos($element, '_check_deactivate');
    });

    $highest_weight = 0;

    foreach ($checkboxes as $checkbox) {
      $filter_name = str_replace('_check_deactivate', '', $checkbox);

      $form[$filter_name]['#weight'] = floatval($form[$filter_name]['#weight']) - 0.2;

      if (isset($form['#info']['filter-' . $filter_name]['operator']) && $form['#info']['filter-' . $filter_name]['operator'] !== "" && isset($form[$form['#info']['filter-' . $filter_name]['operator']])) {
        $form[$form['#info']['filter-' . $filter_name]['operator']]['#weight'] = floatval($form[$filter_name]['#weight']) - 0.001;
        $weight = $form[$form['#info']['filter-' . $filter_name]['operator']]['#weight'];
      }
      else {
        $weight = $form[$filter_name]['#weight'];

        if ($form[$filter_name]['#weight'] > $highest_weight) {
          $highest_weight = $form[$filter_name]['#weight'];
        }
      }

      $form[$checkbox]['#weight'] = floatval($weight) - 0.001;
    }

    if (isset($form["items_per_page"])) {
      $form["items_per_page"]['#weight'] = floatval($highest_weight) + 1;
    }
    if (isset($form["flexible_tables_fieldset"])) {
      $form["flexible_tables_fieldset"]['#weight'] = floatval($highest_weight) + 1.1;
    }
    if (isset($form["selected_filters"])) {
      $form["selected_filters"]['#weight'] = floatval($highest_weight) + 1.2;
    }

    // Sort always_visible filters.
    foreach (array_keys(array_filter($filter_always_visible)) as $filter) {
      $form[$filter]['#weight'] = ($form[$filter]['#weight'] ?? 0) - 100;

      if (($form['#info']['filter-' . $filter]['operator'] ?? FALSE) && $form['#info']['filter-' . $filter]['operator'] !== "" && isset($form[$form['#info']['filter-' . $filter]['operator']])) {
        if ($form[$form['#info']['filter-' . $filter]['operator']]['#weight'] >= $form[$filter]['#weight']) {
          $form[$form['#info']['filter-' . $filter]['operator']]['#weight'] = $form[$filter]['#weight'] - 0.001;
        }
        else {
          $form[$form['#info']['filter-' . $filter]['operator']]['#weight'] = $form[$form['#info']['filter-' . $filter]['operator']]['#weight'] - 100;
        }
      }
    }

    return $form;
  }

  /**
   * Remove fieldsets around filters with operators.
   *
   * @param array $form
   *   The exposed form.
   * @param array $filters
   *   The current filters.
   */
  public static function removeWrapperFieldSets(array &$form, array $filters) {
    foreach ($filters as $filter) {
      $filter = str_replace('filter-', '', $filter);

      if (isset($form[$filter . '_wrapper'])) {
        // Copy filter.
        $form[$filter] = $form[$filter . '_wrapper'][$filter];

        // Copy operator.
        if (isset($form[$filter . '_wrapper'][$filter . '_op'])) {
          $form[$filter . '_op'] = $form[$filter . '_wrapper'][$filter . '_op'];
        }

        // Remove fieldset.
        unset($form[$filter . '_wrapper']);
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function renderExposedForm($block = FALSE) {
    $form = parent::renderExposedForm($block);

    // Set the correct weight for the deactivate_checkboxes.
    $filter_always_visible = $this->options['filter_always_visible'] ?? [];

    return self::sortCheckboxes($form, $filter_always_visible);
  }

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

    $form['#attached']['library'][] = 'flexible_views/manual_selection';
    $form['#attributes']['class'][] = 'manual-selection-form';

    $filters = array_keys($form['#info']);
    // @todo Dependency injection.
    $query = TableSort::getQueryParameters(\Drupal::request());
    $filter_always_visible = isset($this->options['filter_always_visible']) ? array_filter($this->options['filter_always_visible']) : [];
    $manual_select_filter_options = [];

    // We add a hidden field to the form to store the selected filters.
    $form['selected_filters'] = [
      '#type' => 'hidden',
      '#size' => 1024,
      '#maxlength' => 1024,
    ];

    // Remove the column_selector filter from the elements we want to process.
    // Unset the column selector if it is in the filters array.
    if ($column_selector_index = array_search('filter-column_selector', $filters)) {
      unset($filters[$column_selector_index]);
    }
    // The above query does not trigger if the column selector filter is
    // the first filter in the array (or if it is the only exposed filter).
    elseif (array_key_exists('0', $filters) && $filters[0] === 'filter-column_selector') {
      unset($filters[0]);
    }

    // Add the details element if the wrap_with_details option is enabled.
    if ($this->options['wrap_with_details']) {
      $form['manual_selection_filter_details'] = [
        '#type' => 'details',
        '#open' => FALSE,
        '#title' => $this->options['details_label'],
        '#weight' => -180,
        '#attributes' => [
          'style' => 'float: none;clear: both;',
          'class' => ['flexible-views-manual-selection-details'],
        ],
      ];
    }

    self::removeWrapperFieldSets($form, $filters);

    // Deactivate the filters on default.
    foreach ($filters as $filter) {
      $filter_name = str_replace('filter-', '', $filter);

      if (!in_array($filter_name, $filter_always_visible, TRUE)) {
        // Fix for "mismatching in filter naming" - eg. the "combine field
        // filter username or mail" is named user but the $filter_name is
        // filter-combine.
        if (!isset($form[$filter_name]) && isset($form[$form['#info'][$filter]['value']])) {
          $filter_name = $form['#info'][$filter]['value'];
        }

        // Wrap each pair of filters with html div.
        $form[$filter_name]['#suffix'] = '</div>';
        $form[$filter_name]['#chosen'] = FALSE;

        // Add checkboxes to deactivate filter.
        $form[$filter_name . '_check_deactivate'] = [
          '#type' => 'checkbox',
          '#title' => $form['#info'][$filter]['label'],
          '#checked' => array_key_exists($filter_name, $query) ? TRUE : FALSE,
          '#value' => array_key_exists($filter_name, $query) ? TRUE : FALSE,
          '#prefix' => array_key_exists($filter_name, $query) ? "<div class='filter-wrap active'>" : "<div class='filter-wrap'>",
          '#states' => [
            'visible' => [
              ":input[name='{$filter_name}_check_deactivate']" => ['checked' => TRUE],
            ],
          ],
        ];

        // Hide the labels and hide the filters if the checkbox is set to false.
        if (isset($form['#info'][$filter]['operator']) && $form['#info'][$filter]['operator'] !== "" && isset($form[$form['#info'][$filter]['operator']])) {
          $form[$form['#info'][$filter]['operator']]['#title_display'] = 'invisible';
          $form[$form['#info'][$filter]['operator']]['#states']['enabled'] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => TRUE],
          ];
          $form[$form['#info'][$filter]['operator']]['#chosen'] = FALSE;
        }

        $form[$filter_name]['#title_display'] = 'invisible';

        if (isset($form[$filter_name]['value'])) {
          $form[$filter_name]['value']['#states']['enabled'][] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => TRUE],
          ];
          $form[$filter_name]['value']['#states']['invisible'][] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => FALSE],
          ];
        }
        else {
          $form[$filter_name]['#states']['enabled'][] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => TRUE],
          ];
          $form[$filter_name]['#states']['invisible'][] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => FALSE],
          ];
        }

        // If there is an min/max operator, hide the label from the min element.
        if (isset($form[$filter_name]['min'])) {
          $form[$filter_name]['min']['#title_display'] = 'invisible';
          $form[$filter_name]['min']['#states']['enabled'][] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => TRUE],
          ];
        }
        if (isset($form[$filter_name]['max'])) {
          $form[$filter_name]['max']['#attributes']['class'][] = 'label-before';
          $form[$filter_name]['max']['#states']['enabled'][] = [
            ":input[name='{$filter_name}_check_deactivate']" => ['checked' => TRUE],
          ];
        }

        $manual_select_filter_options[$filter_name] = $form['#info'][$filter]['label'];

        if ($this->options['wrap_with_details']) {
          $form['manual_selection_filter_details'][$filter_name . '_check_deactivate'] = $form[$filter_name . '_check_deactivate'];
          unset($form[$filter_name . '_check_deactivate']);

          if (($form['#info'][$filter]['operator'] ?? FALSE) && $form['#info'][$filter]['operator'] !== "" && isset($form[$form['#info'][$filter]['operator']])) {
            $form['manual_selection_filter_details'][$form['#info'][$filter]['operator']] = $form[$form['#info'][$filter]['operator']];
            unset($form[$form['#info'][$filter]['operator']]);
          }

          $form['manual_selection_filter_details'][$filter_name] = $form[$filter_name];
          unset($form[$filter_name]);
        }
      }
      else {
        // Wrap the always visible filters with a wrap.
        if (isset($form['#info'][$filter]['operator']) && $form['#info'][$filter]['operator'] !== "" && isset($form[$form['#info'][$filter]['operator']])) {
          // The filter has an operator.
          $form[$form['#info'][$filter]['operator']]['#title_display'] = 'invisible';
          $form[$form['#info'][$filter]['operator']]['#prefix'] = "<div class='filter-wrap always-visible'><span class='label'>{$form['#info'][$filter]['label']}</span>";
          // Disable chosen.
          $form[$form['#info'][$filter]['operator']]['#chosen'] = FALSE;
        }
        elseif (isset($form[$filter_name])) {
          $form[$filter_name]['#prefix'] = "<div class='filter-wrap always-visible'><span class='label'>{$form['#info'][$filter]['label']}</span>";
        }
        else {
          $form[$form['#info'][$filter]['value']]['#prefix'] = "<div class='filter-wrap always-visible'><span class='label'>{$form['#info'][$filter]['label']}</span>";
        }

        // Fix for "mismatching in filter naming" - eg. the "combine field
        // filter username or mail" is named user but the $filter_name is
        // filter-combine.
        if (!isset($form[$filter_name]) && isset($form[$form['#info'][$filter]['value']])) {
          $filter_name = $form['#info'][$filter]['value'];
        }

        // Label handling.
        if (isset($form[$filter_name]['min'])) {
          $form[$filter_name]['min']['#title_display'] = 'invisible';
        }
        $form[$filter_name]['#title_display'] = 'invisible';

        // Disable chosen.
        $form[$filter_name]['#chosen'] = FALSE;
        $form[$filter_name]['#suffix'] = '</div>';
      }
    }

    // Add manual filter selection.
    $form['manual_select_filter'] = [
      '#type' => 'select',
      '#title' => $this->t('Select filter'),
      '#options' => $manual_select_filter_options,
      '#empty_value' => '',
      '#empty_option' => $this->t('- Select a filter -'),
      '#default_value' => '',
      '#weight' => -10,
      '#chosen' => FALSE,
    ];

    if (count($manual_select_filter_options) === 0) {
      $form['manual_select_filter']['#prefix'] = '<div class="hidden">';
      $form['manual_select_filter']['#suffix'] = '</div>';
    }

    if ($this->options['wrap_with_details']) {
      $form['manual_selection_filter_details']['manual_select_filter'] = $form['manual_select_filter'];
      unset($form['manual_select_filter']);
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc