configurable_views_filter_block-1.0.x-dev/src/Plugin/Block/ConfigurableViewsExposedFilterBlock.php

src/Plugin/Block/ConfigurableViewsExposedFilterBlock.php
<?php

namespace Drupal\configurable_views_filter_block\Plugin\Block;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\views\Plugin\Block\ViewsExposedFilterBlock as CoreViewsExposedFilterBlock;

/**
 * Views Exposed Filter block type with configurable form fields per instance.
 *
 * @Block(
 *   id = "configurable_views_filter_block_block",
 *   admin_label = @Translation("Views Exposed Filter Block (configurable form)"),
 *   deriver = "Drupal\views\Plugin\Derivative\ViewsExposedFilterBlock"
 * )
 */
class ConfigurableViewsExposedFilterBlock extends CoreViewsExposedFilterBlock {

  /**
   * The views filters.
   *
   * @var array
   */
  protected $filters = NULL;

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'visible_filters' => [],
      'no_groups' => FALSE,
      'no_reset' => FALSE,
      'no_sort' => FALSE,
      'no_pager' => FALSE,
    ] + parent::defaultConfiguration();
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildConfigurationForm($form, $form_state);

    // Visible filters.
    $this->buildFilterConfigurationFormOptions($form, $form_state);

    // Additional visibility options.
    $this->buildAdditionalConfigurationFormOptions($form, $form_state);

    return $form;
  }

  /**
   * Build filters configuration form options.
   *
   * @param array $form
   *   The configuration form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  protected function buildFilterConfigurationFormOptions(array &$form, FormStateInterface $form_state) {
    $options = $this->getExposedFilters();

    $form['visible_filters'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Visible filters'),
      '#options' => $options,
      '#default_value' => array_filter($this->configuration['visible_filters']),
    ];

    if (empty($options)) {
      $form['visible_filters']['info'] = ['#markup' => $this->t('The view has no exposed filters.')];
    }
  }

  /**
   * Build additional configuration form options.
   *
   * @param array $form
   *   The configuration form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   */
  protected function buildAdditionalConfigurationFormOptions(array &$form, FormStateInterface $form_state) {
    $options = [
      'no_groups' => $this->t('Remove form groups'),
    ];
    $default_value = [
      'no_groups' => $this->configuration['no_groups'] ? 'no_groups' : FALSE,
    ];

    // Reset option only if the reset button is enabled.
    if (($exposed_form_plugin = $this->view->display_handler->getPlugin('exposed_form'))
      && !empty($exposed_form_plugin->options['reset_button'])) {
      $options['no_reset'] = $this->t('Remove reset button');
      $default_value['no_reset'] = $this->configuration['no_reset'] ? 'no_reset' : FALSE;
    }

    // Sort option only if some sort criteria is exposed in view.
    if ($this->viewsHasExposedSorts()) {
      $options['no_sort'] = $this->t('Hide sort criteria');
      $default_value['no_sort'] = $this->configuration['no_sort'] ? 'no_sort' : FALSE;
    }

    // Pager options only if exposed.
    if ($this->view->getPager()->usesExposed()) {
      $options['no_pager'] = $this->t('Hide pager options');
      $default_value['no_pager'] = $this->configuration['no_pager'] ? 'no_pager' : FALSE;
    }

    $form['form_options'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Other visibility options'),
      '#options' => $options,
      '#default_value' => $default_value,
    ];
  }

  /**
   * Checks if the current view has exposed sorts.
   *
   * @return bool
   *   TRUE if the view has exposed sorts, FALSE otherwise.
   */
  protected function viewsHasExposedSorts() {
    $sorts = $this->view->display_handler->getHandlers('sort');
    foreach ($sorts as $sort_plugin) {
      if ($sort_plugin->isExposed()) {
        return TRUE;
      }
    }

    return FALSE;
  }

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

    $this->configuration['visible_filters'] = array_filter($form_state->getValue('visible_filters'));

    $form_options = $form_state->getValue('form_options');
    $this->configuration['no_groups'] = !empty($form_options['no_groups']);
    $this->configuration['no_reset'] = !empty($form_options['no_reset']);
    $this->configuration['no_sort'] = !empty($form_options['no_sort']);
    $this->configuration['no_pager'] = !empty($form_options['no_pager']);
  }

  /**
   * {@inheritdoc}
   */
  public function build() : array {
    $build = parent::build();

    // Apply visibility options.
    $this->applyVisibilityOptions($build);

    // Set an new unique form id from the build id if available, or by adding a
    // random number to the current id.
    $new_form_id = $build['#build_id'] ?? $build['#id'] . rand(100, 999);
    $build['#id'] = $new_form_id;
    $build['#attributes']['data-drupal-selector'] = $new_form_id;

    // Add CSS.
    $build['#attached']['library'][] = 'configurable_views_filter_block/configurable_views_filter_block.theme';

    return $build;
  }

  /**
   * Apply visibility options to the exposed filters form or element.
   *
   * Recursive method.
   *
   * @param array $element
   *   The current element to process.
   */
  protected function applyVisibilityOptions(array &$element) {
    foreach (Element::children($element) as $child_name) {
      if (!$this->applyCommonVisibilityOptions($child_name, $element[$child_name])
        && !$this->applyFieldVisibilityOptions($child_name, $element[$child_name])) {

        // Check and apply fieldset visibility options.
        $this->applyFieldsetVisibilityOptions($child_name, $element[$child_name]);

        // Check inner elements for field groups and unmanaged form elements.
        $this->applyVisibilityOptions($element[$child_name]);
      }
    }
  }

  /**
   * Checks and apply common visibility options to a given form element.
   *
   * @param string $name
   *   The element name in the build array.
   * @param array $element
   *   The element to evaluate and be processed.
   *
   * @return bool
   *   Boolean indicating if the options were actually applied.
   */
  protected function applyCommonVisibilityOptions($name, array &$element) {
    $applied = FALSE;
    switch ($name) {
      case 'reset':
        // Found the reset submit button.
        if ($applied = !empty($this->configuration['no_reset'])) {
          $this->hideElement($element);
        }
        break;

      case 'sort_by':
      case 'sort_order':
        // Sort form fields found.
        if ($applied = !empty($this->configuration['no_sort'])) {
          $this->hideElement($element);
        }
        break;

      case 'items_per_page':
      case 'offset':
        // Pager options related field found.
        if ($applied = !empty($this->configuration['no_pager'])) {
          $this->hideElement($element);
        }
        break;
    }

    return $applied;
  }

  /**
   * Checks and apply field visibility options to a given form element.
   *
   * @param string $name
   *   The element name in the build array.
   * @param array $element
   *   The element to evaluate and be processed.
   *
   * @return bool
   *   Boolean indicating if the options were actually applied.
   */
  protected function applyFieldVisibilityOptions($name, array &$element) {
    $filters = $this->getExposedFilters();
    if (!isset($filters[$name])) {
      // Element is not a filter field.
      return FALSE;
    }

    if (!in_array($name, $this->configuration['visible_filters'])) {
      // Non visible field found, it will be hide.
      $this->hideElement($element);
    }

    return TRUE;
  }

  /**
   * Checks and apply fieldset visibility options to a given form element.
   *
   * @param string $name
   *   The element name in the build array.
   * @param array $element
   *   The element to evaluate and be processed.
   *
   * @return bool
   *   Boolean indicating if the options were actually applied.
   */
  protected function applyFieldsetVisibilityOptions($name, array &$element) {
    // Fieldsets have wrapper elements containing the legend, so we need to hide
    // the full fieldset.
    if (
      isset($element['#type']) &&
      $element['#type'] == 'fieldset' &&
      str_ends_with($name, '_wrapper')
    ) {
      // Get the name of the actual element that is wrapped.
      $str = substr($name, 0, strlen($name) - 8);
      if (!in_array($str, $this->configuration['visible_filters'])) {
        $this->hideElement($element);
        return TRUE;
      }
    }

    $applies = isset($element['#type'])
      && $element['#type'] == 'details'
      && $this->configuration['no_groups'];

    // Convert collapsible containers into simple containers.
    if ($applies) {
      $element['#type'] = 'container';
      unset($element['#title']);
      unset($element['#open']);
      $element['#theme_wrappers'] = ['container'];
    }

    return $applies;
  }

  /**
   * Get the view existing exposed filters.
   *
   * @return array
   *   The view's exposed filter labels keyed by name.
   */
  protected function getExposedFilters() {
    if ($this->filters === NULL) {
      $this->filters = [];
      foreach ($this->view->display_handler->getHandlers('filter') as $plugin) {
        if ($plugin->isExposed() && $exposed_info = $plugin->exposedInfo()) {
          $this->filters[$exposed_info['value']] = trim($exposed_info['label'] . ' (' . $exposed_info['value'] . ')');
        }
      }
    }

    return $this->filters;
  }

  /**
   * Hides a given element.
   *
   * Current form field values are lost by using the "#access" property, so
   * form fields are only visually hidden.
   *
   * @param array $element
   *   The form element to be hide.
   */
  protected function hideElement(array &$element) {
    $element['#prefix'] = '<div class="hidden-exposed-filter">';
    $element['#suffix'] = '</div>';
  }

}

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

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