Как я могу ограничить результаты запроса 0 в hook_views_pre_execute в Drupal 8?

#php #drupal-8 #drupal-modules #drupal-views

#php #drupal-8 #drupal-модули #drupal-просмотры

Вопрос:

Я разрабатываю веб-сайт Drupal 8, где для определенных типов контента отображается блочное представление, в котором отображается связанная информация из других типов контента. Мне нужно динамически ограничивать результаты запроса на основе состояния модерации посещаемого узла (в отличие от содержимого в представлении). Мой план состоял в том, чтобы захватить состояние модерации узла из контекста страницы и использовать это для ограничения результатов просмотра. Однако функция setLimit, похоже, не влияет на результаты запроса:

 function myModule_views_pre_execute(ViewExecutable $view) {
  // Only for my_view view.
  if ($view->id() == 'my_view') {
    $list_node = Drupal::request()->attributes->get('node');
    if($list_node->moderation_state->value == "approved"){

    }else{
      dpm("node is not approved, setting limit to 0");
      $view->query->setLimit(0);
    }   
  }

  

Я видел похожие вопросы, задаваемые пару лет назад, но ответы, похоже, указывали на изменение пейджера вместо запроса… кажется странным, что пейджер каким-то образом будет привязан непосредственно к самому sql-запросу, а не только к отображению или маршалингу результатов. Разве функция setLimit не просто редактирует «ОГРАНИЧИВАЮЩУЮ» часть конечного SQL-запроса? Или пейджер действительно изменяет ограничение после запуска моего кода? Заранее большое спасибо!

ОБНОВЛЕНИЕ 9.11.2020

Я поиграл с пробованием разных вещей в разных перехватах, проверяя фактический запрос, сгенерированный через интерфейс редактирования представления, поскольку это предоставляет выражение «LIMIT #». Я узнал 2 основные вещи из этого процесса:

  1. Вещи могут и будут редактировать запрос в других перехватах. Я обнаружил, что ввод setLimit hook_views_query_alter был переопределен каким-то другим модулем, и к тому времени, когда hook_views_pre_execute появится, он будет изменен по сравнению с тем, что я установил ранее. Однако установка его в pre_execute работает нормально.
  2. Удивительно, но вызов setLimit(0) полностью удаляет выражение ОГРАНИЧЕНИЯ из запроса! Однако любое другое значение, похоже, работает нормально.

Это ожидаемое поведение? Запрещает ли Drupal устанавливать ограничение для запроса на 0? Или я должен где-то регистрировать проблему?

Ответ №1:

Вместо этого вы должны использовать hook_views_query_alter.

 function myModule_views_pre_execute(ViewExecutable $view, QueryPluginBase $query) {
  // Only for my_view view.
  if ($view->id() == 'my_view') {
    $list_node = Drupal::request()->attributes->get('node');
    if($list_node->moderation_state->value == "approved"){

    }else{
      dpm("node is not approved, setting limit to 0");
      $query->setLimit(0);
    }   
  }

  

Комментарии:

1. Я начал с попытки hook_views_query_alter, в конечном итоге перейдя к hook_views_pre_execute , поскольку я подумал, что, возможно, что-то еще редактировало запрос после меня. Однако это тоже не сработало. Единственный способ, который я нашел для маскировки результатов, — это выполнить $view->result = [] в hook_views_post_execute , однако я хотел бы избежать этого варианта, поскольку запрос может быть дорогостоящим, и нет необходимости запускать его, если он маскируется

2. Сначала вы должны попробовать настроить представления для отладки и показать фактический SQL-запрос. Таким образом, вам будет лучше проверять результирующий запрос.

3. Если действительно какой-то другой модуль изменил запрос на просмотр после вас, попробуйте отложить свой хук, установив больший вес модуля .

4. ах, хорошая идея. Оказывается, что да, что-то редактирует запрос после вызова моего query_alter. Однако, если я помещу setLimit в pre_execute, изменение, похоже, произойдет, НО происходит что-то очень интересное — когда я делаю setLimit(0) , это полностью удаляет выражение «LIMIT» из запроса! Однако, если я это сделаю setLimit(1) , я смогу увидеть выражение «ОГРАНИЧИТЬ 1» в запросе, и оно ограничивает результаты. Это ошибка или предполагаемое поведение? Фактически я хочу, чтобы запрос вообще не выполнялся, есть ли лучший способ выполнить это?

5. Вероятно, это сделано специально. Я не смог найти соответствующую документацию об этом, но я предполагаю, что QueryInterface::range() используемая реализация правильно обрабатывает 0 так же, как и NULL. Это понятно, потому что, если люди хотят 0 элементов, им лучше вообще не выполнять запрос. Возможно, вместо setLimit() вы можете добавить условие, которое всегда будет FALSE?