View source
<?php
namespace Drupal\forum;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\PagerSelectExtender;
use Drupal\Core\Database\Query\TableSortExtender;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\comment\CommentManagerInterface;
use Drupal\node\NodeInterface;
class ForumManager implements ForumManagerInterface {
use StringTranslationTrait;
use DependencySerializationTrait {
__wakeup as defaultWakeup;
__sleep as defaultSleep;
}
const NEWEST_FIRST = 1;
const OLDEST_FIRST = 2;
const MOST_POPULAR_FIRST = 3;
const LEAST_POPULAR_FIRST = 4;
protected $configFactory;
protected $entityFieldManager;
protected $entityTypeManager;
protected $connection;
protected $commentManager;
protected $lastPostData = [];
protected $forumStatistics = [];
protected $forumChildren = [];
protected $history = [];
protected $index;
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, Connection $connection, TranslationInterface $string_translation, CommentManagerInterface $comment_manager, EntityFieldManagerInterface $entity_field_manager) {
$this->configFactory = $config_factory;
$this->entityTypeManager = $entity_type_manager;
$this->connection = $connection;
$this->stringTranslation = $string_translation;
$this->commentManager = $comment_manager;
$this->entityFieldManager = $entity_field_manager;
}
public function getTopics($tid, AccountInterface $account) {
$config = $this->configFactory
->get('forum.settings');
$forum_per_page = $config
->get('topics.page_limit');
$sortby = $config
->get('topics.order');
$header = [
[
'data' => $this
->t('Topic'),
'field' => 'f.title',
],
[
'data' => $this
->t('Replies'),
'field' => 'f.comment_count',
],
[
'data' => $this
->t('Last reply'),
'field' => 'f.last_comment_timestamp',
],
];
$order = $this
->getTopicOrder($sortby);
for ($i = 0; $i < count($header); $i++) {
if ($header[$i]['field'] == $order['field']) {
$header[$i]['sort'] = $order['sort'];
}
}
$query = $this->connection
->select('forum_index', 'f')
->extend(PagerSelectExtender::class)
->extend(TableSortExtender::class);
$query
->fields('f');
$query
->condition('f.tid', $tid)
->addTag('node_access')
->addMetaData('base_table', 'forum_index')
->orderBy('f.sticky', 'DESC')
->orderByHeader($header)
->limit($forum_per_page);
$count_query = $this->connection
->select('forum_index', 'f');
$count_query
->condition('f.tid', $tid);
$count_query
->addExpression('COUNT(*)');
$count_query
->addTag('node_access');
$count_query
->addMetaData('base_table', 'forum_index');
$query
->setCountQuery($count_query);
$result = $query
->execute();
$nids = [];
foreach ($result as $record) {
$nids[] = $record->nid;
}
if ($nids) {
$nodes = $this->entityTypeManager
->getStorage('node')
->loadMultiple($nids);
$query = $this->connection
->select('node_field_data', 'n')
->extend(TableSortExtender::class);
$query
->fields('n', [
'nid',
]);
$query
->join('comment_entity_statistics', 'ces', "[n].[nid] = [ces].[entity_id] AND [ces].[field_name] = 'comment_forum' AND [ces].[entity_type] = 'node'");
$query
->fields('ces', [
'cid',
'last_comment_uid',
'last_comment_timestamp',
'comment_count',
]);
$query
->join('forum_index', 'f', '[f].[nid] = [n].[nid]');
$query
->addField('f', 'tid', 'forum_tid');
$query
->join('users_field_data', 'u', '[n].[uid] = [u].[uid] AND [u].[default_langcode] = 1');
$query
->addField('u', 'name');
$query
->join('users_field_data', 'u2', '[ces].[last_comment_uid] = [u2].[uid] AND [u].[default_langcode] = 1');
$query
->addExpression('CASE [ces].[last_comment_uid] WHEN 0 THEN [ces].[last_comment_name] ELSE [u2].[name] END', 'last_comment_name');
$query
->orderBy('f.sticky', 'DESC')
->orderByHeader($header)
->condition('n.nid', $nids, 'IN')
->condition('n.default_langcode', 1);
$result = [];
foreach ($query
->execute() as $row) {
$topic = $nodes[$row->nid];
$topic->comment_mode = $topic->comment_forum->status;
foreach ($row as $key => $value) {
$topic->{$key} = $value;
}
$result[] = $topic;
}
}
else {
$result = [];
}
$topics = [];
$first_new_found = FALSE;
foreach ($result as $topic) {
if ($account
->isAuthenticated()) {
if ($topic->forum_tid != $tid) {
$topic->new = 0;
}
else {
$history = $this
->lastVisit($topic
->id(), $account);
$topic->new_replies = $this->commentManager
->getCountNewComments($topic, 'comment_forum', $history);
$topic->new = $topic->new_replies || $topic->last_comment_timestamp > $history;
}
}
else {
$topic->new_replies = 0;
$topic->new = 0;
}
$topic->first_new = FALSE;
if ($topic->new != 0 && !$first_new_found) {
$topic->first_new = TRUE;
$first_new_found = TRUE;
}
if ($topic->comment_count > 0) {
$last_reply = new \stdClass();
$last_reply->created = $topic->last_comment_timestamp;
$last_reply->name = $topic->last_comment_name;
$last_reply->uid = $topic->last_comment_uid;
$topic->last_reply = $last_reply;
}
$topics[$topic
->id()] = $topic;
}
return [
'topics' => $topics,
'header' => $header,
];
}
protected function getTopicOrder($sortby) {
switch ($sortby) {
case static::NEWEST_FIRST:
return [
'field' => 'f.last_comment_timestamp',
'sort' => 'desc',
];
case static::OLDEST_FIRST:
return [
'field' => 'f.last_comment_timestamp',
'sort' => 'asc',
];
case static::MOST_POPULAR_FIRST:
return [
'field' => 'f.comment_count',
'sort' => 'desc',
];
case static::LEAST_POPULAR_FIRST:
return [
'field' => 'f.comment_count',
'sort' => 'asc',
];
}
}
protected function lastVisit($nid, AccountInterface $account) {
if (empty($this->history[$nid])) {
$result = $this->connection
->select('history', 'h')
->fields('h', [
'nid',
'timestamp',
])
->condition('uid', $account
->id())
->execute();
foreach ($result as $t) {
$this->history[$t->nid] = $t->timestamp > HISTORY_READ_LIMIT ? $t->timestamp : HISTORY_READ_LIMIT;
}
}
return isset($this->history[$nid]) ? $this->history[$nid] : HISTORY_READ_LIMIT;
}
protected function getLastPost($tid) {
if (!empty($this->lastPostData[$tid])) {
return $this->lastPostData[$tid];
}
$query = $this->connection
->select('node_field_data', 'n');
$query
->join('forum', 'f', '[n].[vid] = [f].[vid] AND [f].[tid] = :tid', [
':tid' => $tid,
]);
$query
->join('comment_entity_statistics', 'ces', "[n].[nid] = [ces].[entity_id] AND [ces].[field_name] = 'comment_forum' AND [ces].[entity_type] = 'node'");
$query
->join('users_field_data', 'u', '[ces].[last_comment_uid] = [u].[uid] AND [u].[default_langcode] = 1');
$query
->addExpression('CASE [ces].[last_comment_uid] WHEN 0 THEN [ces].[last_comment_name] ELSE [u].[name] END', 'last_comment_name');
$topic = $query
->fields('ces', [
'last_comment_timestamp',
'last_comment_uid',
])
->condition('n.status', 1)
->orderBy('last_comment_timestamp', 'DESC')
->range(0, 1)
->addTag('node_access')
->execute()
->fetchObject();
$last_post = new \stdClass();
if (!empty($topic->last_comment_timestamp)) {
$last_post->created = $topic->last_comment_timestamp;
$last_post->name = $topic->last_comment_name;
$last_post->uid = $topic->last_comment_uid;
}
$this->lastPostData[$tid] = $last_post;
return $last_post;
}
protected function getForumStatistics($tid) {
if (empty($this->forumStatistics)) {
$query = $this->connection
->select('node_field_data', 'n');
$query
->join('comment_entity_statistics', 'ces', "[n].[nid] = [ces].[entity_id] AND [ces].[field_name] = 'comment_forum' AND [ces].[entity_type] = 'node'");
$query
->join('forum', 'f', '[n].[vid] = [f].[vid]');
$query
->addExpression('COUNT([n].[nid])', 'topic_count');
$query
->addExpression('SUM([ces].[comment_count])', 'comment_count');
$this->forumStatistics = $query
->fields('f', [
'tid',
])
->condition('n.status', 1)
->condition('n.default_langcode', 1)
->groupBy('tid')
->addTag('node_access')
->execute()
->fetchAllAssoc('tid');
}
if (!empty($this->forumStatistics[$tid])) {
return $this->forumStatistics[$tid];
}
}
public function getChildren($vid, $tid) {
if (!empty($this->forumChildren[$tid])) {
return $this->forumChildren[$tid];
}
$forums = [];
$_forums = $this->entityTypeManager
->getStorage('taxonomy_term')
->loadTree($vid, $tid, NULL, TRUE);
foreach ($_forums as $forum) {
if ($count = $this
->getForumStatistics($forum
->id())) {
$forum->num_topics = $count->topic_count;
$forum->num_posts = $count->topic_count + $count->comment_count;
}
else {
$forum->num_topics = 0;
$forum->num_posts = 0;
}
$forum->last_post = $this
->getLastPost($forum
->id());
$forums[$forum
->id()] = $forum;
}
$this->forumChildren[$tid] = $forums;
return $forums;
}
public function getIndex() {
if ($this->index) {
return $this->index;
}
$vid = $this->configFactory
->get('forum.settings')
->get('vocabulary');
$index = $this->entityTypeManager
->getStorage('taxonomy_term')
->create([
'tid' => 0,
'container' => 1,
'parents' => [],
'isIndex' => TRUE,
'vid' => $vid,
]);
$index->forums = $this
->getChildren($vid, 0);
$this->index = $index;
return $index;
}
public function resetCache() {
$this->index = NULL;
$this->history = [];
}
public function checkNodeType(NodeInterface $node) {
$field_definitions = $this->entityFieldManager
->getFieldDefinitions('node', $node
->bundle());
return !empty($field_definitions['taxonomy_forums']);
}
public function unreadTopics($term, $uid) {
$query = $this->connection
->select('node_field_data', 'n');
$query
->join('forum', 'f', '[n].[vid] = [f].[vid] AND [f].[tid] = :tid', [
':tid' => $term,
]);
$query
->leftJoin('history', 'h', '[n].[nid] = [h].[nid] AND [h].[uid] = :uid', [
':uid' => $uid,
]);
$query
->addExpression('COUNT([n].[nid])', 'count');
return $query
->condition('status', 1)
->condition('n.default_langcode', 1)
->condition('n.created', HISTORY_READ_LIMIT, '>')
->isNull('h.nid')
->addTag('node_access')
->execute()
->fetchField();
}
public function __sleep() {
$vars = $this
->defaultSleep();
unset($vars['history'], $vars['index'], $vars['lastPostData'], $vars['forumChildren'], $vars['forumStatistics']);
return $vars;
}
public function __wakeup() {
$this
->defaultWakeup();
$this->history = [];
$this->lastPostData = [];
$this->forumChildren = [];
$this->forumStatistics = [];
$this->index = NULL;
}
}