comparison core/modules/comment/src/CommentStatistics.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children 12f9dff5fda9
comparison
equal deleted inserted replaced
-1:000000000000 0:c75dbcec494b
1 <?php
2
3 namespace Drupal\comment;
4
5 use Drupal\Core\Database\Connection;
6 use Drupal\Core\Entity\FieldableEntityInterface;
7 use Drupal\Core\Entity\EntityChangedInterface;
8 use Drupal\Core\Entity\EntityInterface;
9 use Drupal\Core\Entity\EntityManagerInterface;
10 use Drupal\Core\State\StateInterface;
11 use Drupal\Core\Session\AccountInterface;
12 use Drupal\user\EntityOwnerInterface;
13
14 class CommentStatistics implements CommentStatisticsInterface {
15
16 /**
17 * The current database connection.
18 *
19 * @var \Drupal\Core\Database\Connection
20 */
21 protected $database;
22
23 /**
24 * The current logged in user.
25 *
26 * @var \Drupal\Core\Session\AccountInterface
27 */
28 protected $currentUser;
29
30 /**
31 * The entity manager service.
32 *
33 * @var \Drupal\Core\Entity\EntityManagerInterface
34 */
35 protected $entityManager;
36
37 /**
38 * The state service.
39 *
40 * @var \Drupal\Core\State\StateInterface
41 */
42 protected $state;
43
44 /**
45 * Constructs the CommentStatistics service.
46 *
47 * @param \Drupal\Core\Database\Connection $database
48 * The active database connection.
49 * @param \Drupal\Core\Session\AccountInterface $current_user
50 * The current logged in user.
51 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
52 * The entity manager service.
53 * @param \Drupal\Core\State\StateInterface $state
54 * The state service.
55 */
56 public function __construct(Connection $database, AccountInterface $current_user, EntityManagerInterface $entity_manager, StateInterface $state) {
57 $this->database = $database;
58 $this->currentUser = $current_user;
59 $this->entityManager = $entity_manager;
60 $this->state = $state;
61 }
62
63 /**
64 * {@inheritdoc}
65 */
66 public function read($entities, $entity_type, $accurate = TRUE) {
67 $options = $accurate ? [] : ['target' => 'replica'];
68 $stats = $this->database->select('comment_entity_statistics', 'ces', $options)
69 ->fields('ces')
70 ->condition('ces.entity_id', array_keys($entities), 'IN')
71 ->condition('ces.entity_type', $entity_type)
72 ->execute();
73
74 $statistics_records = [];
75 while ($entry = $stats->fetchObject()) {
76 $statistics_records[] = $entry;
77 }
78 return $statistics_records;
79 }
80
81 /**
82 * {@inheritdoc}
83 */
84 public function delete(EntityInterface $entity) {
85 $this->database->delete('comment_entity_statistics')
86 ->condition('entity_id', $entity->id())
87 ->condition('entity_type', $entity->getEntityTypeId())
88 ->execute();
89 }
90
91 /**
92 * {@inheritdoc}
93 */
94 public function create(FieldableEntityInterface $entity, $fields) {
95 $query = $this->database->insert('comment_entity_statistics')
96 ->fields([
97 'entity_id',
98 'entity_type',
99 'field_name',
100 'cid',
101 'last_comment_timestamp',
102 'last_comment_name',
103 'last_comment_uid',
104 'comment_count',
105 ]);
106 foreach ($fields as $field_name => $detail) {
107 // Skip fields that entity does not have.
108 if (!$entity->hasField($field_name)) {
109 continue;
110 }
111 // Get the user ID from the entity if it's set, or default to the
112 // currently logged in user.
113 $last_comment_uid = 0;
114 if ($entity instanceof EntityOwnerInterface) {
115 $last_comment_uid = $entity->getOwnerId();
116 }
117 if (!isset($last_comment_uid)) {
118 // Default to current user when entity does not implement
119 // EntityOwnerInterface or author is not set.
120 $last_comment_uid = $this->currentUser->id();
121 }
122 // Default to REQUEST_TIME when entity does not have a changed property.
123 $last_comment_timestamp = REQUEST_TIME;
124 // @todo Make comment statistics language aware and add some tests. See
125 // https://www.drupal.org/node/2318875
126 if ($entity instanceof EntityChangedInterface) {
127 $last_comment_timestamp = $entity->getChangedTimeAcrossTranslations();
128 }
129 $query->values([
130 'entity_id' => $entity->id(),
131 'entity_type' => $entity->getEntityTypeId(),
132 'field_name' => $field_name,
133 'cid' => 0,
134 'last_comment_timestamp' => $last_comment_timestamp,
135 'last_comment_name' => NULL,
136 'last_comment_uid' => $last_comment_uid,
137 'comment_count' => 0,
138 ]);
139 }
140 $query->execute();
141 }
142
143 /**
144 * {@inheritdoc}
145 */
146 public function getMaximumCount($entity_type) {
147 return $this->database->query('SELECT MAX(comment_count) FROM {comment_entity_statistics} WHERE entity_type = :entity_type', [':entity_type' => $entity_type])->fetchField();
148 }
149
150 /**
151 * {@inheritdoc}
152 */
153 public function getRankingInfo() {
154 return [
155 'comments' => [
156 'title' => t('Number of comments'),
157 'join' => [
158 'type' => 'LEFT',
159 'table' => 'comment_entity_statistics',
160 'alias' => 'ces',
161 // Default to comment field as this is the most common use case for
162 // nodes.
163 'on' => "ces.entity_id = i.sid AND ces.entity_type = 'node' AND ces.field_name = 'comment'",
164 ],
165 // Inverse law that maps the highest view count on the site to 1 and 0
166 // to 0. Note that the ROUND here is necessary for PostgreSQL and SQLite
167 // in order to ensure that the :comment_scale argument is treated as
168 // a numeric type, because the PostgreSQL PDO driver sometimes puts
169 // values in as strings instead of numbers in complex expressions like
170 // this.
171 'score' => '2.0 - 2.0 / (1.0 + ces.comment_count * (ROUND(:comment_scale, 4)))',
172 'arguments' => [':comment_scale' => \Drupal::state()->get('comment.node_comment_statistics_scale') ?: 0],
173 ],
174 ];
175 }
176
177 /**
178 * {@inheritdoc}
179 */
180 public function update(CommentInterface $comment) {
181 // Allow bulk updates and inserts to temporarily disable the maintenance of
182 // the {comment_entity_statistics} table.
183 if (!$this->state->get('comment.maintain_entity_statistics')) {
184 return;
185 }
186
187 $query = $this->database->select('comment_field_data', 'c');
188 $query->addExpression('COUNT(cid)');
189 $count = $query->condition('c.entity_id', $comment->getCommentedEntityId())
190 ->condition('c.entity_type', $comment->getCommentedEntityTypeId())
191 ->condition('c.field_name', $comment->getFieldName())
192 ->condition('c.status', CommentInterface::PUBLISHED)
193 ->condition('default_langcode', 1)
194 ->execute()
195 ->fetchField();
196
197 if ($count > 0) {
198 // Comments exist.
199 $last_reply = $this->database->select('comment_field_data', 'c')
200 ->fields('c', ['cid', 'name', 'changed', 'uid'])
201 ->condition('c.entity_id', $comment->getCommentedEntityId())
202 ->condition('c.entity_type', $comment->getCommentedEntityTypeId())
203 ->condition('c.field_name', $comment->getFieldName())
204 ->condition('c.status', CommentInterface::PUBLISHED)
205 ->condition('default_langcode', 1)
206 ->orderBy('c.created', 'DESC')
207 ->range(0, 1)
208 ->execute()
209 ->fetchObject();
210 // Use merge here because entity could be created before comment field.
211 $this->database->merge('comment_entity_statistics')
212 ->fields([
213 'cid' => $last_reply->cid,
214 'comment_count' => $count,
215 'last_comment_timestamp' => $last_reply->changed,
216 'last_comment_name' => $last_reply->uid ? '' : $last_reply->name,
217 'last_comment_uid' => $last_reply->uid,
218 ])
219 ->keys([
220 'entity_id' => $comment->getCommentedEntityId(),
221 'entity_type' => $comment->getCommentedEntityTypeId(),
222 'field_name' => $comment->getFieldName(),
223 ])
224 ->execute();
225 }
226 else {
227 // Comments do not exist.
228 $entity = $comment->getCommentedEntity();
229 // Get the user ID from the entity if it's set, or default to the
230 // currently logged in user.
231 if ($entity instanceof EntityOwnerInterface) {
232 $last_comment_uid = $entity->getOwnerId();
233 }
234 if (!isset($last_comment_uid)) {
235 // Default to current user when entity does not implement
236 // EntityOwnerInterface or author is not set.
237 $last_comment_uid = $this->currentUser->id();
238 }
239 $this->database->update('comment_entity_statistics')
240 ->fields([
241 'cid' => 0,
242 'comment_count' => 0,
243 // Use the changed date of the entity if it's set, or default to
244 // REQUEST_TIME.
245 'last_comment_timestamp' => ($entity instanceof EntityChangedInterface) ? $entity->getChangedTimeAcrossTranslations() : REQUEST_TIME,
246 'last_comment_name' => '',
247 'last_comment_uid' => $last_comment_uid,
248 ])
249 ->condition('entity_id', $comment->getCommentedEntityId())
250 ->condition('entity_type', $comment->getCommentedEntityTypeId())
251 ->condition('field_name', $comment->getFieldName())
252 ->execute();
253 }
254
255 // Reset the cache of the commented entity so that when the entity is loaded
256 // the next time, the statistics will be loaded again.
257 $this->entityManager->getStorage($comment->getCommentedEntityTypeId())->resetCache([$comment->getCommentedEntityId()]);
258 }
259
260 }