toolshed-8.x-1.x-dev/modules/toolshed_search/src/Plugin/views/filter/EntityBundleFilter.php

modules/toolshed_search/src/Plugin/views/filter/EntityBundleFilter.php
<?php

namespace Drupal\toolshed_search\Plugin\views\filter;

use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SortArray;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\search_api\Plugin\views\filter\SearchApiFilterTrait;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\filter\InOperator;
use Drupal\views\ViewExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * A Search API datasource filter with more exposed filter options.
 *
 * @ViewsFilter("toolshed_entity_bundle_filter")
 */
class EntityBundleFilter extends InOperator {

  use SearchApiFilterTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The entity type bundle info service.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected EntityTypeBundleInfoInterface $entityBundleInfo;

  /**
   * Constructs a custom variant of a Toolshed entity bundle filter.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info
   *   The core bundle info service.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_bundle_info) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);

    $this->entityTypeManager = $entity_type_manager;
    $this->entityBundleInfo = $entity_bundle_info;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
      $container->get('entity_type.bundle.info')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL): void {
    parent::init($view, $display, $options);
    $this->operator = strtolower($this->options["operator"]);
  }

  /**
   * {@inheritdoc}
   */
  public function getValueOptions(): array {
    if (!isset($this->valueOptions)) {
      $this->valueOptions = $this->exposedInfo()['bundle_labels'] ?? [];

      // Get all the available bundles from the datasources.
      foreach ($this->getIndex()->getDatasources() as $datasource) {
        if (!($entityTypeId = $datasource->getEntityTypeId())) {
          continue;
        }

        foreach ($datasource->getBundles() as $bundleId => $bundleLabel) {
          $key = "$entityTypeId:$bundleId";
          if (empty($this->valueOptions[$key])) {
            $this->valueOptions[$key] = $bundleLabel;
          }
        }
      }
    }

    return $this->valueOptions;
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions(): array {
    $options = parent::defineOptions();

    $options['operator'] = ['default' => 'in'];
    $options['value'] = ['default' => []];

    // Setup additional exposed filter options. The new options help control
    // who the entity bundle selection will appear when exposed.
    $exposeOpts = &$options['expose']['contains'];
    $exposeOpts['select_type'] = ['default' => 'checkbox'];
    $exposeOpts['bundle_labels'] = ['default' => []];

    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultExposeOptions(): void {
    parent::defaultExposeOptions();

    $this->options['expose']['select_type'] = 'checkbox';
    $this->options['expose']['bundle_labels'] = [];
  }

  /**
   * Display the filter on the administrative summary.
   */
  public function adminSummary(): string|object {
    return $this->operator . ' [' . implode(', ', $this->value) . ']';
  }

  /**
   * Get the operatiors supported for filtering.
   *
   * @return array
   *   An array of operators that this filter uses, with the query operation
   *   as the key, and information about the operation as the value.
   */
  public function operators(): array {
    return [
      'in' => [
        'title' => $this->t('Is one of'),
        'short' => $this->t('in'),
        'short_single' => '=',
        'values' => 1,
      ],
      'not in' => [
        'title' => $this->t('Is not one of'),
        'short' => $this->t('not in'),
        'short_single' => '<>',
        'values' => 1,
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function valueForm(&$form, FormStateInterface $form_state): void {
    parent::valueForm($form, $form_state);

    $bundles = [];
    foreach ($this->getIndex()->getDatasources() as $datasource) {
      $entityTypeId = $datasource->getEntityTypeId();
      $entityType = $entityTypeId ? $this->entityTypeManager->getDefinition($entityTypeId, FALSE) : NULL;

      if ($entityType) {
        $entityLabel = Html::escape($entityType->getLabel());
        $bundles[$entityLabel] = [];

        foreach ($datasource->getBundles() as $key => $bundleLabel) {
          $bundles[$entityLabel]["$entityTypeId:$key"] = $bundleLabel;
        }
      }
    }

    // List all bundles available to the search index, grouped by entity types.
    $form['value'] = [
      '#type' => 'select',
      '#title' => $this->t('Include entity bundles'),
      '#multiple' => TRUE,
      '#options' => $bundles,
      '#default_value' => $this->value ?? [],
    ];
  }

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

    $form['expose']['select_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Selection type'),
      '#options' => [
        'checkbox' => $this->t('Check boxes/radio buttons'),
        'select' => $this->t('Select list'),
      ],
      '#default_value' => $this->options['expose']['select_type'],
    ];

    // Create a table to allow the assignment of labels for use on exposed
    // forms. Show all labels, but only the entity types selected for in the
    // values options will be available.
    $form['expose']['bundle_labels'] = [
      '#type' => 'table',
      '#tree' => TRUE,
      '#header' => [
        'bundle' => $this->t('Entity bundle'),
        'label' => $this->t('Label'),
        'weight' => $this->t('Sort weight'),
      ],
      '#tabledrag' => [
        [
          'action' => 'order',
          'relationship' => 'sibling',
          'group' => 'bundle-weight',
        ],
      ],
    ];

    $availBundles = [];
    $entityLabels = [];
    foreach ($this->getIndex()->getDatasources() as $datasource) {
      if ($entityTypeId = $datasource->getEntityTypeId()) {
        if ($entityType = $this->entityTypeManager->getDefinition($entityTypeId, FALSE)) {
          foreach ($datasource->getBundles() as $bundle => $label) {
            $key = "{$entityTypeId}:{$bundle}";
            $entityLabels[$key] = $label . ' (' . $entityType->getLabel() . ')';
            $availBundles[$key] = $label;
          }
        }
      }
    }

    $defaultLabels = $this->options['expose']['bundle_labels'];
    $table = &$form['expose']['bundle_labels'];
    foreach ($defaultLabels + $availBundles as $bundleKey => $label) {
      if (!isset($availBundles[$bundleKey])) {
        continue;
      }

      $table[$bundleKey] = [
        '#attributes' => ['class' => ['draggable']],

        'bundle' => [
          '#plain_text' => $entityLabels[$bundleKey],
        ],
        'label' => [
          '#type' => 'textfield',
          '#placeholder' => $availBundles[$bundleKey],
          '#default_value' => @$defaultLabels[$bundleKey] ?: '',
        ],
        'weight' => [
          '#type' => 'weight',
          '#default_value' => 0,
          '#attributes' => ['class' => ['bundle-weight']],
        ],
      ];
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitExposeForm($form, FormStateInterface $form_state): void {
    $parents = $form['expose']['bundle_labels']['#parents'];
    $values = $form_state->getValue($parents);
    uasort($values, SortArray::sortByWeightElement(...));

    $bundleLabels = [];
    foreach ($values as $key => $info) {
      $title = trim($info['label']);
      $bundleLabels[$key] = $title ?: FALSE;
    }

    // Set the cleaned up bundle labels.
    $form_state->setValue($parents, $bundleLabels);
    parent::submitExposeForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function acceptExposedInput($input): bool {
    if (empty($this->options['exposed'])) {
      return TRUE;
    }

    $filterKey = $this->options['expose']['identifier'];
    $value = $input[$filterKey];

    if (is_array($value)) {
      $value = array_filter($value);
    }
    else {
      $value = empty($value) ? [] : [$value => $value];
    }

    // If not empty, then change the query value to the options set here.
    // If this is empty fallback to what was set for the filter options.
    if ($value) {
      $this->value = $value;
    }

    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function buildExposedForm(&$form, FormStateInterface $form_state): void {
    if (empty($this->options['exposed'])) {
      return;
    }

    $exposeOpts = $this->options['expose'];
    $filterKey = $exposeOpts['identifier'];
    $element = [
      '#options' => [],
      '#required' => $exposeOpts['required'] ?? FALSE,
    ];

    // Determine which form element to use based on the 'select_type' option,
    // and if multiple values are allowed.
    if ($exposeOpts['select_type'] === 'checkbox') {
      if (empty($exposeOpts['multiple'])) {
        $element['#type'] = 'radios';

        if (!$element['#required']) {
          $element['#options'][0] = $this->t('Any');
          $element['#default_value'] = 0;
        }
      }
      else {
        $element['#type'] = 'checkboxes';
        $element['#default_value'] = [];
      }
    }
    else {
      $element['#type'] = 'select';
      $element['#empty_option'] = $this->t('- Any -');
      $element['#multiple'] = $exposeOpts['multiple'] ?? FALSE;
    }

    // If limited selection / values then iterate only the bundle options
    // available. Otherwise, list all values allowed for this Search API index.
    $element['#options'] = $this->options['value']
      ? array_intersect_key($this->getValueOptions(), $this->options['value'])
      : $this->getValueOptions();

    $form[$filterKey] = $element;
  }

  /**
   * {@inheritdoc}
   */
  public function query(): void {
    if ($this->value) {
      $this->ensureMyTable();

      $op = $this->operator;
      if (count($this->value) === 1) {
        $op = $this->operators()[$this->operator]['short_single'] ?? $this->operator;
      }

      $group = $this->options['group'];
      $field = "$this->tableAlias.$this->realField";

      /** @var \Drupal\search_api\Plugin\views\query\SearchApiQuery $query */
      $query = $this->query;
      $query->addWhere($group, $field, $this->value, $op);
    }
  }

}

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

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