278 lines
9.6 KiB
PHP
278 lines
9.6 KiB
PHP
<?php
|
|
|
|
namespace Drupal\comment;
|
|
|
|
use Drupal\Core\Database\Connection;
|
|
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
|
|
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
|
use Drupal\Core\Entity\FieldableEntityInterface;
|
|
use Drupal\Core\Entity\EntityChangedInterface;
|
|
use Drupal\Core\Entity\EntityInterface;
|
|
use Drupal\Core\State\StateInterface;
|
|
use Drupal\Core\Session\AccountInterface;
|
|
use Drupal\user\EntityOwnerInterface;
|
|
|
|
class CommentStatistics implements CommentStatisticsInterface {
|
|
use DeprecatedServicePropertyTrait;
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
|
|
|
|
/**
|
|
* The current database connection.
|
|
*
|
|
* @var \Drupal\Core\Database\Connection
|
|
*/
|
|
protected $database;
|
|
|
|
/**
|
|
* The replica database connection.
|
|
*
|
|
* @var \Drupal\Core\Database\Connection
|
|
*/
|
|
protected $databaseReplica;
|
|
|
|
/**
|
|
* The current logged in user.
|
|
*
|
|
* @var \Drupal\Core\Session\AccountInterface
|
|
*/
|
|
protected $currentUser;
|
|
|
|
/**
|
|
* The entity type manager.
|
|
*
|
|
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
|
*/
|
|
protected $entityTypeManager;
|
|
|
|
/**
|
|
* The state service.
|
|
*
|
|
* @var \Drupal\Core\State\StateInterface
|
|
*/
|
|
protected $state;
|
|
|
|
/**
|
|
* Constructs the CommentStatistics service.
|
|
*
|
|
* @param \Drupal\Core\Database\Connection $database
|
|
* The active database connection.
|
|
* @param \Drupal\Core\Session\AccountInterface $current_user
|
|
* The current logged in user.
|
|
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
|
* The entity type manager.
|
|
* @param \Drupal\Core\State\StateInterface $state
|
|
* The state service.
|
|
* @param \Drupal\Core\Database\Connection|null $database_replica
|
|
* (Optional) the replica database connection.
|
|
*/
|
|
public function __construct(Connection $database, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, StateInterface $state, Connection $database_replica = NULL) {
|
|
$this->database = $database;
|
|
$this->databaseReplica = $database_replica ?: $database;
|
|
$this->currentUser = $current_user;
|
|
$this->entityTypeManager = $entity_type_manager;
|
|
$this->state = $state;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function read($entities, $entity_type, $accurate = TRUE) {
|
|
$connection = $accurate ? $this->database : $this->databaseReplica;
|
|
$stats = $connection->select('comment_entity_statistics', 'ces')
|
|
->fields('ces')
|
|
->condition('ces.entity_id', array_keys($entities), 'IN')
|
|
->condition('ces.entity_type', $entity_type)
|
|
->execute();
|
|
|
|
$statistics_records = [];
|
|
while ($entry = $stats->fetchObject()) {
|
|
$statistics_records[] = $entry;
|
|
}
|
|
return $statistics_records;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function delete(EntityInterface $entity) {
|
|
$this->database->delete('comment_entity_statistics')
|
|
->condition('entity_id', $entity->id())
|
|
->condition('entity_type', $entity->getEntityTypeId())
|
|
->execute();
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function create(FieldableEntityInterface $entity, $fields) {
|
|
$query = $this->database->insert('comment_entity_statistics')
|
|
->fields([
|
|
'entity_id',
|
|
'entity_type',
|
|
'field_name',
|
|
'cid',
|
|
'last_comment_timestamp',
|
|
'last_comment_name',
|
|
'last_comment_uid',
|
|
'comment_count',
|
|
]);
|
|
foreach ($fields as $field_name => $detail) {
|
|
// Skip fields that entity does not have.
|
|
if (!$entity->hasField($field_name)) {
|
|
continue;
|
|
}
|
|
// Get the user ID from the entity if it's set, or default to the
|
|
// currently logged in user.
|
|
$last_comment_uid = 0;
|
|
if ($entity instanceof EntityOwnerInterface) {
|
|
$last_comment_uid = $entity->getOwnerId();
|
|
}
|
|
if (!isset($last_comment_uid)) {
|
|
// Default to current user when entity does not implement
|
|
// EntityOwnerInterface or author is not set.
|
|
$last_comment_uid = $this->currentUser->id();
|
|
}
|
|
// Default to REQUEST_TIME when entity does not have a changed property.
|
|
$last_comment_timestamp = REQUEST_TIME;
|
|
// @todo Make comment statistics language aware and add some tests. See
|
|
// https://www.drupal.org/node/2318875
|
|
if ($entity instanceof EntityChangedInterface) {
|
|
$last_comment_timestamp = $entity->getChangedTimeAcrossTranslations();
|
|
}
|
|
$query->values([
|
|
'entity_id' => $entity->id(),
|
|
'entity_type' => $entity->getEntityTypeId(),
|
|
'field_name' => $field_name,
|
|
'cid' => 0,
|
|
'last_comment_timestamp' => $last_comment_timestamp,
|
|
'last_comment_name' => NULL,
|
|
'last_comment_uid' => $last_comment_uid,
|
|
'comment_count' => 0,
|
|
]);
|
|
}
|
|
$query->execute();
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getMaximumCount($entity_type) {
|
|
return $this->database->query('SELECT MAX(comment_count) FROM {comment_entity_statistics} WHERE entity_type = :entity_type', [':entity_type' => $entity_type])->fetchField();
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getRankingInfo() {
|
|
return [
|
|
'comments' => [
|
|
'title' => t('Number of comments'),
|
|
'join' => [
|
|
'type' => 'LEFT',
|
|
'table' => 'comment_entity_statistics',
|
|
'alias' => 'ces',
|
|
// Default to comment field as this is the most common use case for
|
|
// nodes.
|
|
'on' => "ces.entity_id = i.sid AND ces.entity_type = 'node' AND ces.field_name = 'comment'",
|
|
],
|
|
// Inverse law that maps the highest view count on the site to 1 and 0
|
|
// to 0. Note that the ROUND here is necessary for PostgreSQL and SQLite
|
|
// in order to ensure that the :comment_scale argument is treated as
|
|
// a numeric type, because the PostgreSQL PDO driver sometimes puts
|
|
// values in as strings instead of numbers in complex expressions like
|
|
// this.
|
|
'score' => '2.0 - 2.0 / (1.0 + ces.comment_count * (ROUND(:comment_scale, 4)))',
|
|
'arguments' => [':comment_scale' => \Drupal::state()->get('comment.node_comment_statistics_scale') ?: 0],
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function update(CommentInterface $comment) {
|
|
// Allow bulk updates and inserts to temporarily disable the maintenance of
|
|
// the {comment_entity_statistics} table.
|
|
if (!$this->state->get('comment.maintain_entity_statistics')) {
|
|
return;
|
|
}
|
|
|
|
$query = $this->database->select('comment_field_data', 'c');
|
|
$query->addExpression('COUNT(cid)');
|
|
$count = $query->condition('c.entity_id', $comment->getCommentedEntityId())
|
|
->condition('c.entity_type', $comment->getCommentedEntityTypeId())
|
|
->condition('c.field_name', $comment->getFieldName())
|
|
->condition('c.status', CommentInterface::PUBLISHED)
|
|
->condition('default_langcode', 1)
|
|
->execute()
|
|
->fetchField();
|
|
|
|
if ($count > 0) {
|
|
// Comments exist.
|
|
$last_reply = $this->database->select('comment_field_data', 'c')
|
|
->fields('c', ['cid', 'name', 'changed', 'uid'])
|
|
->condition('c.entity_id', $comment->getCommentedEntityId())
|
|
->condition('c.entity_type', $comment->getCommentedEntityTypeId())
|
|
->condition('c.field_name', $comment->getFieldName())
|
|
->condition('c.status', CommentInterface::PUBLISHED)
|
|
->condition('default_langcode', 1)
|
|
->orderBy('c.created', 'DESC')
|
|
->range(0, 1)
|
|
->execute()
|
|
->fetchObject();
|
|
// Use merge here because entity could be created before comment field.
|
|
$this->database->merge('comment_entity_statistics')
|
|
->fields([
|
|
'cid' => $last_reply->cid,
|
|
'comment_count' => $count,
|
|
'last_comment_timestamp' => $last_reply->changed,
|
|
'last_comment_name' => $last_reply->uid ? '' : $last_reply->name,
|
|
'last_comment_uid' => $last_reply->uid,
|
|
])
|
|
->keys([
|
|
'entity_id' => $comment->getCommentedEntityId(),
|
|
'entity_type' => $comment->getCommentedEntityTypeId(),
|
|
'field_name' => $comment->getFieldName(),
|
|
])
|
|
->execute();
|
|
}
|
|
else {
|
|
// Comments do not exist.
|
|
$entity = $comment->getCommentedEntity();
|
|
// Get the user ID from the entity if it's set, or default to the
|
|
// currently logged in user.
|
|
if ($entity instanceof EntityOwnerInterface) {
|
|
$last_comment_uid = $entity->getOwnerId();
|
|
}
|
|
if (!isset($last_comment_uid)) {
|
|
// Default to current user when entity does not implement
|
|
// EntityOwnerInterface or author is not set.
|
|
$last_comment_uid = $this->currentUser->id();
|
|
}
|
|
$this->database->update('comment_entity_statistics')
|
|
->fields([
|
|
'cid' => 0,
|
|
'comment_count' => 0,
|
|
// Use the changed date of the entity if it's set, or default to
|
|
// REQUEST_TIME.
|
|
'last_comment_timestamp' => ($entity instanceof EntityChangedInterface) ? $entity->getChangedTimeAcrossTranslations() : REQUEST_TIME,
|
|
'last_comment_name' => '',
|
|
'last_comment_uid' => $last_comment_uid,
|
|
])
|
|
->condition('entity_id', $comment->getCommentedEntityId())
|
|
->condition('entity_type', $comment->getCommentedEntityTypeId())
|
|
->condition('field_name', $comment->getFieldName())
|
|
->execute();
|
|
}
|
|
|
|
// Reset the cache of the commented entity so that when the entity is loaded
|
|
// the next time, the statistics will be loaded again.
|
|
$this->entityTypeManager->getStorage($comment->getCommentedEntityTypeId())->resetCache([$comment->getCommentedEntityId()]);
|
|
}
|
|
|
|
}
|