diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 32404be..a284603 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -1324,7 +1324,7 @@ function comment_num_new($nid, $timestamp = 0) { if ($user->isAuthenticated() && module_exists('history')) { // Retrieve the timestamp at which the current user last viewed this node. if (!$timestamp) { - $timestamp = history_read($nid); + $timestamp = history_read('node', $nid); } $timestamp = ($timestamp > HISTORY_READ_LIMIT ? $timestamp : HISTORY_READ_LIMIT); diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/views/field/NodeNewComments.php b/core/modules/comment/lib/Drupal/comment/Plugin/views/field/NodeNewComments.php index 6da4cb1..b4b1800 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/views/field/NodeNewComments.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/views/field/NodeNewComments.php @@ -111,9 +111,9 @@ public function preRender(&$values) { } if ($nids) { - $result = $this->database->query('SELECT n.nid, COUNT(c.cid) as num_comments FROM {node} n INNER JOIN {comment} c ON n.nid = c.nid - LEFT JOIN {history} h ON h.nid = n.nid AND h.uid = :h_uid WHERE n.nid IN (:nids) - AND c.changed > GREATEST(COALESCE(h.timestamp, :timestamp), :timestamp) AND c.status = :status GROUP BY n.nid', array( + $result = $this->database->query("SELECT n.nid, COUNT(c.cid) as num_comments FROM {node} n INNER JOIN {comment} c ON n.nid = c.nid + LEFT JOIN {history} h ON h.entity_id = n.nid AND h.entity_type = 'node' AND h.uid = :h_uid WHERE n.nid IN (:nids) + AND c.changed > GREATEST(COALESCE(h.timestamp, :timestamp), :timestamp) AND c.status = :status GROUP BY n.nid", array( ':status' => COMMENT_PUBLISHED, ':h_uid' => $user->id(), ':nids' => $nids, diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php index bf7cdb5..b4d437d 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php @@ -157,7 +157,10 @@ function setEnvironment(array $info) { // comment_num_new() relies on history_read(), so ensure that no one has // seen the node of this comment. - db_delete('history')->condition('nid', $this->node->id())->execute(); + db_delete('history') + ->condition('entity_id', $this->node->id()) + ->condition('entity_type', 'node') + ->execute(); } else { $cids = db_query("SELECT cid FROM {comment}")->fetchCol(); diff --git a/core/modules/forum/lib/Drupal/forum/ForumManager.php b/core/modules/forum/lib/Drupal/forum/ForumManager.php index 92c2a7c..7c5cbde 100644 --- a/core/modules/forum/lib/Drupal/forum/ForumManager.php +++ b/core/modules/forum/lib/Drupal/forum/ForumManager.php @@ -330,11 +330,12 @@ protected function lastVisit($nid) { if (empty($this->history[$nid])) { $result = $this->connection->select('history', 'h') - ->fields('h', array('nid', 'timestamp')) + ->fields('h', array('entity_id', 'timestamp')) ->condition('uid', $user->id()) + ->condition('entity_type', 'node') ->execute(); foreach ($result as $t) { - $this->history[$t->nid] = $t->timestamp > HISTORY_READ_LIMIT ? $t->timestamp : HISTORY_READ_LIMIT; + $this->history[$t->entity_id] = $t->timestamp > HISTORY_READ_LIMIT ? $t->timestamp : HISTORY_READ_LIMIT; } } return isset($this->history[$nid]) ? $this->history[$nid] : HISTORY_READ_LIMIT; @@ -497,7 +498,7 @@ public function checkNodeType(NodeInterface $node) { 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', array(':tid' => $term)); - $query->leftJoin('history', 'h', 'n.nid = h.nid AND h.uid = :uid', array(':uid' => $uid)); + $query->leftJoin('history', 'h', "n.nid = h.entity_id AND h.entity_type = 'node' AND h.uid = :uid", array(':uid' => $uid)); $query->addExpression('COUNT(n.nid)', 'count'); return $query ->condition('status', 1) @@ -505,7 +506,7 @@ public function unreadTopics($term, $uid) { // field language and just fall back to the default language. ->condition('n.default_langcode', 1) ->condition('n.created', HISTORY_READ_LIMIT, '>') - ->isNull('h.nid') + ->isNull('h.entity_id') ->addTag('node_access') ->execute() ->fetchField(); diff --git a/core/modules/history/history.install b/core/modules/history/history.install index dcfd871..086c8f7 100644 --- a/core/modules/history/history.install +++ b/core/modules/history/history.install @@ -13,13 +13,20 @@ function history_schema() { 'description' => 'A record of which {users} have read which {node}s.', 'fields' => array( 'uid' => array( - 'description' => 'The {users}.uid that read the {node} nid.', + 'description' => 'The {users}.uid that read the entity_id.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, ), - 'nid' => array( - 'description' => 'The {node}.nid that was read.', + 'entity_type' => array( + 'type' => 'varchar', + 'not null' => TRUE, + 'default' => 'node', + 'length' => 255, + 'description' => 'The entity_type of the entity was read.', + ), + 'entity_id' => array( + 'description' => 'The entity_id that was read.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, @@ -31,11 +38,19 @@ function history_schema() { 'default' => 0, ), ), - 'primary key' => array('uid', 'nid'), + 'primary key' => array( + 'uid', + 'entity_id', + array('entity_type', 32), + ), 'indexes' => array( - 'nid' => array('nid'), + 'history_entity' => array( + 'entity_id', + array('entity_type', 32), + ), ), ); return $schema; } + diff --git a/core/modules/history/history.module b/core/modules/history/history.module index 38dd8ab..fb5d304 100644 --- a/core/modules/history/history.module +++ b/core/modules/history/history.module @@ -10,6 +10,7 @@ */ use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Session\AccountInterface; /** * Entities changed before this time are always shown as read. @@ -22,34 +23,38 @@ /** * Retrieves the timestamp for the current user's last view of a specified node. * - * @param int $nid - * A node ID. + * @param string $entity_type + * The entity type. + * @param int $entity_id + * The entity ID. * * @return int * If a node has been previously viewed by the user, the timestamp in seconds * of when the last view occurred; otherwise, zero. */ -function history_read($nid) { +function history_read($entity_type, $entity_id) { global $user; $history = &drupal_static(__FUNCTION__, array()); - if (!isset($history[$nid])) { - $history[$nid] = db_query("SELECT timestamp FROM {history} WHERE uid = :uid AND nid = :nid", array(':uid' => $user->id(), ':nid' => $nid))->fetchObject(); + if (!isset($history[$entity_id])) { + $history[$entity_id] = db_query("SELECT timestamp FROM {history} WHERE uid = :uid AND entity_id = :entity_id AND entity_type = :entity_type", array(':uid' => $user->id(), ':entity_id' => $entity_id, ':entity_type' => $entity_type))->fetchObject(); } - return (isset($history[$nid]->timestamp) ? $history[$nid]->timestamp : 0); + return (isset($history[$entity_id]->timestamp) ? $history[$entity_id]->timestamp : 0); } /** * Updates 'last viewed' timestamp of the specified entity for the current user. * - * @param $nid - * The node ID that has been read. - * @param $account + * @param string $entity_type + * The entity type. + * @param int $entity_id + * The entity ID that has been read. + * @param \Drupal\Core\Session\AccountInterface $account * (optional) The user account to update the history for. Defaults to the * current user. */ -function history_write($nid, $account = NULL) { +function history_write($entity_type, $entity_id, AccountInterface $account = NULL) { global $user; if (!isset($account)) { @@ -60,7 +65,8 @@ function history_write($nid, $account = NULL) { db_merge('history') ->key(array( 'uid' => $account->id(), - 'nid' => $nid, + 'entity_id' => $entity_id, + 'entity_type' => $entity_type, )) ->fields(array('timestamp' => REQUEST_TIME)) ->execute(); @@ -81,7 +87,8 @@ function history_cron() { */ function history_node_delete(EntityInterface $node) { db_delete('history') - ->condition('nid', $node->id()) + ->condition('entity_id', $node->id()) + ->condition('entity_type', 'node') ->execute(); } diff --git a/core/modules/history/history.views.inc b/core/modules/history/history.views.inc index ed36820..9bf753b 100644 --- a/core/modules/history/history.views.inc +++ b/core/modules/history/history.views.inc @@ -24,8 +24,9 @@ function history_views_data() { 'node' => array( 'table' => 'history', 'left_field' => 'nid', - 'field' => 'nid', + 'field' => 'entity_id', 'extra' => array( + array('field' => 'entity_type', 'value' => 'node'), array('field' => 'uid', 'value' => '***CURRENT_USER***', 'numeric' => TRUE), ), ), diff --git a/core/modules/history/lib/Drupal/history/Tests/Views/HistoryTimestampTest.php b/core/modules/history/lib/Drupal/history/Tests/Views/HistoryTimestampTest.php index 182174c..6eaca65 100644 --- a/core/modules/history/lib/Drupal/history/Tests/Views/HistoryTimestampTest.php +++ b/core/modules/history/lib/Drupal/history/Tests/Views/HistoryTimestampTest.php @@ -54,14 +54,16 @@ public function testHandlers() { db_insert('history') ->fields(array( 'uid' => $account->id(), - 'nid' => $nodes[0]->id(), + 'entity_id' => $nodes[0]->id(), + 'entity_type' => 'node', 'timestamp' => REQUEST_TIME - 100, ))->execute(); db_insert('history') ->fields(array( 'uid' => $account->id(), - 'nid' => $nodes[1]->id(), + 'entity_id' => $nodes[1]->id(), + 'entity_type' => 'node', 'timestamp' => REQUEST_TIME + 100, ))->execute(); diff --git a/core/modules/node/node.install b/core/modules/node/node.install index 02cc7a0..9cee01b 100644 --- a/core/modules/node/node.install +++ b/core/modules/node/node.install @@ -692,9 +692,37 @@ function node_update_8011() { } /** - * Enable History module. + * Convert {history} table to new format and enable History module. */ function node_update_8012() { + // Drop all keys to properly rename constraints. + db_drop_primary_key('history'); + db_drop_index('history', 'nid'); + // Add new column. + db_add_field('history', 'entity_type', array( + 'type' => 'varchar', + 'not null' => TRUE, + 'default' => 'node', + 'length' => 255, + 'description' => 'The entity_type of the entity was read.', + )); + db_change_field('history', 'nid', 'entity_id', array( + 'description' => 'The entity_id that was read.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + )); + // Create new indexes. + db_add_primary_key('history', array( + 'uid', + 'entity_id', + array('entity_type', 32), + )); + db_add_index('history', 'history_entity', array( + 'entity_id', + array('entity_type', 32), + )); + // Enable the history module without re-installing the schema. module_enable(array('history')); } diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 6d3708d..98fcf71 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -285,7 +285,7 @@ function node_mark($nid, $timestamp) { return MARK_READ; } if (!isset($cache[$nid])) { - $cache[$nid] = history_read($nid); + $cache[$nid] = history_read('node', $nid); } if ($cache[$nid] == 0 && $timestamp > HISTORY_READ_LIMIT) { return MARK_NEW; @@ -588,8 +588,8 @@ function node_show(EntityInterface $node, $message = FALSE) { $nodes = array('nodes' => node_view_multiple(array($node->id() => $node), 'full')); // Update the history table, stating that this user viewed this node. - if (module_exists('history')) { - history_write($node->id()); + if (Drupal::moduleHandler()->moduleExists('history')) { + history_write('node', $node->id()); } return $nodes;