Рейтинг:0

Надеть один открытый фильтр на другой? (Д9)

флаг pk

У меня есть с десяток строковых полей, содержащих объекты и их состояния (например, возьмем «AC_on» и «heater_off»). И у меня есть представление, которое показывает узлы, содержащие эти поля. Задача, которую я пытаюсь решить, заключается в следующем. У пользователя должно быть два набора опций для фильтрации узлов по вышеупомянутым полям:

  • Выбрать один из объектов с помощью переключателя (AC или обогреватель);
  • Чтобы выбрать состояния, в которых ранее выбранная опция должна быть в отфильтрованном наборе узлов (только «вкл.», или только «выкл.», или «вкл.» и «выкл.» — поэтому, очевидно, установите флажки).

Косметически создать желаемые фильтры не составляет большого труда: мы можем использовать фильтр комбинированных полей для набора переключателей (поиск по всем полям объекта и, если пользователь выбирает «AC», отфильтровывать все значения «AC_null»), и еще раз - для флажков (к «Вкл.» относятся те значения, которые содержат «вкл.» и т.д.). Проблема в том, что этот подход не работает :) Второму набору все равно, какой объект с «выключенным» состоянием он отфильтровывает.

Итак, я подумал, что могу каким-то образом передать все, что пользователь выбрал в части радио (AC), в значения фильтра флажка (чтобы он не просто искал «on», а «AC_on»). Проблема в том, что я не могу найти модуль, который позволил бы мне это сделать.

"Представления Зависимые фильтры" вроде просто инструмент для работы, но, к сожалению, он для D7, а у меня D9. Есть ли способ добиться этого? Любая помощь будет высоко оценен.

PS Я не умею программировать, кроме простейших однострочников на PHP и CSS, поэтому решение без кода предпочтительнее.

misterdidi avatar
флаг de
Привет, добро пожаловать в Drupal Answers. Возможно, вам стоит взглянуть на этот учебник https://bouteillenicolas.com/fr/blog-drupal/views-ajax-dynamic-dependent-exposed-filters. Хотя это для D7, логика остается той же для D9 (плюс, hook_form_alter() все еще существует в D9). Боюсь, вы не можете избежать небольшого количества пользовательского кода.
Basil Vlasyuk avatar
флаг pk
Привет @misterdidi! Спасибо. Я уже смирился с тем, что решения без кода в этом случае не существует. Я создал свой собственный модуль, но меня убивает то, что кодовые решения, предложенные для D8, чаще всего не работают на D9 (а решения для D7 почти никогда не работают). Так что их адаптация требует знаний, которых мне не хватает. Эта статья, которую вы прислали, выглядит точно так же, как то, что мне нужно, я проверю ее и вернусь, чтобы сказать, сработало ли это. Еще раз спасибо!
Рейтинг:1
флаг pk

Спасибо Мистердиди за то, что поставил меня на правильный путь. Приведенная вами статья помогла, но чтобы найти решение, мне пришлось изучить еще несколько десятков, и в итоге решение пришло.

Итак, для этой задачи единственное верное решение, которое я нашел, это:

  1. Прочитайте все, что находится в «Радиофильтре».
  2. Измените «фильтр флажка», чтобы он содержал значение из «радиофильтра» в каждой опции.
  3. Объедините все "поля состояния" в одно поле с несколькими значениями, чтобы мы могли...
  4. Используйте контекстные фильтры, чтобы прочитать значение «фильтр флажка» из 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, но он работает безупречно. Клиент доволен, я доволен.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.