#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 основные вещи из этого процесса:
- Вещи могут и будут редактировать запрос в других перехватах. Я обнаружил, что ввод setLimit
hook_views_query_alter
был переопределен каким-то другим модулем, и к тому времени, когдаhook_views_pre_execute
появится, он будет изменен по сравнению с тем, что я установил ранее. Однако установка его вpre_execute
работает нормально. - Удивительно, но вызов
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?