123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- <?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()]);
- }
- }
|