Спасибо Мистердиди за то, что поставил меня на правильный путь.
Приведенная вами статья помогла, но чтобы найти решение, мне пришлось изучить еще несколько десятков, и в итоге решение пришло.
Итак, для этой задачи единственное верное решение, которое я нашел, это:
- Прочитайте все, что находится в «Радиофильтре».
- Измените «фильтр флажка», чтобы он содержал значение из «радиофильтра» в каждой опции.
- Объедините все "поля состояния" в одно поле с несколькими значениями, чтобы мы могли...
- Используйте контекстные фильтры, чтобы прочитать значение «фильтр флажка» из URL-адреса и найти его в нашем поле с несколькими значениями.
1. Чтение значения из радиофильтра
Я достиг этого с views_pre_view крюк:
функция MY_MODULE_views_pre_view ($ view, $ display_id, массив и $ args) {
// Проверяем, правильный ли вид и режим отображения
если ($view->id() == 'MY_VIEW') {
переключатель ($ display_id) {
случай 'MY_DISPLAY':
// Получить любое значение в Radio Filter и записать его в глобальную переменную
$filter_input = $view->getExposedInput();
глобальный аргумент $;
$arg= $filter_input['RADIO_FILTER'];
}
}
}
(Здесь и далее все ЗАГЛАВНЫМИ БУКВАМИ — это имена, которые вы должны заменить на те, которые вы используете)
С помощью этого кода я читаю содержимое Radio Filter и помещаю его в глобальную переменную. $аргумент.
2. Поместите значение из Radio Filter в Checkbox Filter.
Для этой части я использовал form_views_exposed_form_alter крюк:
функция MY_MODULE_form_views_exposed_form_alter(&$form, $form_state, $form_id) {
// Вызываем глобальную переменную со значением Radio Filter
глобальный аргумент $;
// Преобразование необработанного значения Radio Filter во что-то, что мы можем использовать для контекстного фильтра
если ($arg == '1') {
$arg= 'АС';
}
elseif ($arg == '2') {
$arg= 'НАГРЕВАТЕЛЬ';
}
elseif ($arg == 'Все') {
$аргумент = '';
}
$arg_on = ($arg . '_on');
$arg_off = ($arg . '_off');
// Проверяем, что это правильная форма
если ($form['#id'] == 'EXPOSED_FILTER_FORM_ID') {
// Нам нужны разные значения фильтра, в зависимости от того, выбрано ли значение в Radio Filter или установлено значение по умолчанию ("Все")
если ($аргумент != '') {
$form['CHECKBOX_FILTER']['#options'] = массив(
$arg_on => $arg_on,
$arg_off => $arg_off,
);
}
еще {
$form['CHECKBOX_FILTER']['#options'] = массив(
'_на' => '_на',
'_off' => '_off', );
}
// Если ничего не выбрано, следует считать выбранным все.
если ($form['CHECKBOX_FILTER']['#value'] == '') {
$form['CHECKBOX_FILTER']['#value'] = [$arg_on, $arg_off];
}
}
}
Таким образом я изменяю значения в фильтре Checkbox. Это делает их в значительной степени неработоспособными в качестве открытых фильтров (я не уверен, почему, но в тот момент, когда форма изменяется с помощью хука - она больше ничего не фильтрует), но предоставляет параметры URL, которые мы будем использовать для контекстных фильтров. .
3. Объединение всех полей параметров в одно
Это то, для чего я ожидал найти модуль, но не смог, поэтому hook_entity_presave Это.
функция MY_MODULE_entity_presave (Drupal\Core\Entity\EntityInterface $entity) {
// Здесь мы подготавливаем переменные для каждого поля, которое нам нужно объединить...
если ($entity->bundle() == 'MY_NODE_TYPE') {
$par_ac = ($entity->field_AC_CHECK->значение);
$par_heater = ($entity->field_HEATER_CHECK->значение);
$par_all = ($par_ac . ',' . $par_heater);
// ... а также проверить, нет ли среди них "включенных" или "выключенных"...
если (str_contains($par_all, 'вкл')) {
$par_cont_on = '_on';
}
если (str_contains($par_all, 'выкл')) {
$par_cont_off = '_off';
}
// ... чтобы объединить их все в одно поле и указать общие значения «включено» и «выключено» для случаев, когда радиофильтр не заполнен
$entity->field_par_comb = [$par_ac, $par_heater, $par_cont_on, $par_cont_off];
}
}
Я не особенно доволен тем фактом, что поля жестко закодированы, а не собираются динамически, возможно, позже я придумаю способ их дежесткого кодирования.
Но пока у нас есть поле с несколькими значениями, которое содержит состояние для каждого параметра, и мы, наконец, можем...
4. Используйте контекстный фильтр
Как мы выяснили в п. 2, открытый фильтр Checkbox ничего не делает, когда он изменен. Но мы можем заставить его проверять параметр URL фильтра флажков. Таким образом, если у нас есть «checkbox_filter=heater_on», контекстный фильтр будет искать в нашем многозначном поле из p. 3 для значения «heater_on».
Так как Checkbox Filter может содержать несколько значений, то в настройках фильтра следует выбрать союз "ИЛИ".
Обратите внимание, что Радиофильтр должен быть «не требуется». Это связано с тем, что при первой загрузке представления значения открытого фильтра по умолчанию НЕ отображаются в параметрах URL по какой-то причине. Но, поскольку значение Радиофильтра по умолчанию — «Любой» (и мы должны скрыть его с помощью CSS через :Первый ребенок selector), в нашем коде есть часть, которая учитывает этот случай, заменяя значение радиофильтра «Все» на ''. И, поскольку у нас есть специальная проверка и значения "_on"/"_off" в нашем многозначном поле, это будет работать нормально:
- Если в Radio Filter выбрано значение по умолчанию Any, код не заменит значения Checkbox Filter.
- В настройках просмотра значения фильтра флажков по умолчанию установлены на «_on» и «_off», и фильтр работает.
- Когда пользователь выбирает «AC», «Heater» или любой другой параметр в Radio Filter, он помещается в измененные значения Checkbox Filter, и срабатывает контекстный фильтр.
Это был адский случай для первого опыта разработки модуля Drupal, но он работает безупречно. Клиент доволен, я доволен.