drupal/core/modules/history/history.module

235 lines
6.5 KiB
Plaintext
Raw Normal View History

<?php
/**
* @file
* Records which users have read which content.
*
* @todo
* - Generic helper for _forum_user_last_visit() + history_read().
* - Generic helper for node_mark().
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
/**
* Entities changed before this time are always shown as read.
*
* Entities changed within this time may be marked as new, updated, or read,
* depending on their state for the current user. Defaults to 30 days ago.
*/
define('HISTORY_READ_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
/**
* Implements hook_help().
*/
function history_help($path, $arg) {
switch ($path) {
case 'admin/help#history':
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The History module keeps track of which content a user has read. Its data is available through the Views module. The History module marks content as <em>new</em> or <em>updated</em> depending on the last time the user viewed that content. It also provides a filter to <a href="!views-help">Views</a> to show new or updated content. History records older than one month will be removed during cron. This means that content older than one month will always be considered <em>read</em>. The module does not provide a user interface. For more information, see the online documentation for the <a href="!url">History module</a>.', array('!views-help' => \Drupal::url('help.page', array ('name' => 'views')), '!url' => 'https://drupal.org/documentation/modules/history')) . '</p>';
return $output;
}
}
/**
* Retrieves the timestamp for the current user's last view of a specified node.
*
* @param int $nid
* A node 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) {
$history = history_read_multiple(array($nid));
return $history[$nid];
}
/**
* Retrieves the last viewed timestamp for each of the passed node IDs.
*
* @param array $nids
* An array of node IDs.
*
* @return array
* Array of timestamps keyed by node ID. 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_multiple($nids) {
$history = &drupal_static(__FUNCTION__, array());
$return = array();
$nodes_to_read = array();
foreach ($nids as $nid) {
if (isset($history[$nid])) {
$return[$nid] = $history[$nid];
}
else {
// Initialize value if current user has not viewed the node.
$nodes_to_read[$nid] = 0;
}
}
if (empty($nodes_to_read)) {
return $return;
}
$result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN(:nids)', array(
':uid' => \Drupal::currentUser()->id(),
':nids' => array_keys($nodes_to_read),
));
foreach ($result as $row) {
$nodes_to_read[$row->nid] = (int) $row->timestamp;
}
$history += $nodes_to_read;
return $return + $nodes_to_read;
}
/**
* Updates 'last viewed' timestamp of the specified entity for the current user.
*
* @param $nid
* The node ID that has been read.
* @param $account
* (optional) The user account to update the history for. Defaults to the
* current user.
*/
function history_write($nid, $account = NULL) {
if (!isset($account)) {
$account = \Drupal::currentUser();
}
if ($account->isAuthenticated()) {
db_merge('history')
->key(array(
'uid' => $account->id(),
'nid' => $nid,
))
->fields(array('timestamp' => REQUEST_TIME))
->execute();
// Update static cache.
$history = &drupal_static('history_read_multiple', array());
$history[$nid] = REQUEST_TIME;
}
}
/**
* Implements hook_cron().
*/
function history_cron() {
db_delete('history')
->condition('timestamp', HISTORY_READ_LIMIT, '<')
->execute();
}
/**
* Implements hook_node_view_alter().
*/
function history_node_view_alter(&$build, EntityInterface $node, EntityViewDisplayInterface $display) {
// Update the history table, stating that this user viewed this node.
if (($display->originalMode === 'full') && \Drupal::currentUser()->isAuthenticated()) {
$build['#attached'] = array(
'js' => array(
// When the window's "load" event is triggered, mark the node as read.
// This still allows for Drupal behaviors (which are triggered on the
// "DOMContentReady" event) to add "new" and "updated" indicators.
array(
'data' => 'window.addEventListener("load",function(){Drupal.history.markAsRead(' . $node->id() . ');},false);',
'type' => 'inline',
),
),
'library' => array(
array('history', 'drupal.history'),
),
);
}
}
/**
* Implements hook_node_delete().
*/
function history_node_delete(EntityInterface $node) {
db_delete('history')
->condition('nid', $node->id())
->execute();
}
/**
* Implements hook_user_cancel().
*/
function history_user_cancel($edit, $account, $method) {
switch ($method) {
case 'user_cancel_reassign':
db_delete('history')
->condition('uid', $account->id())
->execute();
break;
}
}
/**
* Implements hook_user_delete().
*/
function history_user_delete($account) {
db_delete('history')
->condition('uid', $account->id())
->execute();
}
/**
* Implements hook_library_info().
*/
function history_library_info() {
$libraries['drupal.history'] = array(
'title' => 'History',
'version' => \Drupal::VERSION,
'js' => array(
drupal_get_path('module', 'history') . '/js/history.js' => array(),
),
'dependencies' => array(
array('system', 'jquery'),
array('system', 'drupalSettings'),
array('system', 'drupal'),
array('system', 'drupal.ajax'),
),
);
return $libraries;
}
/**
* #post_render_cache callback; attaches the last read timestamp for a node.
*
* @param array $element
* A render array with the following keys:
* - #markup
* - #attached
* @param array $context
* An array with the following keys:
* - node_id: the node ID for which to attach the last read timestamp.
*
* @return array $element
* The updated $element.
*/
function history_attach_timestamp(array $element, array $context) {
$element['#attached']['js'][] = array(
'type' => 'setting',
'data' => array(
'history' => array(
'lastReadTimestamps' => array(
$context['node_id'] => (int) history_read($context['node_id']),
)
),
),
);
return $element;
}