У меня есть тип узла статьи с полем, ссылающимся на связанные статьи.
Если статья имеет менее 4 ссылок на это поле, мне нужно искать другие статьи, которые
- не являются текущим узлом
- были обновлены менее 2 лет назад
- поставить галочку "избранное"
- поделиться хотя бы одним идентификатором культуры (ссылка на таксономию) И хотя бы одним идентификатором темы (ссылка на таксономию)
И мне действительно интересно, как выполнить эту последнюю потребность...
На основе Выполнение запроса с условием поля объекта с несколькими значениями, я написал следующий код:
<?php
пространство имен Drupal\my_module\Preprocess;
используйте Drupal\Core\DependencyInjection\ContainerInjectionInterface;
используйте Drupal\Core\Entity\EntityTypeManagerInterface;
используйте Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Тип узла предварительной обработки Статья.
*/
класс MyArticle реализует ContainerInjectionInterface {
константа MAX_RELATED_ARTICLES = 4;
/**
* Хранение терминов таксономии.
*
* @var \Drupal\node\NodeStorage
*/
защищенное $nodeStorage;
/**
* Конструктор класса.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* Менеджер типов объектов.
*/
общедоступная функция __construct (EntityTypeManagerInterface $entity_type_manager) {
$this->nodeStorage = $entity_type_manager->getStorage('узел');
}
/**
* {@inheritdoc}
*/
общедоступная статическая функция create(ContainerInterface $container) {
вернуть новую статику(
$container->получить('entity_type.manager')
);
}
/**
* Статья о типе узла предварительной обработки.
*
* массив @param $переменные
* Массив переменных, используемых для рендеринга узла.
*/
предварительная обработка публичной функции (массив и переменные $) {
если ('полный' === $variables['view_mode']) {
$this->preprocessFull($variables);
}
}
/**
* Предварительная обработка статьи типа узла в режиме просмотра full.
*
* массив @param $переменные
* Массив переменных, используемых для рендеринга узла.
*/
защищенная функция preprocessFull (массив и переменные $) {
$узел = $переменные['узел'];
$related_articles = $node->get('related_articles')->referencedEntities();
$themes = $node->get('themes')->referencedEntities();
$cultures = $node->get('cultures')->referencedEntities();
$themes_ids = $cultures_ids = [];
foreach ($темы как $term) {
$themes_ids[] = $term->id();
}
foreach ($культуры как $term) {
$cultures_ids[] = $term->id();
}
$nb_related_articles = количество($related_articles);
если ($nb_related_articles < self::MAX_RELATED_ARTICLES) {
$limit = self::MAX_RELATED_ARTICLES - $nb_related_articles;
$changed_boundary = strtotime('-2 года');
$query = $this->nodeStorage->getQuery()
->условие('тип', 'статья')
->условие('статус', 1)
->условие('nid', $node->id(), '<>')
->условие('любимое', 1)
->условие('изменено', $changed_boundary, '>=')
->диапазон(0, $предел);
$or_themes = $or_cultures = $query->orConditionGroup();
foreach ($themes_ids как $tid) {
$or_themes->условие('культуры', $tid);
}
foreach ($cultures_ids как $tid) {
$or_cultures->условие('темы', $tid);
}
$and = $query->andConditionGroup()
-> условие ($ or_themes);
$запрос->условие($и);
$and = $query->andConditionGroup()
->условие($или_культуры);
$запрос->условие($и);
$node_ids = $запрос->выполнить();
}
}
}
который дает мне следующий запрос:
ВЫБЕРИТЕ «base_table». «vid» КАК «vid», «base_table». «nid» КАК «nid»
ОТ "узла" "базовая_таблица"
ВНУТРЕННЕЕ СОЕДИНЕНИЕ "node_field_data" "node_field_data" ON "node_field_data"."nid" = "base_table"."nid"
ВНУТРЕННЕЕ СОЕДИНЕНИЕ "node__favorite" "node__favorite" ON "node__favorite"."entity_id" = "base_table"."nid"
ЛЕВОЕ СОЕДИНЕНИЕ "node__cultures" "node__cultures" ON "node__cultures"."entity_id" = "base_table"."nid"
LEFT JOIN "node__themes" "node__themes" ON "node__themes"."entity_id" = "base_table"."nid"
ЛЕВОЕ СОЕДИНЕНИЕ "node__cultures" "node__cultures_2" ON "node__cultures_2"."entity_id" = "base_table"."nid"
LEFT JOIN "node__themes" "node__themes_2" ON "node__themes_2"."entity_id" = "base_table"."nid"
ГДЕ ("node_field_data". "тип" = 'статья')
И ("node_field_data". "status" = 'NODE_PUBLISHED')
И ("node_field_data"."nid" <> '19533')
И ("node__favorite"."favorite_value" = '1')
И ("node_field_data". "изменено" >= '1583280325')
И (("node__cultures"."cultures_target_id" = '5077') или ("node__themes"."themes_target_id" = '42') или ("node__themes"."themes_target_id" = '38'))
И (("node__cultures_2"."cultures_target_id" = '5077') или ("node__themes_2"."themes_target_id" = '42') или ("node__themes_2"."themes_target_id" = '38'))
СГРУППИРОВАТЬ ПО base_table.vid, base_table.nid
ПРЕДЕЛ 4 СМЕЩЕНИЕ 0
И это не то, что я ожидал, так как мне нужно условие И между идентификаторами культуры и идентификаторами темы.
Мне нужно что-то вроде:
И (("node__cultures"."cultures_target_id" = '5077') И (("node__themes"."themes_target_id" = '42') или ("node__themes"."themes_target_id" = '38')))
вместо
И (("node__cultures"."cultures_target_id" = '5077') или ("node__themes"."themes_target_id" = '42') или ("node__themes"."themes_target_id" = '38'))
Итак, мой вопрос: есть ли способ добиться этого с помощью And/OrConditionGroup или мне следует использовать подзапросы для сопоставления некоторых конкретных идентификаторов как для тем, так и для культур?