Remove unused local variables
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / comment / CommentHandler.class.php
1 <?php
2
3 namespace wcf\system\comment;
4
5 use wcf\data\comment\CommentEditor;
6 use wcf\data\comment\CommentList;
7 use wcf\data\comment\response\CommentResponse;
8 use wcf\data\comment\response\CommentResponseList;
9 use wcf\data\comment\StructuredComment;
10 use wcf\data\comment\StructuredCommentList;
11 use wcf\data\object\type\ObjectType;
12 use wcf\data\object\type\ObjectTypeCache;
13 use wcf\data\user\notification\UserNotificationList;
14 use wcf\system\comment\manager\ICommentManager;
15 use wcf\system\exception\NamedUserException;
16 use wcf\system\exception\SystemException;
17 use wcf\system\exception\UserInputException;
18 use wcf\system\flood\FloodControl;
19 use wcf\system\message\censorship\Censorship;
20 use wcf\system\reaction\ReactionHandler;
21 use wcf\system\SingletonFactory;
22 use wcf\system\user\activity\event\UserActivityEventHandler;
23 use wcf\system\user\notification\UserNotificationHandler;
24 use wcf\system\WCF;
25
26 /**
27 * Provides methods for comment object handling.
28 *
29 * @author Alexander Ebert
30 * @copyright 2001-2020 WoltLab GmbH
31 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
32 * @package WoltLabSuite\Core\System\Comment
33 */
34 class CommentHandler extends SingletonFactory
35 {
36 /**
37 * cached object types
38 * @var mixed[][]
39 */
40 protected $cache;
41
42 /**
43 * @inheritDoc
44 */
45 protected function init()
46 {
47 $this->cache = [
48 'objectTypes' => [],
49 'objectTypeIDs' => [],
50 ];
51
52 $cache = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.comment.commentableContent');
53 foreach ($cache as $objectType) {
54 $this->cache['objectTypes'][$objectType->objectTypeID] = $objectType;
55 $this->cache['objectTypeIDs'][$objectType->objectType] = $objectType->objectTypeID;
56 }
57 }
58
59 /**
60 * Returns the id of the comment object type with the given name or `null` if no
61 * such object type exists.
62 *
63 * @param string $objectType
64 * @return int|null
65 */
66 public function getObjectTypeID($objectType)
67 {
68 return $this->cache['objectTypeIDs'][$objectType] ?? null;
69 }
70
71 /**
72 * Returns the comment object type with the given name or `null` if no such
73 * object type exists.
74 *
75 * @param int $objectTypeID
76 * @return ObjectType|null
77 */
78 public function getObjectType($objectTypeID)
79 {
80 return $this->cache['objectTypes'][$objectTypeID] ?? null;
81 }
82
83 /**
84 * Returns comment manager object for given object type.
85 *
86 * @param string $objectType
87 * @return ICommentManager
88 * @throws SystemException
89 */
90 public function getCommentManager($objectType)
91 {
92 $objectTypeID = $this->getObjectTypeID($objectType);
93 if ($objectTypeID === null) {
94 throw new SystemException("Unable to find object type for '" . $objectType . "'");
95 }
96
97 return $this->getObjectType($objectTypeID)->getProcessor();
98 }
99
100 /**
101 * Returns a comment list for a given object type and object id.
102 *
103 * @param ICommentManager $commentManager
104 * @param int $objectTypeID
105 * @param int $objectID
106 * @param bool $readObjects
107 * @return StructuredCommentList
108 */
109 public function getCommentList(ICommentManager $commentManager, $objectTypeID, $objectID, $readObjects = true)
110 {
111 $commentList = new StructuredCommentList($commentManager, $objectTypeID, $objectID);
112 if ($readObjects) {
113 $commentList->readObjects();
114 }
115
116 return $commentList;
117 }
118
119 /**
120 * Removes all comments for given objects.
121 *
122 * @param string $objectType
123 * @param int[] $objectIDs
124 */
125 public function deleteObjects($objectType, array $objectIDs)
126 {
127 $objectTypeID = $this->getObjectTypeID($objectType);
128 $objectTypeObj = $this->getObjectType($objectTypeID);
129
130 // get comment ids
131 $commentList = new CommentList();
132 $commentList->getConditionBuilder()->add('comment.objectTypeID = ?', [$objectTypeID]);
133 $commentList->getConditionBuilder()->add('comment.objectID IN (?)', [$objectIDs]);
134 $commentList->readObjectIDs();
135 $commentIDs = $commentList->getObjectIDs();
136
137 // no comments -> skip
138 if (empty($commentIDs)) {
139 return;
140 }
141
142 // get response ids
143 $responseList = new CommentResponseList();
144 $responseList->getConditionBuilder()->add('comment_response.commentID IN (?)', [$commentIDs]);
145 $responseList->readObjectIDs();
146 $responseIDs = $responseList->getObjectIDs();
147
148 // delete likes
149 $notificationObjectTypes = [];
150 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType . '.like.notification')) {
151 $notificationObjectTypes[] = $objectTypeObj->objectType . '.like.notification';
152 }
153
154 ReactionHandler::getInstance()->removeReactions(
155 'com.woltlab.wcf.comment',
156 $commentIDs,
157 $notificationObjectTypes
158 );
159
160 // delete activity events
161 if (UserActivityEventHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType . '.recentActivityEvent')) {
162 UserActivityEventHandler::getInstance()
163 ->removeEvents($objectTypeObj->objectType . '.recentActivityEvent', $commentIDs);
164 }
165 // delete notifications
166 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType . '.notification')) {
167 UserNotificationHandler::getInstance()
168 ->removeNotifications($objectTypeObj->objectType . '.notification', $commentIDs);
169 }
170
171 if (!empty($responseIDs)) {
172 // delete likes (for responses)
173 $notificationObjectTypes = [];
174 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType . '.response.like.notification')) {
175 $notificationObjectTypes[] = $objectTypeObj->objectType . '.response.like.notification';
176 }
177
178 ReactionHandler::getInstance()->removeReactions(
179 'com.woltlab.wcf.comment.response',
180 $responseIDs,
181 $notificationObjectTypes
182 );
183
184 // delete activity events (for responses)
185 if (UserActivityEventHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType . '.response.recentActivityEvent')) {
186 UserActivityEventHandler::getInstance()
187 ->removeEvents($objectTypeObj->objectType . '.response.recentActivityEvent', $responseIDs);
188 }
189 // delete notifications (for responses)
190 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectTypeObj->objectType . '.response.notification')) {
191 UserNotificationHandler::getInstance()
192 ->removeNotifications($objectTypeObj->objectType . '.response.notification', $responseIDs);
193 }
194 }
195
196 // delete comments / responses
197 CommentEditor::deleteAll($commentIDs);
198 }
199
200 /**
201 * Enforces the flood control.
202 *
203 * @throws NamedUserException if flood control is exceeded
204 */
205 public static function enforceFloodControl()
206 {
207 $floodControlTime = WCF::getSession()->getPermission('user.comment.floodControlTime');
208 if (!$floodControlTime) {
209 return;
210 }
211
212 $lastTime = FloodControl::getInstance()->getLastTime('com.woltlab.wcf.comment');
213 if ($lastTime !== null && $lastTime > TIME_NOW - $floodControlTime) {
214 throw new NamedUserException(WCF::getLanguage()->getDynamicVariable(
215 'wcf.comment.error.floodControl',
216 ['lastCommentTime' => $lastTime]
217 ));
218 }
219 }
220
221 /**
222 * Marks all comment-related notifications for objects of the given object type and with
223 * the given ids as confirmed for the active user.
224 *
225 * @param string $objectType comment object type name
226 * @param int[] $objectIDs ids of the objects whose comment-related notifications will be marked as confirmed
227 * @param int $time only notifications older than the given timestamp will be marked as confirmed
228 * @throws \InvalidArgumentException if invalid comment object type name is given
229 * @since 5.2
230 */
231 public function markNotificationsAsConfirmed($objectType, array $objectIDs, $time = TIME_NOW)
232 {
233 // notifications are only relevant for logged-in users
234 if (!WCF::getUser()->userID) {
235 return;
236 }
237
238 if ($this->getObjectTypeID($objectType) === null) {
239 throw new \InvalidArgumentException("Unknown comment object type '{$objectType}'.");
240 }
241
242 if (empty($objectIDs)) {
243 return;
244 }
245
246 // 1. comments
247
248 // mark comment notifications as confirmed
249 $commentEvents = [];
250 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.notification')) {
251 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.notification') as $event) {
252 $commentEvents[$event->eventID] = [
253 'eventName' => $event->eventName,
254 'objectType' => $objectType . '.notification',
255 ];
256 }
257 }
258
259 if (!empty($commentEvents)) {
260 $notificationList = new UserNotificationList();
261 $notificationList->getConditionBuilder()->add(
262 'user_notification.eventID IN (?)',
263 [\array_keys($commentEvents)]
264 );
265 $notificationList->getConditionBuilder()->add('user_notification.userID = ?', [WCF::getUser()->userID]);
266 $notificationList->sqlJoins .= "
267 LEFT JOIN wcf" . WCF_N . "_comment comment
268 ON comment.commentID = user_notification.objectID
269 AND comment.objectTypeID = " . \intval($this->getObjectTypeID($objectType));
270 $notificationList->getConditionBuilder()->add('comment.objectID IN (?)', [$objectIDs]);
271 $notificationList->getConditionBuilder()->add('comment.time <= ?', [$time]);
272 $notificationList->readObjects();
273
274 $notificationObjectIDs = [];
275 foreach ($notificationList as $notification) {
276 if (!isset($notificationObjectIDs[$notification->eventID])) {
277 $notificationObjectIDs[$notification->eventID] = [];
278 }
279
280 $notificationObjectIDs[$notification->eventID][] = $notification->objectID;
281 }
282
283 if (!empty($notificationObjectIDs)) {
284 foreach ($notificationObjectIDs as $eventID => $commentIDs) {
285 UserNotificationHandler::getInstance()->markAsConfirmed(
286 $commentEvents[$eventID]['eventName'],
287 $commentEvents[$eventID]['objectType'],
288 [WCF::getUser()->userID],
289 $commentIDs
290 );
291 }
292 }
293 }
294
295 // mark comment reaction notifications as confirmed
296 $reactionCommentEvents = [];
297 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.like.notification') !== null) {
298 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.like.notification') as $event) {
299 $reactionCommentEvents[$event->eventID] = [
300 'eventName' => $event->eventName,
301 'objectType' => $objectType . '.like.notification',
302 ];
303 }
304 }
305
306 if (!empty($reactionCommentEvents)) {
307 // the value of the `objectID` property of the notifications is the like object
308 // id which is currently unknown, thus it needs to be read from database
309 $notificationList = new UserNotificationList();
310 $notificationList->getConditionBuilder()->add(
311 'user_notification.eventID IN (?)',
312 [\array_keys($reactionCommentEvents)]
313 );
314 $notificationList->getConditionBuilder()->add('user_notification.userID = ?', [WCF::getUser()->userID]);
315 $notificationList->sqlJoins .= "
316 LEFT JOIN wcf" . WCF_N . "_comment comment
317 ON comment.commentID = user_notification.baseObjectID
318 AND comment.objectTypeID = " . \intval($this->getObjectTypeID($objectType));
319 $notificationList->getConditionBuilder()->add('comment.objectID IN (?)', [$objectIDs]);
320 $notificationList->getConditionBuilder()->add('comment.time <= ?', [$time]);
321 $notificationList->readObjects();
322
323 $notificationObjectIDs = [];
324 foreach ($notificationList as $notification) {
325 if (!isset($notificationObjectIDs[$notification->eventID])) {
326 $notificationObjectIDs[$notification->eventID] = [];
327 }
328
329 $notificationObjectIDs[$notification->eventID][] = $notification->objectID;
330 }
331
332 if (!empty($notificationObjectIDs)) {
333 foreach ($notificationObjectIDs as $eventID => $reactionIDs) {
334 UserNotificationHandler::getInstance()->markAsConfirmed(
335 $reactionCommentEvents[$eventID]['eventName'],
336 $reactionCommentEvents[$eventID]['objectType'],
337 [WCF::getUser()->userID],
338 $reactionIDs
339 );
340 }
341 }
342 }
343
344 // 2. responses
345
346 // mark response notifications as confirmed
347 $responseEvents = [];
348 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.response.notification')) {
349 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.response.notification') as $event) {
350 $responseEvents[$event->eventID] = [
351 'eventName' => $event->eventName,
352 'objectType' => $objectType . '.response.notification',
353 ];
354 }
355 }
356
357 if (!empty($responseEvents)) {
358 $notificationList = new UserNotificationList();
359 $notificationList->getConditionBuilder()->add(
360 'user_notification.eventID IN (?)',
361 [\array_keys($responseEvents)]
362 );
363 $notificationList->getConditionBuilder()->add('user_notification.userID = ?', [WCF::getUser()->userID]);
364 $notificationList->sqlJoins .= "
365 LEFT JOIN wcf" . WCF_N . "_comment_response comment_response
366 ON comment_response.responseID = user_notification.objectID
367 LEFT JOIN wcf" . WCF_N . "_comment comment
368 ON comment.commentID = comment_response.commentID";
369 $notificationList->getConditionBuilder()->add(
370 'comment.objectTypeID IN (?)',
371 [$this->getObjectTypeID($objectType)]
372 );
373 $notificationList->getConditionBuilder()->add('comment.objectID IN (?)', [$objectIDs]);
374 $notificationList->getConditionBuilder()->add('comment_response.time <= ?', [$time]);
375 $notificationList->readObjects();
376
377 $notificationObjectIDs = [];
378 foreach ($notificationList as $notification) {
379 if (!isset($notificationObjectIDs[$notification->eventID])) {
380 $notificationObjectIDs[$notification->eventID] = [];
381 }
382
383 $notificationObjectIDs[$notification->eventID][] = $notification->objectID;
384 }
385
386 if (!empty($notificationObjectIDs)) {
387 foreach ($notificationObjectIDs as $eventID => $responseIDs) {
388 UserNotificationHandler::getInstance()->markAsConfirmed(
389 $responseEvents[$eventID]['eventName'],
390 $responseEvents[$eventID]['objectType'],
391 [WCF::getUser()->userID],
392 $responseIDs
393 );
394 }
395 }
396 }
397
398 // mark comment response reaction notifications as confirmed
399 $reactionResponseEvents = [];
400 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.response.like.notification') !== null) {
401 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.response.like.notification') as $event) {
402 $reactionResponseEvents[$event->eventID] = [
403 'eventName' => $event->eventName,
404 'objectType' => $objectType . '.response.like.notification',
405 ];
406 }
407 }
408
409 if (!empty($reactionResponseEvents)) {
410 // the value of the `objectID` property of the notifications is the like object
411 // id which is currently unknown, thus it needs to be read from database
412 $notificationList = new UserNotificationList();
413 $notificationList->getConditionBuilder()->add(
414 'user_notification.eventID IN (?)',
415 [\array_keys($reactionResponseEvents)]
416 );
417 $notificationList->getConditionBuilder()->add('user_notification.userID = ?', [WCF::getUser()->userID]);
418 $notificationList->sqlJoins .= "
419 LEFT JOIN wcf" . WCF_N . "_comment_response comment_response
420 ON comment_response.responseID = user_notification.baseObjectID
421 LEFT JOIN wcf" . WCF_N . "_comment comment
422 ON comment.commentID = comment_response.commentID";
423 $notificationList->getConditionBuilder()->add(
424 'comment.objectTypeID IN (?)',
425 [$this->getObjectTypeID($objectType)]
426 );
427 $notificationList->getConditionBuilder()->add('comment.objectID IN (?)', [$objectIDs]);
428 $notificationList->getConditionBuilder()->add('comment_response.time <= ?', [$time]);
429 $notificationList->readObjects();
430
431 $notificationObjectIDs = [];
432 foreach ($notificationList as $notification) {
433 if (!isset($notificationObjectIDs[$notification->eventID])) {
434 $notificationObjectIDs[$notification->eventID] = [];
435 }
436
437 $notificationObjectIDs[$notification->eventID][] = $notification->objectID;
438 }
439
440 if (!empty($notificationObjectIDs)) {
441 foreach ($notificationObjectIDs as $eventID => $reactionIDs) {
442 UserNotificationHandler::getInstance()->markAsConfirmed(
443 $reactionResponseEvents[$eventID]['eventName'],
444 $reactionResponseEvents[$eventID]['objectType'],
445 [WCF::getUser()->userID],
446 $reactionIDs
447 );
448 }
449 }
450 }
451 }
452
453 /**
454 * Marks all comment-related notifications for objects of the given object type in the
455 * given comment list as confirmed for the active user.
456 *
457 * @param string $objectType comment object type name
458 * @param StructuredComment[] $comments comments whose notifications will be marked as read
459 * @throws \InvalidArgumentException if invalid comment object type name is given
460 * @since 5.2
461 */
462 public function markNotificationsAsConfirmedForComments($objectType, array $comments)
463 {
464 // notifications are only relevant for logged-in users
465 if (!WCF::getUser()->userID) {
466 return;
467 }
468
469 if ($this->getObjectTypeID($objectType) === null) {
470 throw new \InvalidArgumentException("Unknown comment object type '{$objectType}'.");
471 }
472
473 if (\count($comments) === 0) {
474 return;
475 }
476
477 $commentIDs = [];
478 foreach ($comments as $comment) {
479 $commentIDs[] = $comment->commentID;
480 }
481
482 // 1. comments
483
484 // mark comment notifications as confirmed
485 $commentEvents = [];
486 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.notification')) {
487 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.notification') as $event) {
488 $commentEvents[$event->eventID] = [
489 'eventName' => $event->eventName,
490 'objectType' => $objectType . '.notification',
491 ];
492 }
493 }
494
495 if (!empty($commentEvents)) {
496 foreach ($commentEvents as $eventData) {
497 UserNotificationHandler::getInstance()->markAsConfirmed(
498 $eventData['eventName'],
499 $eventData['objectType'],
500 [WCF::getUser()->userID],
501 $commentIDs
502 );
503 }
504 }
505
506 // mark comment reaction notifications as confirmed
507 $reactionCommentEvents = [];
508 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.like.notification') !== null) {
509 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.like.notification') as $event) {
510 $reactionCommentEvents[$event->eventID] = [
511 'eventName' => $event->eventName,
512 'objectType' => $objectType . '.like.notification',
513 ];
514 }
515 }
516
517 if (!empty($reactionCommentEvents)) {
518 // the value of the `objectID` property of the notifications is the like object
519 // id which is currently unknown, thus it needs to be read from database
520 $notificationList = new UserNotificationList();
521 $notificationList->getConditionBuilder()->add(
522 'user_notification.eventID IN (?)',
523 [\array_keys($reactionCommentEvents)]
524 );
525 $notificationList->getConditionBuilder()->add('user_notification.userID = ?', [WCF::getUser()->userID]);
526 $notificationList->getConditionBuilder()->add('user_notification.baseObjectID IN (?)', [$commentIDs]);
527 $notificationList->readObjects();
528
529 $objectIDs = [];
530 foreach ($notificationList as $notification) {
531 if (!isset($objectIDs[$notification->eventID])) {
532 $objectIDs[$notification->eventID] = [];
533 }
534
535 $objectIDs[$notification->eventID][] = $notification->objectID;
536 }
537
538 if (!empty($objectIDs)) {
539 foreach ($objectIDs as $eventID => $reactionIDs) {
540 UserNotificationHandler::getInstance()->markAsConfirmed(
541 $reactionCommentEvents[$eventID]['eventName'],
542 $reactionCommentEvents[$eventID]['objectType'],
543 [WCF::getUser()->userID],
544 $reactionIDs
545 );
546 }
547 }
548 }
549
550 // 2. responses
551
552 $responseIDs = [];
553 foreach ($comments as $comment) {
554 // as we do not know whether `Comment::getUnfilteredResponseIDs()`
555 // or `Comment::getResponseIDs()` has been used, collect response
556 // ids manually
557 foreach ($comment as $response) {
558 $responseIDs[] = $response->responseID;
559 }
560 }
561
562 if (!empty($responseIDs)) {
563 // mark response notifications as confirmed
564 $responseEvents = [];
565 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.response.notification')) {
566 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.response.notification') as $event) {
567 $responseEvents[$event->eventID] = [
568 'eventName' => $event->eventName,
569 'objectType' => $objectType . '.response.notification',
570 ];
571 }
572 }
573
574 if (!empty($responseEvents)) {
575 foreach ($responseEvents as $eventData) {
576 UserNotificationHandler::getInstance()->markAsConfirmed(
577 $eventData['eventName'],
578 $eventData['objectType'],
579 [WCF::getUser()->userID],
580 $responseIDs
581 );
582 }
583 }
584
585 // mark comment response reaction notifications as confirmed
586 $reactionResponseEvents = [];
587 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.response.like.notification') !== null) {
588 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.response.like.notification') as $event) {
589 $reactionResponseEvents[$event->eventID] = [
590 'eventName' => $event->eventName,
591 'objectType' => $objectType . '.response.like.notification',
592 ];
593 }
594 }
595
596 if (!empty($reactionResponseEvents)) {
597 // the value of the `objectID` property of the notifications is the like object
598 // id which is currently unknown, thus it needs to be read from database
599 $notificationList = new UserNotificationList();
600 $notificationList->getConditionBuilder()->add(
601 'user_notification.eventID IN (?)',
602 [\array_keys($reactionResponseEvents)]
603 );
604 $notificationList->getConditionBuilder()->add(
605 'user_notification.userID = ?',
606 [WCF::getUser()->userID]
607 );
608 $notificationList->getConditionBuilder()->add('user_notification.baseObjectID IN (?)', [$responseIDs]);
609 $notificationList->readObjects();
610
611 $objectIDs = [];
612 foreach ($notificationList as $notification) {
613 if (!isset($objectIDs[$notification->eventID])) {
614 $objectIDs[$notification->eventID] = [];
615 }
616
617 $objectIDs[$notification->eventID][] = $notification->objectID;
618 }
619
620 if (!empty($objectIDs)) {
621 foreach ($objectIDs as $eventID => $reactionIDs) {
622 UserNotificationHandler::getInstance()->markAsConfirmed(
623 $reactionResponseEvents[$eventID]['eventName'],
624 $reactionResponseEvents[$eventID]['objectType'],
625 [WCF::getUser()->userID],
626 $reactionIDs
627 );
628 }
629 }
630 }
631 }
632 }
633
634 /**
635 * Marks all comment response-related notifications for objects of the given object type in
636 * the given comment response list as confirmed for the active user.
637 *
638 * @param string $objectType comment object type name
639 * @param CommentResponse[] $responses comment responses whose notifications will be marked as read
640 *
641 * @throws \InvalidArgumentException if invalid comment object type name is given
642 * @since 5.2
643 */
644 public function markNotificationsAsConfirmedForResponses($objectType, array $responses)
645 {
646 // notifications are only relevant for logged-in users
647 if (!WCF::getUser()->userID) {
648 return;
649 }
650
651 if ($this->getObjectTypeID($objectType) === null) {
652 throw new \InvalidArgumentException("Unknown comment object type '{$objectType}'.");
653 }
654
655 if (\count($responses) === 0) {
656 return;
657 }
658
659 $responseIDs = [];
660 foreach ($responses as $response) {
661 $responseIDs[] = $response->responseID;
662 }
663
664 $responseEvents = [];
665 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.response.notification')) {
666 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.response.notification') as $event) {
667 $responseEvents[$event->eventID] = [
668 'eventName' => $event->eventName,
669 'objectType' => $objectType . '.response.notification',
670 ];
671 }
672 }
673
674 if (!empty($responseEvents)) {
675 foreach ($responseEvents as $eventData) {
676 UserNotificationHandler::getInstance()->markAsConfirmed(
677 $eventData['eventName'],
678 $eventData['objectType'],
679 [WCF::getUser()->userID],
680 $responseIDs
681 );
682 }
683 }
684
685 // mark comment response reaction notifications as confirmed
686 $reactionResponseEvents = [];
687 if (UserNotificationHandler::getInstance()->getObjectTypeID($objectType . '.response.like.notification') !== null) {
688 foreach (UserNotificationHandler::getInstance()->getEvents($objectType . '.response.like.notification') as $event) {
689 $reactionResponseEvents[$event->eventID] = [
690 'eventName' => $event->eventName,
691 'objectType' => $objectType . '.response.like.notification',
692 ];
693 }
694 }
695
696 if (!empty($reactionResponseEvents)) {
697 // the value of the `objectID` property of the notifications is the like object
698 // id which is currently unknown, thus it needs to be read from database
699 $notificationList = new UserNotificationList();
700 $notificationList->getConditionBuilder()->add(
701 'user_notification.eventID IN (?)',
702 [\array_keys($reactionResponseEvents)]
703 );
704 $notificationList->getConditionBuilder()->add('user_notification.userID = ?', [WCF::getUser()->userID]);
705 $notificationList->getConditionBuilder()->add('user_notification.baseObjectID IN (?)', [$responseIDs]);
706 $notificationList->readObjects();
707
708 $objectIDs = [];
709 foreach ($notificationList as $notification) {
710 if (!isset($objectIDs[$notification->eventID])) {
711 $objectIDs[$notification->eventID] = [];
712 }
713
714 $objectIDs[$notification->eventID][] = $notification->objectID;
715 }
716
717 if (!empty($objectIDs)) {
718 foreach ($objectIDs as $eventID => $reactionIDs) {
719 UserNotificationHandler::getInstance()->markAsConfirmed(
720 $reactionResponseEvents[$eventID]['eventName'],
721 $reactionResponseEvents[$eventID]['objectType'],
722 [WCF::getUser()->userID],
723 $reactionIDs
724 );
725 }
726 }
727 }
728 }
729
730 /**
731 * Enforces the censorship.
732 *
733 * @param string $text
734 * @throws UserInputException
735 */
736 public static function enforceCensorship($text)
737 {
738 // search for censored words
739 if (ENABLE_CENSORSHIP) {
740 $result = Censorship::getInstance()->test($text);
741 if ($result) {
742 throw new UserInputException(
743 'text',
744 WCF::getLanguage()->getDynamicVariable(
745 'wcf.message.error.censoredWordsFound',
746 ['censoredWords' => $result]
747 )
748 );
749 }
750 }
751 }
752 }