/** * #post_render_cache callback; attaches "X new comments" link metadata. * * @param array $element * A render array with the following keys: * - #markup * - #attached * @param array $context * An array with the following keys: * - entity_type: an entity type * - entity_id: an entity ID * - field_name: a comment field name * * @return array * The updated $element. */ public function attachNewCommentsLinkMetadata(array $element, array $context) { $entity = $this->entityManager->getStorage($context['entity_type'])->load($context['entity_id']); // Build "X new comments" link metadata. $new = $this->commentManager->getCountNewComments($entity); // Early-return if there are zero new comments for the current user. if ($new === 0) { return $element; } $field_name = $context['field_name']; $page_number = $this->entityManager->getStorage('comment')->getNewCommentPageNumber($entity->{$field_name}->comment_count, $new, $entity); $query = $page_number ? array('page' => $page_number) : NULL; // Attach metadata. $element['#attached']['js'][] = array('type' => 'setting', 'data' => array('comment' => array('newCommentsLinks' => array($context['entity_type'] => array($context['field_name'] => array($context['entity_id'] => array('new_comment_count' => (int) $new, 'first_new_comment_link' => $entity->url('canonical', ['query' => $query, 'fragment' => 'new'])))))))); return $element; }
/** * Returns a set of nodes' last read timestamps. * * @param \Symfony\Component\HttpFoundation\Request $request * The request of the page. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * @return \Symfony\Component\HttpFoundation\JsonResponse * The JSON response. */ public function renderNewCommentsNodeLinks(Request $request) { if ($this->currentUser()->isAnonymous()) { throw new AccessDeniedHttpException(); } $nids = $request->request->get('node_ids'); $field_name = $request->request->get('field_name'); if (!isset($nids)) { throw new NotFoundHttpException(); } // Only handle up to 100 nodes. $nids = array_slice($nids, 0, 100); $links = array(); foreach ($nids as $nid) { $node = $this->entityManager->getStorage('node')->load($nid); $new = $this->commentManager->getCountNewComments($node); $page_number = $this->entityManager()->getStorage('comment')->getNewCommentPageNumber($node->{$field_name}->comment_count, $new, $node); $query = $page_number ? array('page' => $page_number) : NULL; $links[$nid] = array('new_comment_count' => (int) $new, 'first_new_comment_link' => $this->getUrlGenerator()->generateFromRoute('entity.node.canonical', array('node' => $node->id()), array('query' => $query, 'fragment' => 'new'))); } return new JsonResponse($links); }
/** * {@inheritdoc} */ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, array &$context) { $entity_links = array(); $view_mode = $context['view_mode']; if ($view_mode == 'search_index' || $view_mode == 'search_result' || $view_mode == 'print' || $view_mode == 'rss') { // Do not add any links if the entity is displayed for: // - search indexing. // - constructing a search result excerpt. // - print. // - rss. return array(); } $fields = $this->commentManager->getFields($entity->getEntityTypeId()); foreach ($fields as $field_name => $detail) { // Skip fields that the entity does not have. if (!$entity->hasField($field_name)) { continue; } $links = array(); $commenting_status = $entity->get($field_name)->status; if ($commenting_status != CommentItemInterface::HIDDEN) { // Entity has commenting status open or closed. $field_definition = $entity->getFieldDefinition($field_name); if ($view_mode == 'teaser') { // Teaser view: display the number of comments that have been posted, // or a link to add new comments if the user has permission, the // entity is open to new comments, and there currently are none. if ($this->currentUser->hasPermission('access comments')) { if (!empty($entity->get($field_name)->comment_count)) { $links['comment-comments'] = array('title' => $this->formatPlural($entity->get($field_name)->comment_count, '1 comment', '@count comments'), 'attributes' => array('title' => $this->t('Jump to the first comment.')), 'fragment' => 'comments', 'url' => $entity->urlInfo()); if ($this->moduleHandler->moduleExists('history')) { $links['comment-new-comments'] = array('title' => '', 'url' => Url::fromRoute('<current>'), 'attributes' => array('class' => 'hidden', 'title' => $this->t('Jump to the first new comment.'), 'data-history-node-last-comment-timestamp' => $entity->get($field_name)->last_comment_timestamp, 'data-history-node-field-name' => $field_name)); } } } // Provide a link to new comment form. if ($commenting_status == CommentItemInterface::OPEN) { $comment_form_location = $field_definition->getSetting('form_location'); if ($this->currentUser->hasPermission('post comments')) { $links['comment-add'] = array('title' => $this->t('Add new comments'), 'language' => $entity->language(), 'attributes' => array('title' => $this->t('Share your thoughts and opinions.')), 'fragment' => 'comment-form'); if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE) { $links['comment-add']['url'] = Url::fromRoute('comment.reply', ['entity_type' => $entity->getEntityTypeId(), 'entity' => $entity->id(), 'field_name' => $field_name]); } else { $links['comment-add'] += ['url' => $entity->urlInfo()]; } } elseif ($this->currentUser->isAnonymous()) { $links['comment-forbidden'] = array('title' => $this->commentManager->forbiddenMessage($entity, $field_name)); } } } else { // Entity in other view modes: add a "post comment" link if the user // is allowed to post comments and if this entity is allowing new // comments. if ($commenting_status == CommentItemInterface::OPEN) { $comment_form_location = $field_definition->getSetting('form_location'); if ($this->currentUser->hasPermission('post comments')) { // Show the "post comment" link if the form is on another page, or // if there are existing comments that the link will skip past. if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE || !empty($entity->get($field_name)->comment_count) && $this->currentUser->hasPermission('access comments')) { $links['comment-add'] = array('title' => $this->t('Add new comment'), 'attributes' => array('title' => $this->t('Share your thoughts and opinions.')), 'fragment' => 'comment-form'); if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE) { $links['comment-add']['url'] = Url::fromRoute('comment.reply', ['entity_type' => $entity->getEntityTypeId(), 'entity' => $entity->id(), 'field_name' => $field_name]); } else { $links['comment-add']['url'] = $entity->urlInfo(); } } } elseif ($this->currentUser->isAnonymous()) { $links['comment-forbidden'] = array('title' => $this->commentManager->forbiddenMessage($entity, $field_name)); } } } } if (!empty($links)) { $entity_links['comment__' . $field_name] = array('#theme' => 'links__entity__comment__' . $field_name, '#links' => $links, '#attributes' => array('class' => array('links', 'inline'))); if ($view_mode == 'teaser' && $this->moduleHandler->moduleExists('history') && $this->currentUser->isAuthenticated()) { $entity_links['comment__' . $field_name]['#cache']['contexts'][] = 'user'; $entity_links['comment__' . $field_name]['#attached']['library'][] = 'comment/drupal.node-new-comments-link'; // Embed the metadata for the "X new comments" link (if any) on this // entity. $entity_links['comment__' . $field_name]['#attached']['drupalSettings']['history']['lastReadTimestamps'][$entity->id()] = (int) history_read($entity->id()); $new_comments = $this->commentManager->getCountNewComments($entity); if ($new_comments > 0) { $page_number = $this->entityManager->getStorage('comment')->getNewCommentPageNumber($entity->{$field_name}->comment_count, $new_comments, $entity, $field_name); $query = $page_number ? ['page' => $page_number] : NULL; $value = ['new_comment_count' => (int) $new_comments, 'first_new_comment_link' => $entity->url('canonical', ['query' => $query, 'fragment' => 'new'])]; $parents = ['comment', 'newCommentsLinks', $entity->getEntityTypeId(), $field_name, $entity->id()]; NestedArray::setValue($entity_links['comment__' . $field_name]['#attached']['drupalSettings'], $parents, $value); } } } } return $entity_links; }
/** * {@inheritdoc} */ 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 = array(array('data' => $this->t('Topic'), 'field' => 'f.title'), array('data' => $this->t('Replies'), 'field' => 'f.comment_count'), array('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('Drupal\\Core\\Database\\Query\\PagerSelectExtender')->extend('Drupal\\Core\\Database\\Query\\TableSortExtender'); $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 = array(); foreach ($result as $record) { $nids[] = $record->nid; } if ($nids) { $nodes = $this->entityManager->getStorage('node')->loadMultiple($nids); $query = $this->connection->select('node_field_data', 'n')->extend('Drupal\\Core\\Database\\Query\\TableSortExtender'); $query->fields('n', array('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', array('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 = array(); 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 = array(); } $topics = array(); $first_new_found = FALSE; foreach ($result as $topic) { if ($account->isAuthenticated()) { // A forum is new if the topic is new, or if there are new comments since // the user's last visit. 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 { // Do not track "new replies" status for topics if the user is anonymous. $topic->new_replies = 0; $topic->new = 0; } // Make sure only one topic is indicated as the first new topic. $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 array('topics' => $topics, 'header' => $header); }