Студия разработки сайтов и приложений

Netspark.ru

Drupal и фильтр по редакциям

Как я уже упоминал, в коробке Drupal 8 есть такой полезный модуль Content Moderation. Он позволяет модерировать материалы на базе редакций (revisions): материал может быть в состоянии (moderation_state) черновик, опубликован, или в архиве. Названия состояний можно менять, можно добавлять и новые состояния, и переходы между ними. При каждой смене состояния материала создается новая редакция. Благодаря этому можно, например, оставить проверенную редакцию опубликованной для всех пользователей сайта и, в то же время, работать с более новой редакцией в состоянии черновика.

Если мы на сайте используем такую модерацию, рано или поздно нам может понадобиться программно загрузить все материалы, у которых последняя редакция в состоянии черновика. Например, чтобы их сосчитать, или еще зачем-то.

Казалось бы, нужно сделать что-то типа:

\Drupal::entityQuery('node')
      ->condition('moderation_state', 'draft')
      ->latestRevision()
      ->execute();

Но не тут-то было. Фильтровать entityQuery по moderation_state — нельзя, нет такого поля. Отфильтровать просто по полю status=0 (т.е. не опубликовано) тоже нельзя: во-первых у нас может быть несколько состояний модерации, в которых материал не опубликован (черновик и архив). Во-вторых, если у нас есть опубликованная редакция, то она будет дефолтной и для нее status=1 (хотя эта проблема решается с помощью latestRevision()).

В общем, надо строить обычный запрос к БД.

Выбираем из редакций:

$query = \Drupal::database()->select('node_field_revision', 'r');

добавляем таблицу состояний модерации и node заодно:

$query->join('node', 'n', 'r.nid=n.nid');
$query->join('content_moderation_state_field_revision', 's', "r.vid=s.content_entity_revision_id AND s.content_entity_type_id='node'");

Чтобы убедиться, что это последняя редакция, добавим проверку что нет в таблице значения vid (revision id) больше данного для выбранного id материала:

$query->leftJoin('node_field_revision', 'r1', 'r.nid = r1.nid AND r1.vid > r.vid');
$query->isNull('r1.nid');

Выберем нужные поля:

$query->fields('r');
$query->fields('s');

Собственно, выберем только черновики:

$query->condition('s.moderation_state', 'draft');

Можем ограничить по типам:

$query->condition('n.type', ['article', 'product', 'another_content_type',], 'IN');

И можно запускать. В результате получится:

$query = \Drupal::database()->select('node_field_revision', 'r');
$query->join('node', 'n', 'r.nid=n.nid');
$query->join('content_moderation_state_field_revision', 's', "r.vid=s.content_entity_revision_id AND s.content_entity_type_id='node'");
$query->leftJoin('node_field_revision', 'r1', 'r.nid = r1.nid AND r1.vid > r.vid');
$query->fields('r');
$query->fields('s');
$query->isNull('r1.nid');
$query->condition('n.type', ['article', 'product', 'another_content_type',], 'IN');
$query->condition('s.moderation_state', 'draft');

$results = $query->execute()->fetchAll();

Похожий запрос строит и вью из модуля Content Moderation, показывающий табличку материалов в модерации.

Комментарии