Drupal 8 — это мощная CMS, которая предоставляет множество инструментов для создания сложных и гибких представлений данных. Один из таких инструментов — модуль Views, который позволяет пользователям создавать и настраивать таблицы и списки данных с помощью графического интерфейса.

Однако иногда возникает необходимость фильтровать данные по составным полям, которые включают в себя несколько значений. В этой статье мы рассмотрим, как создать фильтр по составному полю в Views на Drupal 8 и предоставим примеры программного кода для осуществления этой задачи.

Шаг 1: Создание составного поля в контент-типе

Прежде чем мы начнем создавать фильтр, необходимо убедиться, что у нас есть контент-тип с составным полем. Для этого нам понадобится модуль Field UI, который по умолчанию включается в Drupal 8.

1. Перейдите на страницу Структура → Типы контента и выберите нужный вам контент-тип.

2. Нажмите на ссылку «Управление полями» рядом с выбранным контент-типом.

3. Нажмите на кнопку «Добавить поле» и выберите нужный вам тип поля. Например, тип поля «Текст» или «Список (оутпут с текстовым полем)».

4. Выберите «Составное поле» и настройте его по вашему усмотрению.

5. Нажмите на кнопку «Сохранить и продолжить» и настройте дополнительные параметры поля, если это необходимо.

Шаг 2: Создание обработчика фильтра в коде

Теперь, когда у нас есть контент-тип с составным полем, мы можем создать обработчик фильтра в коде, чтобы его использовать во Views.

1. Создайте каталог с названием «modules/custom» в корневой директории вашего сайта Drupal 8.

2. В каталоге «custom» создайте каталог с названием «custom_views_filter» (вы можете выбрать любое удобное вам название).

3. В каталоге «custom_views_filter» создайте файл с названием «custom_views_filter.info.yml» и добавьте следующий код:

name: Custom Views Filter
type: module
description: 'Custom Views Filter module for filtering composite fields in Views.'
package: Custom
core_version_requirement: ^8 || ^9
dependencies:
  - views
  - field

4. В том же каталоге создайте файл с названием «custom_views_filter.views.inc» и добавьте следующий код:

<?php

use Drupal\views\Plugin\views\display\DisplayPluginInterface;
use Drupal\views\Plugin\views\filter\FilterPluginBase;
use Drupal\views\ViewExecutable;

/**
 * Implements hook_views_data_alter().
 */
function custom_views_filter_views_data_alter(array &$data) {
  $data['node_field_data']['field_composite_field'] = [
    'title' => t('Composite field'),
    'filter' => [
      'title' => t('Composite field filter'),
      'help' => t('Filter by composite field.'),
      'field' => [
        'id' => 'composite_field_filter',
        'click_sort_column' => 'composite_field',
      ],
    ],
  ];
}

/**
 * Composite field filter handler.
 *
 * @ingroup views_filter_handlers
 *
 * @ViewsFilter("composite_field_filter")
 */
class CompositeFieldFilter extends FilterPluginBase {
  /**
   * Implement query().
   */
  public function query() {
    $this->ensureMyTable();
    $this->query->addWhereExpression($this->options['group'], 'CONCAT_WS("", ' . $this->tableAlias . '.field_composite_field__value, ' . $this->tableAlias . '.field_composite_field__value_2) LIKE :composite_field', [':composite_field' => '%' . $this->value . '%']);
  }

  /**
   * Helper function for ensuring the table is joined.
   */
  protected function ensureMyTable() {
    if (!empty($this->tableAlias)) {
      return;
    }

    $this->ensureMyTableByNodeId();
  }

  /**
   * Join the default table.
   */
  protected function ensureMyTableByNodeId() {
    $base_table = $this->view->base_table;

    $join = Views::viewsData()->get($base_table);
    $this->tableAlias = $this->query->ensureTable($base_table, $this->relationship);

    if (isset($join['table']['base']['entity type'])) {
      $entity_type_id = $join['table']['base']['entity type'];
      $entity_assoc = entity_load("@entity_type", (array) $this->view->argument[7]);
    }
    else {
      $entity_type_id = 'node';
      $entity_assoc = entity_load('node', (array) $this->view->argument[7]);
    }

    $this->ensureMyFieldDefinitions();
  }

  /**
   * Ensure the field definition is set for our field.
   */
  protected function ensureMyFieldDefinitions() {
    // Get the composite field definition.
    $field_definition_1 = $this->definition['field']['field_1'];
    $field_definition_2 = $this->definition['field']['field_2'];

    $this->field_alias = $this->query->addField(NULL, $field_definition_1['table'], $field_definition_1['field'], $this->relationship);
    $this->field_alias_2 = $this->query->addField(NULL, $field_definition_2['table'], $field_definition_2['field'], $this->relationship);
  }
}

Шаг 3: Использование фильтрации составных полей в Views

Теперь, когда обработчик фильтра создан, мы можем использовать его внутри Views для фильтрации данных по составным полям.

1. Откройте Views, с которым вы хотите работать.

2. Добавьте фильтр, выбрав «Composite field filter» из списка доступных фильтров.

3. Настройте параметры фильтра согласно своим потребностям.

4. Нажмите на кнопку «Применить» для сохранения настроек фильтра.

Вот и все! Теперь вы можете использовать фильтрацию составных полей в своих Views на Drupal 8.

Дополнительные вопросы и ответы

1. Как создать фильтр по полю, включающему только одно значение?

Для создания фильтра по полю, включающему только одно значение, вам не требуется создавать обработчик фильтра в коде. Вместо этого вы можете использовать стандартный фильтр «Один из списка» или «Строка». Просто добавьте этот фильтр в ваше представление и настройте его параметры по вашему усмотрению.

2. Как создать фильтр по нескольким составным полям?

Для создания фильтра по нескольким составным полям вам нужно добавить все эти поля в ваше представление и настроить каждое поле отдельно. Затем вы можете использовать комбинацию фильтров (например, «И» или «Или») для определения правил фильтрации.

3. Могу ли я создать фильтр по составному полю с использованием модуля Better Exposed Filters?

Да, вы можете использовать модуль Better Exposed Filters для создания более сложных фильтров по составным полям. Просто добавьте фильтр «Composite field filter» как обычно, а затем используйте модуль Better Exposed Filters для настройки внешнего вида и поведения фильтра.